Trace spans are the building blocks of a trace. Each span represents one specific step in a request, like a database query or an API call. They are hierarchical because spans are linked, showing how each part of the request depends on another. This hierarchy gives a clear picture of what happened in your app and helps you pinpoint issues faster.
A span is a single operation in a trace. For example, if a user request involves a database query and an API call, there will be separate spans for each. Each span includes details like:
Spans are hierarchical to show relationships between operations. Every span has a parent span (except the root span) and may have child spans. This hierarchy makes it easier to:
OpenTelemetry automatically links spans together using context propagation. While OpenTelemetry is market's default way to instrument code, most popular libraries already has it inside automatically. Here’s an example of creating a root span and linking child spans in TypeScript:
1import { trace, context, SpanStatusCode } from '@opentelemetry/api';
2
3const tracer = trace.getTracer('example-service');
4
5// Create a root span
6const rootSpan = tracer.startSpan('process-request');
7
8// Propagate context so child spans inherit the trace ID and parent span
9context.with(trace.setSpan(context.active(), rootSpan), () => {
10 try {
11 // Create a child span for a database query
12 const dbSpan = tracer.startSpan('fetch-database', {
13 attributes: { query: 'SELECT * FROM users WHERE id = 123' },
14 });
15
16 // Simulate an error
17 const errorOccurred = false; // Change to true to simulate an error
18 if (errorOccurred) {
19 dbSpan.recordException(new Error('Database connection failed'));
20 dbSpan.setStatus({ code: SpanStatusCode.ERROR });
21 }
22
23 dbSpan.end();
24
25 // Create another child span for an API call
26 const apiSpan = tracer.startSpan('call-payment-api', {
27 attributes: { endpoint: '/payment', method: 'POST' },
28 });
29
30 apiSpan.end();
31 } catch (error) {
32 rootSpan.recordException(error);
33 rootSpan.setStatus({ code: SpanStatusCode.ERROR });
34 }
35});
36
37// End the root span
38rootSpan.end();
39
In this example, rootSpan represents the overall request, while dbSpan and apiSpan represent specific steps. Context propagation ensures they are all linked in a hierarchy.
Hierarchical spans provide a clear timeline and structure for debugging. For example:
Otelic.com lets you visualize the entire span hierarchy in a user-friendly way. You can jump between spans and logs, ensuring no detail is missed. Combined with the market’s best pricing per GB, Otelic makes it affordable to keep more data for deeper insights without breaking your budget.