Table of Contents

    Model Observability and Logging

    MLOps Fundamentals

    Model Observability and Logging

    Learn how to make production Machine Learning systems understandable through structured logs, metrics, distributed traces, request correlation, model-version metadata, feature diagnostics, prediction monitoring, dashboards, alerts, privacy controls, incident response, and OpenTelemetry instrumentation.

    Introduction

    A deployed Machine Learning model is part of a larger production system. A prediction request may pass through an API gateway, authentication service, feature store, inference service, model runtime, database, message broker, and downstream business application.

    When a prediction is slow, incorrect, unavailable, or inconsistent, an operations team needs more than a generic error message. The team must be able to determine which model version ran, which application version handled the request, where time was spent, which dependency failed, whether feature values were missing or stale, and whether similar requests were affected.

    Model observability is the ability to understand the internal state and behavior of an ML system by examining the telemetry it produces. Logging is one important part of observability, but complete observability also includes metrics, traces, events, version metadata, model-quality signals, and business outcomes.

    Core principle: Monitoring tells operators that a problem may exist. Observability provides the evidence needed to understand where, why, and under which model, data, or application conditions it occurred.

    Learning Objectives

    By the End of This Lesson

    • Define model observability
    • Distinguish monitoring from observability
    • Explain the roles of logs, metrics, and traces
    • Understand structured logging
    • Create correlation and trace identifiers
    • Record model and application versions safely
    • Log inference lifecycle events
    • Avoid logging sensitive prediction payloads
    • Define operational ML metrics
    • Define data and feature-quality metrics
    • Track prediction distributions
    • Track delayed model-quality metrics
    • Create distributed traces for inference requests
    • Instrument a FastAPI service with OpenTelemetry
    • Correlate logs with traces
    • Understand telemetry collection and export
    • Design observability dashboards
    • Create actionable alerts
    • Use telemetry during incident investigation
    • Create an observability-readiness checklist

    Prerequisites

    Recommended Knowledge

    • Python programming
    • FastAPI or Flask fundamentals
    • REST APIs and HTTP status codes
    • Model deployment
    • Model monitoring
    • Feature stores
    • JSON fundamentals
    • Docker fundamentals
    • Distributed-system fundamentals
    • Basic incident-management concepts

    Example Packages

    • FastAPI
    • Uvicorn
    • OpenTelemetry API
    • OpenTelemetry SDK
    • OpenTelemetry OTLP exporter
    • OpenTelemetry FastAPI instrumentation
    • Prometheus client
    python -m pip install \
      fastapi \
      uvicorn \
      opentelemetry-api \
      opentelemetry-sdk \
      opentelemetry-exporter-otlp \
      opentelemetry-instrumentation-fastapi \
      prometheus-client
    Operational requirement: Use only approved telemetry backends, exporters, endpoints, authentication methods, retention policies, and network paths.

    What Is Observability?

    Observability is an engineering property that allows an operator to understand a system's internal behavior using the signals emitted by that system.

    Observability
    Logs + Metrics + Traces + Context → System Understanding
    Signal Main Question
    Logs What event occurred?
    Metrics How much, how often, or how long?
    Traces Where did this request travel and where was time spent?
    Profiles Which code paths consumed CPU or memory?
    Events What deployment, configuration, or infrastructure change occurred?
    ML Context Which model, feature contract, threshold, and data conditions were involved?

    Monitoring vs Observability

    Area Monitoring Observability
    Primary Purpose Tracks known indicators and conditions Supports investigation of known and unexpected behavior
    Typical Question Is the error rate above the defined threshold? Why did errors increase for this model version?
    Primary Outputs Dashboards, thresholds, and alerts Correlated logs, metrics, traces, events, and context
    Scope Predefined health and performance measures Deep investigation across system components
    ML Requirement Tracks data, prediction, quality, and business signals Explains how those signals relate to requests, models, features, and dependencies
    Relationship: Monitoring is implemented using observable signals. Observability makes those signals sufficiently rich and correlated for diagnosis.

    Layers of ML Observability

    Layer Examples
    Infrastructure CPU, memory, storage, accelerator, network, and restarts
    Application Availability, requests, HTTP errors, latency, and exceptions
    Data Schema failures, missing values, invalid ranges, and unexpected categories
    Features Freshness, retrieval latency, coverage, and offline-online consistency
    Predictions Scores, classes, uncertainty, abstention, and threshold rates
    Model Quality Precision, recall, calibration, residuals, and drift
    Responsible Use Relevant group behavior, overrides, complaints, and harmful outcomes
    Business Task completion, value, cost, fallback use, and operational impact
    Critical distinction: Healthy infrastructure and successful HTTP responses do not prove that predictions remain accurate, appropriate, or useful.

    Logs

    A log is a timestamped record describing an event that occurred within an application, service, pipeline, or infrastructure component.

    Log Category Example Event
    Lifecycle Model loaded successfully
    Request Prediction request accepted
    Validation Unsupported category detected
    Feature Required feature value unavailable
    Inference Prediction completed
    Dependency Feature-store request timed out
    Security Unauthorized request rejected
    Deployment Application version started
    Incident Fallback mode activated

    Structured Logging

    Structured logging records events as named fields rather than unstructured text. This makes logs easier to search, filter, aggregate, correlate, validate, and process automatically.

    Unstructured Log Prediction failed for customer 1001 because the feature service timed out.
    Structured Log Record the event name, severity, request identifier, model version, dependency, error type, duration, and outcome as separate fields without exposing the customer's identity unnecessarily.
    {
        "timestamp": "recorded-event-time",
        "level": "ERROR",
        "event_name": "feature_retrieval_failed",
        "service_name": "customer-churn-api",
        "application_version": "2.1.0",
        "model_name": "customer-churn-classifier",
        "model_version": "1.0.0",
        "request_id": "generated-request-id",
        "trace_id": "generated-trace-id",
        "dependency": "feature-store",
        "error_type": "timeout",
        "duration_ms": 1200,
        "fallback_applied": true
    }
    Synthetic example: The identifiers and values illustrate the structure only. Runtime telemetry must contain actual system-generated values.

    Log Levels

    Level General Purpose ML Example
    DEBUG Detailed development or diagnostic information Validated feature names and component transitions
    INFO Expected lifecycle and operational events Model version loaded successfully
    WARNING Unexpected condition that did not stop processing Optional feature missing and approved fallback applied
    ERROR Failed operation requiring investigation Prediction failed because a required dependency was unavailable
    CRITICAL Severe condition threatening safe service operation Model integrity verification failed during startup
    Level principle: Select levels according to operational impact. Do not use ERROR for expected invalid user input or INFO for a condition that compromises safe inference.

    Create a JSON Log Formatter

    import json
    import logging
    from datetime import datetime
    from datetime import timezone
    
    
    class JsonLogFormatter(
        logging.Formatter
    ):
    
        def format(
            self,
            record
        ):
            log_record = {
                "timestamp": (
                    datetime.now(
                        timezone.utc
                    ).isoformat()
                ),
                "level": record.levelname,
                "logger": record.name,
                "message": (
                    record.getMessage()
                )
            }
    
            approved_fields = [
                "event_name",
                "service_name",
                "application_version",
                "model_name",
                "model_version",
                "request_id",
                "trace_id",
                "span_id",
                "schema_version",
                "duration_ms",
                "status",
                "error_type"
            ]
    
            for field_name in approved_fields:
    
                field_value = getattr(
                    record,
                    field_name,
                    None
                )
    
                if field_value is not None:
    
                    log_record[
                        field_name
                    ] = field_value
    
            if record.exc_info:
    
                log_record[
                    "exception"
                ] = self.formatException(
                    record.exc_info
                )
    
            return json.dumps(
                log_record,
                ensure_ascii=False
            )

    Configure Structured Logging

    import logging
    import sys
    
    
    def configure_logging():
    
        log_handler = logging.StreamHandler(
            sys.stdout
        )
    
        log_handler.setFormatter(
            JsonLogFormatter()
        )
    
        root_logger = logging.getLogger()
    
        root_logger.handlers.clear()
    
        root_logger.addHandler(
            log_handler
        )
    
        root_logger.setLevel(
            logging.INFO
        )
    
    
    configure_logging()
    
    
    logger = logging.getLogger(
        "customer-churn-api"
    )
    Container practice: Writing application logs to standard output supports collection by container and orchestration platforms. The final destination, retention, redaction, and access rules belong to the approved logging architecture.

    Log Model Startup

    from pathlib import Path
    
    import joblib
    
    
    def load_model_artifact(
        model_path,
        model_name,
        model_version
    ):
        model_path = Path(
            model_path
        )
    
        try:
            model = joblib.load(
                model_path
            )
    
            logger.info(
                "Model loaded successfully.",
                extra={
                    "event_name": "model_loaded",
                    "service_name": (
                        "customer-churn-api"
                    ),
                    "model_name": model_name,
                    "model_version": model_version,
                    "status": "success"
                }
            )
    
            return model
    
        except Exception:
    
            logger.critical(
                "Model loading failed.",
                extra={
                    "event_name": (
                        "model_loading_failed"
                    ),
                    "service_name": (
                        "customer-churn-api"
                    ),
                    "model_name": model_name,
                    "model_version": model_version,
                    "status": "failed"
                },
                exc_info=True
            )
    
            raise
    Security warning: Load serialized models only from trusted and integrity-verified sources. A successful log entry does not establish that an artifact was originally safe or approved.

    Correlation Identifiers

    Correlation identifiers connect telemetry produced by different components while processing one logical request.

    Identifier Purpose
    Request ID Identifies one API or application request
    Trace ID Identifies an end-to-end distributed transaction
    Span ID Identifies one operation within a trace
    Prediction ID Identifies one model prediction for later outcome joining
    Pipeline Run ID Identifies one training or monitoring-pipeline execution
    Experiment Run ID Links production lineage to the tracked training run
    Request Correlation
    API Gateway → Feature Store → Model Service → Business Workflow = One Trace ID

    Create Request Middleware

    import time
    import uuid
    
    from fastapi import FastAPI
    from fastapi import Request
    
    
    app = FastAPI(
        title="Customer Churn API",
        version="2.1.0"
    )
    
    
    @app.middleware(
        "http"
    )
    async def request_observability(
        request: Request,
        call_next
    ):
        request_id = (
            request.headers.get(
                "X-Request-ID"
            )
            or str(
                uuid.uuid4()
            )
        )
    
        request.state.request_id = (
            request_id
        )
    
        started_at = (
            time.perf_counter()
        )
    
        try:
            response = await call_next(
                request
            )
    
            duration_ms = (
                time.perf_counter()
                -
                started_at
            ) * 1000
    
            logger.info(
                "Request completed.",
                extra={
                    "event_name": (
                        "request_completed"
                    ),
                    "service_name": (
                        "customer-churn-api"
                    ),
                    "application_version": (
                        "2.1.0"
                    ),
                    "request_id": request_id,
                    "duration_ms": round(
                        duration_ms,
                        3
                    ),
                    "status": str(
                        response.status_code
                    )
                }
            )
    
            response.headers[
                "X-Request-ID"
            ] = request_id
    
            return response
    
        except Exception:
    
            duration_ms = (
                time.perf_counter()
                -
                started_at
            ) * 1000
    
            logger.error(
                "Request failed.",
                extra={
                    "event_name": (
                        "request_failed"
                    ),
                    "service_name": (
                        "customer-churn-api"
                    ),
                    "application_version": (
                        "2.1.0"
                    ),
                    "request_id": request_id,
                    "duration_ms": round(
                        duration_ms,
                        3
                    ),
                    "status": "failed"
                },
                exc_info=True
            )
    
            raise
    Identifier safety: Generate an internal identifier when the supplied request ID is absent, invalid, excessively long, or untrusted.

    What Must Not Be Logged?

    Prohibited or High-Risk Content

    • Passwords
    • Access tokens
    • API keys
    • Private cryptographic keys
    • Session cookies
    • Complete authorization headers
    • Unnecessary personal information
    • Complete confidential prediction payloads
    • Raw documents submitted for inference
    • Sensitive feature values without approved need
    • Database connection strings
    • Internal stack details exposed to end users
    Unsafe Logging Log the complete request body, authentication token, customer identity, every feature value, and complete model response.
    Minimized Logging Record a controlled request identifier, schema-validation status, model version, aggregated diagnostics, duration, outcome, and approved error metadata.

    Redact Sensitive Fields

    SENSITIVE_KEYS = {
        "password",
        "access_token",
        "api_key",
        "authorization",
        "cookie",
        "secret",
        "private_key"
    }
    
    
    def redact_value(
        value
    ):
        if isinstance(
            value,
            dict
        ):
            return {
                key: (
                    "[REDACTED]"
                    if key.lower()
                    in SENSITIVE_KEYS
                    else redact_value(
                        nested_value
                    )
                )
                for key, nested_value
                in value.items()
            }
    
        if isinstance(
            value,
            list
        ):
            return [
                redact_value(
                    item
                )
                for item in value
            ]
    
        return value
    Redaction limitation: Key-based redaction is one control. Sensitive data can also appear under unexpected field names or inside free text. Prefer not collecting such content whenever possible.

    Metrics

    Metrics are numerical measurements aggregated over time. They are efficient for dashboards, thresholds, trend analysis, service-level objectives, and alerts.

    Metric Type Purpose Example
    Counter Tracks an accumulated total Total prediction requests
    Gauge Tracks a value that can increase or decrease Current queue depth
    Histogram Tracks the distribution of observations Inference latency
    Summary Summarizes observations according to implementation behavior Request duration

    Operational Metrics for ML APIs

    Metric Purpose
    Request Count Tracks inference traffic
    Success Rate Tracks completed requests
    Error Rate Tracks failed requests
    Validation-Failure Rate Tracks rejected input contracts
    Latency Distribution Tracks service and inference duration
    Throughput Tracks completed predictions per interval
    Queue Depth Tracks waiting asynchronous work
    Fallback Rate Tracks use of alternate behavior
    Dependency-Failure Rate Tracks feature, database, or external-service failures
    Error Rate
    \[ \text{Error Rate} = \frac{ \text{Failed Requests} }{ \text{Total Requests} } \]

    ML-Specific Metrics

    Metric Area Examples
    Input Quality Missing values, invalid ranges, and unsupported categories
    Feature Store Coverage, freshness, retrieval latency, and stale-value rate
    Prediction Mean score, class distribution, selection rate, and uncertainty
    Drift Feature, prediction, label, and attribution drift
    Delayed Quality Precision, recall, F1, calibration, and regression error
    Group Behavior Quality and selection measures across relevant groups
    Business Outcome Task completion, intervention success, overrides, and complaints
    Cost Compute, storage, request, feature retrieval, and downstream use

    Instrument Metrics with Prometheus

    from prometheus_client import Counter
    from prometheus_client import Histogram
    
    
    prediction_requests = Counter(
        "ml_prediction_requests_total",
        "Total prediction requests",
        [
            "model_name",
            "model_version",
            "status"
        ]
    )
    
    
    prediction_latency = Histogram(
        "ml_prediction_duration_seconds",
        "Prediction request duration",
        [
            "model_name",
            "model_version"
        ]
    )
    
    
    validation_failures = Counter(
        "ml_validation_failures_total",
        "Rejected prediction inputs",
        [
            "schema_version",
            "failure_type"
        ]
    )
    Metric-label rule: Use bounded, low-cardinality labels such as model version and status. Do not use request IDs, customer IDs, or raw feature values as metric labels.

    Record Prediction Metrics

    import time
    
    
    def run_observed_prediction(
        model,
        feature_frame,
        model_name,
        model_version
    ):
        started_at = (
            time.perf_counter()
        )
    
        try:
            probabilities = model.predict_proba(
                feature_frame
            )[:, 1]
    
            prediction_requests.labels(
                model_name=model_name,
                model_version=model_version,
                status="success"
            ).inc()
    
            return probabilities
    
        except Exception:
    
            prediction_requests.labels(
                model_name=model_name,
                model_version=model_version,
                status="failed"
            ).inc()
    
            raise
    
        finally:
            duration_seconds = (
                time.perf_counter()
                -
                started_at
            )
    
            prediction_latency.labels(
                model_name=model_name,
                model_version=model_version
            ).observe(
                duration_seconds
            )

    Traces

    A distributed trace represents the path of one request across services and operations. A trace consists of spans. Each span represents one timed operation such as authentication, feature retrieval, preprocessing, model inference, or persistence.

    Inference Trace
    HTTP Request → Validation → Feature Retrieval → Preprocessing → Inference → Response
    Trace Concept Meaning
    Trace The complete end-to-end request path
    Span One operation inside the trace
    Parent Span The operation that initiated another operation
    Span Attribute Searchable metadata describing an operation
    Span Event A timestamped event occurring within a span
    Span Status The completion state of an operation

    Configure OpenTelemetry Tracing

    from opentelemetry import trace
    from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
    from opentelemetry.sdk.resources import Resource
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    
    
    resource = Resource.create(
        {
            "service.name": (
                "customer-churn-api"
            ),
            "service.version": "2.1.0",
            "deployment.environment.name": (
                "development"
            )
        }
    )
    
    
    trace_provider = TracerProvider(
        resource=resource
    )
    
    
    trace_exporter = OTLPSpanExporter(
        endpoint=(
            "replace-with-approved-otlp-endpoint"
        ),
        insecure=False
    )
    
    
    trace_provider.add_span_processor(
        BatchSpanProcessor(
            trace_exporter
        )
    )
    
    
    trace.set_tracer_provider(
        trace_provider
    )
    
    
    tracer = trace.get_tracer(
        "customer-churn-api"
    )
    Endpoint requirement: Configure the OTLP endpoint, transport security, certificates, authentication, and headers according to the approved observability platform.

    Instrument FastAPI

    from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
    
    
    FastAPIInstrumentor.instrument_app(
        app
    )
    Instrumentation review: Automatic instrumentation can create HTTP spans, but custom ML operations such as feature retrieval and model inference may require explicit spans and approved attributes.

    Create Custom ML Spans

    from opentelemetry.trace import Status
    from opentelemetry.trace import StatusCode
    
    
    def traced_prediction(
        model,
        feature_frame,
        model_name,
        model_version,
        feature_service_version
    ):
        with tracer.start_as_current_span(
            "ml.predict"
        ) as prediction_span:
    
            prediction_span.set_attribute(
                "ml.model.name",
                model_name
            )
    
            prediction_span.set_attribute(
                "ml.model.version",
                model_version
            )
    
            prediction_span.set_attribute(
                "ml.feature_service.version",
                feature_service_version
            )
    
            prediction_span.set_attribute(
                "ml.batch_size",
                len(
                    feature_frame
                )
            )
    
            try:
                probabilities = model.predict_proba(
                    feature_frame
                )[:, 1]
    
                prediction_span.set_status(
                    Status(
                        StatusCode.OK
                    )
                )
    
                return probabilities
    
            except Exception as error:
    
                prediction_span.record_exception(
                    error
                )
    
                prediction_span.set_status(
                    Status(
                        StatusCode.ERROR,
                        str(
                            error
                        )
                    )
                )
    
                raise
    Span-data caution: Add model metadata, controlled dimensions, durations, and status. Do not add complete feature vectors, credentials, or personal data as span attributes.

    Trace Feature Retrieval

    def retrieve_features_with_trace(
        feature_store,
        feature_service,
        entity_rows
    ):
        with tracer.start_as_current_span(
            "feature_store.get_online_features"
        ) as feature_span:
    
            feature_span.set_attribute(
                "feature_store.service",
                feature_service
            )
    
            feature_span.set_attribute(
                "feature_store.entity_count",
                len(
                    entity_rows
                )
            )
    
            try:
                result = (
                    feature_store.get_online_features(
                        features=feature_service,
                        entity_rows=entity_rows
                    )
                )
    
                response = result.to_dict()
    
                feature_span.set_attribute(
                    "feature_store.status",
                    "success"
                )
    
                return response
    
            except Exception as error:
    
                feature_span.set_attribute(
                    "feature_store.status",
                    "failed"
                )
    
                feature_span.record_exception(
                    error
                )
    
                raise

    Correlate Logs with Traces

    from opentelemetry import trace
    
    
    def get_trace_context():
    
        current_span = (
            trace.get_current_span()
        )
    
        span_context = (
            current_span.get_span_context()
        )
    
        if not span_context.is_valid:
    
            return {
                "trace_id": None,
                "span_id": None
            }
    
        return {
            "trace_id": format(
                span_context.trace_id,
                "032x"
            ),
            "span_id": format(
                span_context.span_id,
                "016x"
            )
        }
    trace_context = (
        get_trace_context()
    )
    
    
    logger.info(
        "Prediction completed.",
        extra={
            "event_name": (
                "prediction_completed"
            ),
            "service_name": (
                "customer-churn-api"
            ),
            "model_name": (
                "customer-churn-classifier"
            ),
            "model_version": "1.0.0",
            "trace_id": (
                trace_context[
                    "trace_id"
                ]
            ),
            "span_id": (
                trace_context[
                    "span_id"
                ]
            ),
            "status": "success"
        }
    )
    Correlation benefit: A trace identifier in a structured log allows an investigator to move from a high-level failure event to the detailed distributed request path.

    OpenTelemetry Collector

    An OpenTelemetry Collector can receive telemetry, process it, and export it to one or more approved observability destinations.

    Telemetry Pipeline
    Applications → OTLP → Collector → Logs, Metrics, and Trace Backends
    receivers:
      otlp:
        protocols:
          grpc:
          http:
    
    processors:
      batch:
    
    exporters:
      otlp:
        endpoint: replace-with-approved-backend
        tls:
          insecure: false
    
    service:
      pipelines:
        traces:
          receivers:
            - otlp
          processors:
            - batch
          exporters:
            - otlp
    Illustrative configuration: Authentication, certificates, queueing, retries, redaction, sampling, memory controls, and backend-specific settings must follow the approved platform design.

    Telemetry Sampling

    Sampling controls which trace or event records are retained. It can reduce telemetry volume and cost, but insufficient sampling may remove rare failures or important operational evidence.

    Approach General Purpose
    Head Sampling Decides near the beginning of the request
    Tail Sampling Decides after more of the trace is available
    Probability Sampling Retains a configured proportion of traces
    Error-Focused Sampling Prioritizes failed operations
    Latency-Focused Sampling Prioritizes unusually slow traces
    Version-Aware Sampling Increases evidence for a newly released candidate
    Sampling principle: Preserve sufficient evidence for security, incident response, canary validation, rare failures, and responsible-use review.

    Metric Cardinality

    Metric cardinality is the number of distinct label combinations associated with a metric. Unbounded labels can make monitoring expensive and difficult to operate.

    Suitable Bounded Label High-Cardinality Label to Avoid
    Model version Request ID
    Environment Customer ID
    Response status Raw error message
    Error category Feature vector
    Endpoint name Complete URL with unique query values
    Deployment region Prediction ID
    Signal selection: Store unique request-level context in logs and traces. Use bounded dimensions for metrics.

    Observability Dashboard

    Dashboard Section Suggested Content
    Release Context Model, application, schema, feature-service, and threshold versions
    Traffic Requests, throughput, batch size, and endpoint usage
    Reliability Availability, errors, retries, fallbacks, and dependency health
    Latency P50, P90, P95, and P99 request and inference duration
    Infrastructure CPU, memory, accelerators, replicas, and restarts
    Input Quality Schema failures, missing values, invalid ranges, and categories
    Features Retrieval latency, coverage, freshness, and stale values
    Predictions Score distribution, positive rate, uncertainty, and abstention
    Model Quality Delayed quality, calibration, drift, and relevant group metrics
    Business Task success, override rate, complaints, cost, and fallback use
    Incidents Active alerts, owners, severity, response, and recovery status
    Dashboard requirement: Every view should make its model version, population, time window, metric definition, update time, and responsible owner clear.

    Actionable Alerts

    Every Important Alert Should Define

    • Metric or log condition
    • Affected service and model version
    • Evaluation window
    • Threshold
    • Minimum sample size
    • Persistence requirement
    • Severity
    • Responsible owner
    • Notification channel
    • Dashboard or query link
    • Investigation runbook
    • Fallback and rollback criteria
    Weak Alert Model error detected.
    Actionable Alert Identify the model version, endpoint, error category, observed rate, threshold, window, trace examples, affected population, owner, and required response.

    Reduce Alert Fatigue

    Alert-Quality Controls

    • Use appropriate warning and critical severities
    • Require sufficient sample size
    • Require persistence where appropriate
    • Group correlated failures into one incident
    • Suppress duplicate notifications
    • Account for maintenance and controlled deployments
    • Route alerts to responsible owners
    • Review false positives and missed incidents
    • Retire alerts that do not lead to action
    • Increase evidence temporarily during canary releases

    Incident Investigation

    1

    Validate the Alert

    Confirm the signal, calculation, time window, sample size, deployment state, and alert configuration.

    2

    Identify the Scope

    Determine affected endpoints, model versions, application versions, regions, users, entities, and time periods.

    3

    Inspect Representative Traces

    Locate slow, failed, or unusual requests and identify the affected span or dependency.

    4

    Query Correlated Logs

    Use trace, request, prediction, and deployment identifiers to retrieve related events.

    5

    Review Metrics

    Compare errors, latency, resources, input quality, feature freshness, predictions, and dependencies.

    6

    Assess ML Impact

    Review prediction distributions, drift, calibration, delayed outcomes, relevant groups, and business effects.

    7

    Mitigate and Recover

    Correct data, scale resources, disable a dependency, use fallback, restrict traffic, or roll back as required.

    8

    Document and Improve

    Record root cause, impact, response, recovery evidence, and observability improvements.

    Fallback and Rollback Observability

    Signal Purpose
    Fallback Activation Count Shows how often alternate behavior is used
    Fallback Reason Separates feature, model, dependency, and policy causes
    Rollback Initiated Records the start of restoration
    Previous Version Identifies the release being replaced
    Restored Version Identifies the approved release restored
    Recovery Validation Confirms health, latency, errors, and prediction consistency
    Post-Rollback Monitoring Verifies stability after restoration

    Test Logging Behavior

    import json
    import logging
    
    
    def test_json_log_formatter():
    
        formatter = JsonLogFormatter()
    
        record = logging.LogRecord(
            name="test-logger",
            level=logging.INFO,
            pathname=__file__,
            lineno=1,
            msg="Prediction completed.",
            args=(),
            exc_info=None
        )
    
        record.event_name = (
            "prediction_completed"
        )
    
        record.model_version = "1.0.0"
    
        record.request_id = (
            "test-request-id"
        )
    
        serialized_log = formatter.format(
            record
        )
    
        parsed_log = json.loads(
            serialized_log
        )
    
        assert parsed_log[
            "level"
        ] == "INFO"
    
        assert parsed_log[
            "event_name"
        ] == "prediction_completed"
    
        assert parsed_log[
            "model_version"
        ] == "1.0.0"
    
        assert parsed_log[
            "request_id"
        ] == "test-request-id"

    Test Redaction

    def test_sensitive_values_are_redacted():
    
        payload = {
            "username": "approved-test-user",
            "password": "example-password",
            "nested": {
                "api_key": "example-key",
                "status": "active"
            }
        }
    
        redacted = redact_value(
            payload
        )
    
        assert redacted[
            "password"
        ] == "[REDACTED]"
    
        assert redacted[
            "nested"
        ][
            "api_key"
        ] == "[REDACTED]"
    
        assert redacted[
            "nested"
        ][
            "status"
        ] == "active"
    python -m pytest -v

    Telemetry Retention

    Telemetry Retention Consideration
    Application Logs Operational diagnosis, security, privacy, volume, and incident needs
    Audit Logs Governance, privileged access, and required audit history
    Metrics Trend, capacity, drift, performance, and cost analysis
    Traces Sampling strategy, incident analysis, and storage cost
    Prediction Metadata Delayed-label joining, model quality, privacy, and investigation
    Raw Payload Samples Require explicit authorization, minimization, and restricted retention
    Incident Evidence Preserve according to incident and governance requirements
    Retention principle: Retain enough telemetry to operate, investigate, audit, and improve the system without storing unnecessary sensitive information indefinitely.

    Observability Cost Management

    Cost Driver Possible Control
    Verbose Logs Use environment-appropriate levels and structured events
    High-Cardinality Metrics Use bounded labels and move unique context to traces or logs
    Full Trace Retention Apply approved sampling while preserving important failures
    Long Retention Apply tiered lifecycle and deletion policies
    Duplicate Telemetry Standardize collectors and avoid unnecessary repeated exports
    Raw Payload Logging Use safe aggregates and approved diagnostic samples
    Unused Dashboards Retire views without owners or operational value

    Responsible Model Observability

    Responsible-Use Requirements

    • Collect only telemetry required for an approved purpose
    • Protect personal and confidential information
    • Track model, schema, threshold, and feature versions
    • Monitor relevant operating groups appropriately
    • Use minimum sample sizes for group-level reporting
    • Track complaints, corrections, and overrides
    • Preserve human review for consequential actions
    • Communicate uncertainty in diagnostic conclusions
    • Audit access to sensitive telemetry
    • Maintain tested fallback and rollback
    • Retire telemetry fields without a valid operational purpose
    • Retire models that are no longer appropriate

    Common Observability Mistakes

    Mistake Treat logging and observability as identical.
    Correction Combine structured logs with metrics, traces, context, events, and ML-quality signals.
    Mistake Log complete prediction payloads by default.
    Correction Record minimized metadata, aggregates, validation outcomes, and approved diagnostic samples.
    Mistake Use request IDs as metric labels.
    Correction Keep unique identifiers in logs and traces and use bounded metric dimensions.
    Mistake Record the model name but not its version.
    Correction Record the immutable model version, application version, schema, threshold, and feature-service version.
    Mistake Create traces containing raw feature vectors.
    Correction Use controlled metadata such as feature count, retrieval status, service version, and duration.
    Mistake Create dashboards without metric definitions or owners.
    Correction Document the population, window, model version, calculation, threshold, update time, and owner.
    Mistake Alert on every individual error.
    Correction Separate expected validation failures from service incidents and apply windows, severity, persistence, and ownership.
    Mistake Monitor the API but ignore model quality.
    Correction Combine operational telemetry with data, prediction, delayed quality, group, and business monitoring.

    Recommended Observability Workflow

    1

    Define Observability Objectives

    Identify system risks, operational questions, service objectives, model risks, owners, and incident needs.

    2

    Design the Telemetry Schema

    Standardize events, fields, model context, identifiers, severity, and redaction requirements.

    3

    Instrument Application Boundaries

    Instrument HTTP requests, validation, features, inference, dependencies, persistence, and fallback paths.

    4

    Generate Structured Logs

    Emit machine-readable events containing approved diagnostic context.

    5

    Record Metrics

    Track traffic, errors, latency, resources, data quality, predictions, delayed quality, and business outcomes.

    6

    Create Distributed Traces

    Connect service, feature, inference, and dependency spans under one trace context.

    7

    Collect and Export Safely

    Use approved collectors, exporters, identities, encryption, redaction, sampling, and destinations.

    8

    Create Dashboards and Alerts

    Present system and ML behavior with defined thresholds, ownership, and investigation links.

    9

    Test Incident Response

    Verify telemetry discovery, trace correlation, fallback, rollback, escalation, and recovery validation.

    10

    Continuously Improve

    Review missing evidence, noisy alerts, privacy exposure, cost, retention, and incident learnings.

    Hands-On Practice

    1

    Create a Telemetry Inventory

    List the logs, metrics, traces, events, versions, and business signals required for one deployed model.

    2

    Implement Structured Logging

    Create a JSON formatter and record model startup, request completion, validation failure, and dependency failure events.

    3

    Add Request Correlation

    Generate or validate a request ID and return it to the API caller.

    4

    Create Metrics

    Track prediction requests, errors, validation failures, and inference duration using bounded labels.

    5

    Instrument FastAPI

    Add OpenTelemetry HTTP instrumentation and confirm that request traces are generated.

    6

    Add Custom ML Spans

    Trace feature retrieval, preprocessing, inference, and response construction.

    7

    Correlate Logs and Traces

    Include trace and span identifiers in structured log events.

    8

    Run an Incident Exercise

    Introduce a safe development-only feature timeout and use metrics, logs, and traces to identify the failing operation.

    Knowledge Check

    1

    What is model observability?

    Explain how telemetry helps operators understand the internal behavior of a production ML system.

    2

    How does observability differ from monitoring?

    Explain predefined condition tracking compared with deeper investigation using correlated signals.

    3

    What is structured logging?

    Explain how named fields make events searchable, filterable, aggregatable, and machine-readable.

    4

    What is a metric?

    Explain a numerical measurement aggregated or observed over time.

    5

    What is a distributed trace?

    Explain the end-to-end path of one request across multiple operations and services.

    6

    What is a span?

    Explain one timed operation within a distributed trace.

    7

    Why correlate logs and traces?

    Explain how trace identifiers connect event details with the complete request path.

    8

    Why avoid high-cardinality metric labels?

    Explain how unique identifiers create excessive time-series combinations and operational cost.

    9

    Why should raw feature vectors not be added to traces?

    Explain privacy, security, telemetry volume, and unnecessary exposure.

    10

    Why is application observability insufficient for ML quality?

    Explain how a reliable API can still serve a degraded, inaccurate, unfair, or inappropriate model.

    Observability Readiness Checklist

    Confirm Before Production Use

    • Observability objectives are documented
    • Telemetry owners are identified
    • Application logs use a structured format
    • Log event names are standardized
    • Log levels are used consistently
    • Request identifiers are generated or validated
    • Distributed trace propagation is configured
    • Logs contain trace and span identifiers
    • Every prediction identifies its model version
    • Application and schema versions are recorded
    • Feature-service and threshold versions are recorded
    • Sensitive values are not logged unnecessarily
    • Credential and token redaction is tested
    • Raw payload logging is disabled by default
    • Operational metrics are available
    • ML-specific metrics are available
    • Metric labels have bounded cardinality
    • Latency percentiles are monitored
    • Feature retrieval is traced and monitored
    • Model inference has a dedicated trace span
    • Dependency failures are identifiable
    • An approved telemetry collector is configured
    • Telemetry export uses secure transport
    • Sampling preserves important failures
    • Dashboards identify their population and owners
    • Alerts include actionable context
    • Critical alerts have runbooks
    • Fallback and rollback events are observable
    • Telemetry retention policies are documented
    • Access to telemetry is auditable
    • Logging and redaction logic is tested
    • Incident-response exercises have been completed
    • Responsible-use monitoring is included

    Lesson Summary

    Observability Area Main Outcome
    Structured Logs Provide searchable event-level diagnostic details
    Metrics Provide numerical trends, dashboards, and alert signals
    Traces Show the end-to-end path and timing of a request
    Correlation IDs Connect telemetry across components
    Model Context Identifies the model and serving configuration involved
    Input Observability Tracks schema, quality, and validation behavior
    Feature Observability Tracks retrieval, coverage, freshness, and consistency
    Prediction Observability Tracks score, class, uncertainty, and decision distributions
    Delayed Quality Tracks model performance after verified outcomes arrive
    OpenTelemetry Provides vendor-neutral telemetry instrumentation and export
    Collector Receives, processes, and exports telemetry
    Dashboards Present operational and ML behavior clearly
    Alerts Direct responsible owners toward defined action
    Incident Response Uses correlated evidence for diagnosis and recovery
    Privacy and Governance Control telemetry content, access, retention, and use

    Key Takeaway

    Model observability and logging make production Machine Learning systems understandable and supportable. Structured logs explain individual events, metrics reveal trends and threshold conditions, and distributed traces show how requests move through validation, feature retrieval, preprocessing, inference, and downstream services. Complete ML observability also records the model, application, schema, feature-service, threshold, and deployment versions associated with each request. OpenTelemetry can provide vendor-neutral instrumentation and telemetry export, but instrumentation must be combined with privacy-safe schemas, bounded metric labels, secure collection, appropriate sampling, actionable alerts, responsible ownership, and tested incident procedures. Observability does not replace model monitoring. It connects operational evidence with data, prediction, delayed-quality, responsible-use, and business signals so teams can understand and correct production behavior safely.

    Get Machine Learning updates by email

    Short, practical lessons and course updates from Rumman Ansari. No spam.