Traces
Overview
Embrace's Traces solution gives you visibility into any app operation you'd like to track, including duration, success rate, and any contextual metadata collected at runtime that helps debug the root cause of your mobile app's performance issues. You can quickly spot bottlenecks in your app's architecture, pinpoint areas you need to troubleshoot with high precision, and ultimately deliver a truly optimized user experience.
API usage examples
Start and stop a span
A span typically models the lifecycle of an operation in your app. You start it, let the operation finish, then stop the span, and Embrace records how long the span took.
final span = await Embrace.instance.startSpan('my-span');
// some lengthy operation
await span?.stop();
Add attributes to a span
If you have metadata values that relate to the entire span you can add these as attributes.
final span = await Embrace.instance.startSpan('my-span');
await span?.addAttribute('my-key', 'my-value');
Add events to a span
If you have an event that happens at a point in time within a span, you can add a span event. This can contain optional attributes about the event.
final span = await Embrace.instance.startSpan('my-span');
await span?.addEvent(
'my-event-name',
attributes: {
'my-event-attribute-key': 'my-event-attribute-value',
},
);
Record an operation that already happened
If an operation already happened or you don't want to call start/stop individually, it's possible to record that a span happened via recordCompletedSpan.
final start = DateTime.now().millisecondsSinceEpoch - 1000;
final end = start + 500;
final result = await Embrace.instance.recordCompletedSpan(
'my-recorded-span',
start,
end,
attributes: {'my-span-key': 'my-span-value'},
events: [
EmbraceSpanEvent(
name: 'my-span-event',
attributes: {'my-event-key': 'my-event-value'},
timestampMs: DateTime.now().millisecondsSinceEpoch,
)
],
);
Add child spans
It's possible to create child spans. This can be useful if you want to record finer details about an operation, for example, a network request span might have a child span of JSON serialization to see how long it took.
final span = await Embrace.instance.startSpan('my-span');
if (span != null) {
final childSpan =
await Embrace.instance.startSpan('child-span', parent: span);
await childSpan?.stop();
await span.stop();
}
Export to OpenTelemetry collectors
To send telemetry to any OpenTelemetry Collector directly from your app, you can set up a SpanExporter and LogRecordExporter. When configured, telemetry is sent to these exporters as soon as it's recorded. You can configure more than one exporter of each signal, but be aware of the performance impact of sending too many network requests if that applies.
All telemetry in the Embrace Flutter SDK is routed through Embrace's Android/iOS SDKs. Configure Android/iOS exporters before initializing the SDK to send Dart telemetry to your desired destination.
Android OTel export
Follow this guide to set up OpenTelemetry exporters on Android.
iOS OTel export
Follow this guide for details on setting up OpenTelemetry exporters on iOS.
Exporters are set when the SDK is configured. A sample implementation looks like:
try Embrace
.setup(
options: Embrace.Options(
appId: "", // Your App ID from Embrace Dash
platform: .flutter,
export: OpenTelemetryExport(
spanExporter: OtlpHttpTraceExporter(
endpoint: URL(string: "https://otelcollector-gateway.mydomain.com/v1/traces")!,
useSession: URLSession(configuration: myAuthorizedConfiguration)
),
logExporter: OtlpHttpLogExporter(
endpoint: URL(string: "https://otelcollector-gateway.mydomain.com/v1/logs")!,
useSession: URLSession(configuration: myAuthorizedConfiguration)
)
)
)
)
.start()
The OpenTelemetry-Swift repository does not support CocoaPods, so you can't import ready-made exporters directly. We recommend adding a new file that implements a Swift SpanExporter or LogRecordExporter directly, using the ready-made exporters as reference implementations.