By Chason ArthurRevision 151.032Published Updated

OpenTelemetry / Observability / SLOs

The server is healthy. Customers are waiting.

Every request returns successfully. One takes much longer than the others. Follow its spans, find the missing context and choose a signal that reflects the customer’s wait.

The idea in plain language

A successful response can still be a poor experience. Metrics tell you how often that happens; a trace helps explain where a particular request spent its time.

The worker creates real OpenTelemetry spans around actual timer waits. The database is a timed fixture. Eight requests teach latency arithmetic, not a production SLO window. A local HTTP service and optional Prometheus/Grafana recipe accompany the download.

Your independent testing environment

Make the failure visible.

Run the slow-query example. Inspect the mean, p95 and under-100-ms fraction. In the safeguarded trace, the database span shares the customer request’s trace ID instead of starting an unrelated root.

Compare a green availability signal with the slow request’s trace and latency.

Ready. Choose an example and run both implementations.

Explain the result

Both versions return eight successful responses. The safeguarded trace contains the request, service and database spans under one trace ID. A long tail remains visible even though availability is 100%.

Open the exact source behind this edition. The viewer checks each file against its SHA-256 manifest and explains the decision it implements.

Download this lab

Choose your next step

Build the safeguards

Eight explained steps, a source example and a checkpoint at each decision.

Read the tutorial

Compare the alternatives

Understand where each pattern helps and which tradeoffs remain.

Compare approaches

Run and extend it locally

Download the independent environment, run the native checks and try a specific extension.

Open the how-to guide

Before you try it

Do I need to know how to code?

Start with Run and read the comparison. The tutorial introduces the code after you have seen the behavior. The how-to guide separates a no-install route from the native developer exercise.

What happens to the experiment when I reset?

Reset discards this lab’s temporary state and cancels or terminates its pending work. These examples use invented records. No account, production data or cloud deployment is needed.

What does the browser experiment establish?

The worker creates real OpenTelemetry spans around actual timer waits. The database is a timed fixture. Eight requests teach latency arithmetic, not a production SLO window. A local HTTP service and optional Prometheus/Grafana recipe accompany the download.

Lab discussion / Trace the Wait Lab

What would you try next?

Ask about the code, compare an approach, or describe an edge case. Reader comments are reviewed before publication.

All lab discussions

Reader comments

Open the discussion to read and add reader comments.

Read or write a comment →

Code walkthrough

Follow the implementation in code.

These short excerpts connect the lab’s behavior to its implementation. Each example links to the full tutorial step for its context, tradeoffs and checkpoint. Names and dependencies belong to that source; the excerpts are not standalone programs.

Example 01 · Tutorial excerpt

Start with the customer’s operation

The root span describes GET /report, not an internal implementation detail. Its duration represents the operation the visitor experiences in this fixture. A health endpoint checks a different question and cannot replace a user-facing indicator.

const root = tracer.startSpan("GET /report", {}, ROOT_CONTEXT);

Read the full tutorial step

Example 02 · Tutorial excerpt

Create spans with useful boundaries

The service and database-fixture spans surround work that can explain the request. Their names remain bounded and understandable. Attributes describe the operation without embedding arbitrary customer data. Too many tiny spans can create overhead without helping a diagnosis.

tracer.startSpan("db.query orders", {}, parentContext);

Read the full tutorial step

Example 03 · Tutorial excerpt

Carry parent context explicitly

The broken database span uses ROOT_CONTEXT and becomes an independent trace. The safeguarded path places the service span in the supplied context before creating the child. A real network boundary additionally needs compatible injection and extraction of trace headers.

const childContext = trace.setSpan(parentContext, serviceSpan);

Read the full tutorial step

Example 04 · Tutorial excerpt

Inspect the distribution, not just its mean

The example uses nearest-rank p95 on eight recorded durations. One long sample can dominate the tail while barely moving an average. A tiny fixture makes this arithmetic visible; production percentile estimates depend on aggregation methods, histogram buckets and traffic volume.

sorted[Math.ceil(0.95 * sorted.length) - 1]

Read the full tutorial step

Example 05 · Tutorial excerpt

Relate a target to an error budget

A target states the permitted fraction of bad eligible events over a specified window. The lab’s illustrative target is 90% under 100 ms. Real alerts need a window, minimum useful volume and burn-rate reasoning rather than an alarm on every slow request.

budgetFraction = 1 - target;
consumedFraction = badEvents / eligibleEvents;

Read the full tutorial step