Skip to main content

Custom instrumentation

Custom Spans

Custom spans let you mark manual business flows and correlate them with Dart-side network/interaction/error instrumentation.

Prerequisite: initialize the SDK with traceParentInHeader.enable = true. Without this, CxFlutterPlugin.getCustomTracer() returns null.

import 'package:cx_flutter_plugin/cx_flutter_plugin.dart';
import 'package:cx_flutter_plugin/cx_http_client.dart';

Future<void> runCheckoutFlow() async {
final tracer = CxFlutterPlugin.getCustomTracer(
ignoredInstruments: const [
// Optional: disable linkage for specific Dart instruments.
CoralogixIgnoredInstrument.userInteractions,
],
);
if (tracer == null) return;

final global = await tracer.startGlobalSpan(
'checkout.flow',
labels: {'screen': 'checkout'},
);
if (global == null) return; // Native rejected (e.g., another global span is active).

try {
await global.withContext(() async {
final client = CxHttpClient();
try {
await client.get(Uri.parse('https://api.example.com/checkout'));
} finally {
client.close();
}
});

final child = await global.startCustomSpan('checkout.payment');
await child.endSpan();
} finally {
await global.endSpan();
}
}

withContext uses runZonedGuarded under the hood, so the active global span id is preserved across await chains in that flow and not leaked to unrelated async tasks.

Time Measurement

Time arbitrary spans of work with startTimeMeasure / endTimeMeasure. The duration is reported by the native SDK as a custom-measurement span (milliseconds) — useful when you need to measure something the SDK can't auto-instrument (checkout flows, custom render passes, asset loading, etc.).

await CxFlutterPlugin.startTimeMeasure('checkout', labels: {'cart_size': 3});
// ... do work ...
await CxFlutterPlugin.endTimeMeasure('checkout');
MethodArgumentBehavior
startTimeMeasurename: StringUnique identifier. Empty / whitespace-only names are ignored. Duplicate start for an in-flight name is ignored (first wins).
startTimeMeasurelabels: Map<String, dynamic>?Optional. Merged with SDK-level labels at end; start labels win on key collision.
endTimeMeasurename: StringMust match a prior start. No-op when never started, already ended, or the session has gone idle.

The bridge is a pure pass-through — no Dart-side state is kept, the native SDK owns the in-flight registry. You are responsible for pairing every start with exactly one end (leaked starts persist in memory until the session ends).

Last updated on
Was this page helpful?