Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Observability & Quality

🔧 HOW-TO | 📚 REFERENCE | Add observability and measure quality

Chicago TDD Tools provides comprehensive observability and quality measurement capabilities.

Quick Reference: Observability API

ComponentPurposeKey Methods/Fields
Span::new_active()Create an OTEL spanParameters: context, name, start_time, attributes, events, status
Span.attributesStore span metadata.insert(key, value)
Span.complete()Finish span timingParameter: end_time
Span.statusSet result statusVariants: Ok, Error, Unknown
Span.validate()Verify span correctnessReturns: Result<(), Error>
Metric structTrack measurementsFields: name, value, timestamp_ms, attributes
MetricValue enumMetric typesVariants: Counter, Gauge, Histogram
MetricValidator::new()Validate metrics.validate(&metric)
WeaverValidator::check_weaver_available()Check Weaver CLIReturns: Result<(), Error>
SpanValidator::new()Validate span format.validate(&span)

Overview

Observability helps you understand what your code is doing:

  • OTEL Instrumentation: Track operations with spans and metrics
  • Weaver Validation: Ensure telemetry matches semantic conventions
  • Coverage Measurement: Verify test coverage
  • Performance Tracking: Measure operation timing

OTEL Spans

OTEL (OpenTelemetry) spans track operations:

#![allow(unused)]
fn main() {
use chicago_tdd_tools::otel::*;

test!(test_with_span, {
    let start_time = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .ok()?
        .as_millis() as u64;

    // Create a span
    let mut span = Span::new_active(
        SpanContext::root(TraceId(123), SpanId(456), 1),
        "parse_operation",
        start_time,
        BTreeMap::new(),
        Vec::new(),
        SpanStatus::Unset,
    );

    // Add attributes
    span.attributes.insert("input".to_string(), "42".to_string());

    // Do work
    let result = "42".parse::<u32>()?;

    // Complete span
    let end_time = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .ok()?
        .as_millis() as u64;

    span.complete(end_time)?;
    span.status = SpanStatus::Ok;

    // Span is now complete with timing
    assert_ok!(&span.validate());
});
}

OTEL Metrics

Track measurements over time:

#![allow(unused)]
fn main() {
use chicago_tdd_tools::otel::*;

test!(test_with_metric, {
    let timestamp = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .ok()?
        .as_millis() as u64;

    let mut metric = Metric {
        name: "requests_total".to_string(),
        value: MetricValue::Counter(42),
        timestamp_ms: timestamp,
        attributes: BTreeMap::new(),
    };

    metric.attributes.insert("endpoint".to_string(), "/api/users".to_string());
    metric.attributes.insert("status".to_string(), "success".to_string());

    // Validate metric
    let validator = MetricValidator::new();
    assert_ok!(&validator.validate(&metric));
});
}

Weaver Live-Check

Validate telemetry against semantic conventions:

#![allow(unused)]
fn main() {
test!(test_weaver_validation, {
    // Check if Weaver is available
    match WeaverValidator::check_weaver_available() {
        Ok(()) => {
            // Weaver is available
            // Can validate OTEL spans against semantic conventions
            alert_success!("Weaver available");
        }
        Err(e) => {
            alert_info!("Weaver not available: {}", e);
            alert_info!("Install with: cargo make weaver-bootstrap");
        }
    }
});
}

Coverage Measurement

Measure test coverage:

# Run coverage
cargo make coverage

# Generate report
cargo make coverage-report

Coverage shows:

  • Code coverage percentage
  • Covered lines
  • Uncovered lines
  • Branch coverage

Target: 80%+ coverage for critical code

Best Practices

OTEL Spans

Do:

  • Add meaningful attributes
  • Track timing
  • Mark errors with SpanStatus
  • Propagate context between services

Don't:

  • Create spans for every operation (too noisy)
  • Include sensitive data in attributes
  • Forget to complete spans

Weaver Validation

Do:

  • Use semantic conventions
  • Validate telemetry early
  • Document telemetry schema
  • Keep conventions up-to-date

Don't:

  • Use custom attribute names
  • Skip validation
  • Ignore schema mismatches

Coverage

Do:

  • Aim for 80%+ coverage
  • Focus on critical paths
  • Test error paths (often uncovered)
  • Review coverage reports

Don't:

  • Obsess over 100% coverage
  • Ignore untested lines
  • Only focus on coverage number

Combining Observability with Testing

OTEL + Unit Tests

#![allow(unused)]
fn main() {
test!(test_with_otel, {
    let span = create_test_span("my_operation");

    // Do work
    let result = my_function()?;

    // Verify behavior AND telemetry
    assert_ok!(&result);
    span.validate()?;
    assert_eq!(span.status, SpanStatus::Ok);
});
}

Metrics + Property-Based Testing

#![allow(unused)]
fn main() {
test!(test_with_metrics, {
    let strategy = ProptestStrategy::new().with_cases(100);

    strategy.test(any::<u32>(), |num| {
        let timestamp = SystemTime::now()...;
        let mut metric = Metric {
            name: "parsing_attempts".to_string(),
            value: MetricValue::Counter(1),
            timestamp_ms: timestamp,
            attributes: BTreeMap::new(),
        };

        // Validate metric
        let validator = MetricValidator::new();
        validator.validate(&metric).is_ok()
    });
});
}

Real-World Example

#![allow(unused)]
fn main() {
test!(test_api_with_observability, {
    // Span for entire operation
    let mut operation_span = Span::new_active(
        SpanContext::root(TraceId(1), SpanId(1), 1),
        "api_request",
        start_time,
        BTreeMap::new(),
        Vec::new(),
        SpanStatus::Unset,
    );

    // Make API call
    let result = api_client.get_user(123)?;

    // Record metric
    let mut metric = Metric {
        name: "api_requests_total".to_string(),
        value: MetricValue::Counter(1),
        timestamp_ms: current_time,
        attributes: {
            let mut m = BTreeMap::new();
            m.insert("endpoint".to_string(), "/users".to_string());
            m.insert("status".to_string(), "success".to_string());
            m
        },
    };

    // Validate everything
    let span_validator = SpanValidator::new();
    assert_ok!(&span_validator.validate(&operation_span));

    let metric_validator = MetricValidator::new();
    assert_ok!(&metric_validator.validate(&metric));
});
}

Observability Checklist

For production code:

  • Operations tracked with OTEL spans
  • Meaningful attributes on spans
  • Metrics for important measurements
  • Error cases marked in telemetry
  • Telemetry validates against conventions
  • 80%+ test coverage
  • Error paths covered
  • Boundary conditions tested

Next Steps

See how to combine observability with real applications: Real-World Applications


Summary

Observability provides:

  • ✅ OTEL spans for operation tracking
  • ✅ Metrics for measurements
  • ✅ Weaver validation for compliance
  • ✅ Coverage for test quality

Combined with testing for complete confidence.