Module 9: Production Realities and Wrap-Up

Everything you built today ran on one laptop, with two services and a load generator. Here’s what changes when it doesn’t. πŸš€

Learning Objectives

By the end of this module, you will:

9.1 β€” Cost

Each signal has its own cost driver, and they fail differently.

Signal What costs money What blows up
Metrics Cardinality β€” active time series One unbounded attribute. You watched this happen in Module 6.2. Growth is permanent until retention expires
Logs Volume β€” bytes ingested and stored A debug log left on in a hot loop. Growth is proportional to traffic, so it’s at least predictable
Traces Sampling rate Γ— span count per trace An N+1 in a hot path. One request can produce a thousand spans

Useful intuitions:

9.2 β€” Sampling

In production you rarely keep every trace. There are two places to decide which ones to keep, and they make very different mistakes.

Head sampling decides when the trace starts, in the SDK. It’s two environment variables:

OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1

Cheap, simple, and it works at any scale: one process decides, and every downstream service respects the decision through traceparent. The catch is that the decision is made before anything has happened, so it drops 90% of your errors along with 90% of your successes. The traces you most want are exactly as likely to be discarded as the boring ones.

Tail sampling decides in the Collector, after the whole trace has arrived, so it can look at what happened:

processors:
  tail_sampling:
    decision_wait: 10s
    policies:
      - name: keep-errors
        type: status_code
        status_code: { status_codes: [ERROR] }
      - name: keep-slow
        type: latency
        latency: { threshold_ms: 500 }
      - name: sample-the-rest
        type: probabilistic
        probabilistic: { sampling_percentage: 10 }

Every error and every slow request survives; the successful ones are thinned out. The price is that the Collector has to hold every trace in memory until it’s complete, and all the spans of a trace have to reach the same Collector.

Either way, sampling changes your traces, not your metrics. Request rates and error rates still come from metrics that count every request β€” one of the good reasons to have both.

9.3 β€” PII and compliance

Telemetry leaks personal data in three places, and log bodies are only the most obvious one:

  1. Log bodies β€” someone logs the whole request object. Once.
  2. Span attributes β€” a full URL with an email address in the query string, db.query.text with literal values in it.
  3. Metric attributes β€” rarer, but a user_email label is both a privacy incident and a cardinality incident.

This is one of the strongest arguments for the Collector architecture. You can enforce it centrally, once, rather than reviewing it in every service:

processors:
  redaction:
    allow_all_keys: true
    blocked_values:
      - '[0-9]{16}'                                  # card numbers
      - '\b[\w.%+-]+@[\w.-]+\.[A-Za-z]{2,}\b'        # emails
    summary: debug

  transform:
    log_statements:
      - context: log
        statements:
          - delete_key(attributes, "authorization")

A service team that forgets is caught by the platform. That’s a genuinely different security posture from “we wrote it in the coding standards”.

Note the habit we started in Module 7.1: logging title_length rather than title. Redaction at the Collector is the safety net; not collecting it in the first place is the actual fix.

9.4 β€” Rollout strategy for a real team

The order matters more than people expect. This one is battle-tested:

  1. Auto-instrument everything. Every service, config only, no code changes. You’ll be astonished how far this gets you, and it costs almost nothing to try.
  2. Deploy a Collector and route everything through it. Do this early, before you have twenty services with hard-coded backend endpoints.
  3. Add domain spans to your two most painful endpoints. Not all of them. Two. The ones you already dread being paged about.
  4. Add business metrics for the three or four numbers your team actually discusses in standup.
  5. Wire up correlation β€” the jumps from a metric to its logs to its trace. This is where it starts feeling like a system rather than three tools.
  6. Then, and only then, think about taxonomy, naming standards and governance.

❌ Do not start by designing a metrics taxonomy. It’s the most common failure mode: six weeks of meetings, a beautiful document, zero telemetry in production, and the enthusiasm gone. Ship step 1 this week instead.

Two more pieces of advice that cost nothing:

9.5 β€” What to read next

Wrap-up

Look back at what you did today:

Please fill in the feedback form now, while you’re still in the room. πŸ“ Not later by email. Later never happens.

Thank you for spending the day on this. Go instrument something. πŸ‘‹