Traces
Custom traces allow you to measure the duration of specific operations in your app, providing insights into performance and behavior of code paths that matter to your business. See our Core Concepts section on Traces & Spans for a more detailed overview.
Creating Spans
Each span:
- Has a name
- Tracks when the operation started and ended
- Can include attributes (key-value pairs) that provide context
- Can record that an error occurred during the operation
- Can have parent-child relationships with other spans
- Must be ended to properly capture the operation's duration and avoid memory leaks
Basic Span Creation
The simplest way to create a span is with the startSpan
method:
import { trace } from '@embrace-io/web-sdk';
const span = trace.startSpan("span-name");
someAsyncOperation()
.then(() => span.end())
.catch(() => span.fail());
Span Attributes
Add context to your spans with attributes:
import { trace } from '@embrace-io/web-sdk';
// Adding attributes on start is recommended if they are known at that point
const span = trace.startSpan("span-name", {
attributes: {
"my-attr-on-create": "hello",
},
});
// But they can also be added later on if needed as long as the span hasn't been ended
span.setAttribute("my-other-attr", "bye");
Embrace span attribute values must be strings even though the OTel interface allows for a wider range of types
Span Hierarchy
Create parent-child relationships between spans to represent nested operations:
import { trace } from '@embrace-io/web-sdk';
const parentSpan = tracer.startSpan("the-parent");
const childSpan = tracer.startSpan("the-child", { parentSpan });
await someNestedOperation();
childSpan.end();
await finalStep();
parentSpan.end();
This creates a hierarchy that helps visualize the relationship between operations.
Add an Event to a Span
If you just want to record that something interesting happened at a certain point in the span's lifetime rather than a full child span you can instead add an event to the span:
import { trace } from '@embrace-io/web-sdk';
const span = trace.startSpan("span-name");
span.addEvent("something-happened", {
"some-event-attr": "event-attr-value",
});
Recording a Completed Span
Sometimes you need to create a span for an operation that has already completed:
import { trace } from '@embrace-io/web-sdk';
trace.startSpan("span-name", {
startTime: previouslyStartedTime,
}).end(previouslyEndedTime);
Best Practices
Naming Conventions
Use clear, descriptive names for your spans. Consider a naming convention such as:
- Using consistent casing for span names and attributes
- Including the general category followed by the specific operation
- Being consistent across your codebase
Granularity
Choose an appropriate level of granularity for your spans:
- Too coarse:
app-startup
(better to break into component parts) - Too fine-grained:
increment-counter
(likely too small to be useful) - Just right:
user-authentication
Capturing Meaningful Data
Add attributes that would be useful for troubleshooting:
trace.startSpan("span-name", {
attributes: {
"user-tier": "premium",
"data-size": dataSize.description,
"retry-count": retryCount.description
}
});