Start with auto-instrumentation and add to it. Manual spans are meant to
sit inside the trace auto-instrumentation already produces, not to replace
it. See Instrument your application.
What is worth a span
Good candidates:Creating a span
Every SDK follows the same shape: get a tracer, start a span, do the work, end the span. Language-specific syntax is in the OpenTelemetry documentation for your SDK; the parts that decide whether it is useful are below.1
Name the operation, not the instance
charge-payment, not charge-payment-8817. A name containing an
identifier produces one operation per request, which makes aggregation —
the whole point — impossible.2
Attach the identifiers as attributes
order.id, customer.tier, payment.provider. This is where per-request
values belong, and where they are cheap.3
Record the outcome
Set the span’s status to error when it fails, and record the exception.
A span that failed but reports success is worse than no span — it is
evidence pointing the wrong way.
4
End it, always
Use your language’s scope or context manager so it ends on the error path
too. A leaked span is a trace that never completes and never arrives.
Attributes, events and status
Prefix your own attribute names.
acme.order.id, not order.id, so
nothing you invent collides with an OpenTelemetry semantic convention added
later. Follow the conventions where one exists — see
Resource attributes.Context propagation
A manual span joins the current trace automatically if the context reaches it. That is where manual instrumentation usually goes wrong. Across a network boundary, propagation is thetraceparent header, and
auto-instrumentation handles it. If you make an HTTP call with a client the SDK
does not instrument, you must inject the header yourself or the trace ends
there.
Connecting logs to traces
A log line written while a span is active carries that span’s trace id, and becomes clickable from the trace.Custom metrics
Where a span answers “what happened in this request”, a metric answers “how often, across all of them”. Counters, histograms and gauges are all available through the SDK.Verify
1
Trigger the code path
Then open Traces and find the trace.
2
Confirm your span is nested, not a root
A manual span appearing as its own root trace means the context did not
reach it — see Context propagation.
3
Confirm the failure path
Force an error and check the span is marked as failed and carries the
exception. This is the half people forget to test, and it is the half you
need during an incident.
Next
Auto-instrumentation
The layer this sits on top of.
Resource attributes
Naming, conventions and cardinality.
Explore traces
Finding what you instrumented.