opentelemetry_propagator_gcp 0.0.1
opentelemetry_propagator_gcp: ^0.0.1 copied to clipboard
OpenTelemetry propagator for Google Cloud's X-Cloud-Trace-Context header, mirroring the official Python, Go and JavaScript packages.
opentelemetry_propagator_gcp #
OpenTelemetry propagator for Google Cloud's X-Cloud-Trace-Context header, for Dart.
Google Cloud services — Cloud Run, App Engine, Cloud Functions, and the HTTP(S) load balancer among
them — inject X-Cloud-Trace-Context on inbound requests. Honouring it links your service's spans to
the trace the platform already started. Without it, your waterfall begins after the interesting part:
you lose the gap that shows queueing and cold start.
Google publishes this propagator for Python, Go and JavaScript. This package is the Dart equivalent.
Community-maintained. This is not an official Google or OpenTelemetry package. It mirrors the official implementations listed below, and we will gladly transfer it to GoogleCloudPlatform or to the OpenTelemetry project if either would like to own it — open an issue and it is yours.
Install #
dependencies:
opentelemetry_propagator_gcp: ^0.0.1
This package depends on the OpenTelemetry API only, never an SDK, so adding it does not force an SDK choice on your consumers.
Usage #
Most services want to accept the Google header and emit W3C traceparent. That is
CloudTraceOneWayPropagator, composed with a W3C propagator:
import 'package:dartastic_opentelemetry_api/dartastic_opentelemetry_api.dart';
import 'package:opentelemetry_propagator_gcp/opentelemetry_propagator_gcp.dart';
// Reads X-Cloud-Trace-Context, writes nothing. Pair it with a W3C propagator so
// outbound calls carry traceparent rather than a vendor-specific header.
const propagator = CloudTraceOneWayPropagator<Map<String, String>>();
final context = propagator.extract(
OTelAPI.context(),
headers,
MyHeaderGetter(headers),
);
Use CloudTraceFormatPropagator instead when a downstream service reads the Google header and does
not understand traceparent:
const propagator = CloudTraceFormatPropagator<Map<String, String>>();
propagator.inject(context, headers, MyHeaderSetter(headers));
// headers['x-cloud-trace-context'] == '<32 hex>/<decimal span id>;o=1'
Which one you want is the same split the official Python package makes with
CloudTraceFormatPropagator and CloudTraceOneWayPropagator.
The header format, and the mistake everyone makes #
X-Cloud-Trace-Context: TRACE_ID/SPAN_ID;o=OPTIONS
| Field | Encoding |
|---|---|
TRACE_ID |
32 hex characters, case-insensitive |
SPAN_ID |
decimal representation of an unsigned 64-bit integer |
o= |
1 if the parent was sampled, 0 if not; absent means not sampled |
SPAN_ID is decimal, not hex. Every other id in tracing is hex, so this is the field that gets
misread. 1234567890 is span id 00000000499602d2, not 0000001234567890 — and a wrong parent
produces a broken trace that still looks plausible. In Dart the value also does not fit a signed 64-bit
int, so parsing goes through BigInt.
Behaviour #
- A malformed header never throws.
extractreturns the context it was given, because a broken header from an upstream caller must not fail a request. - Extracted span contexts are marked remote, so samplers and backends treat the parent as foreign rather than locally created.
- Trace ids are normalised to lowercase. Google documents the field as case-insensitive; W3C requires lowercase.
- All-zero trace and span ids are rejected, per the W3C definition of an invalid id.
- Other
o=-adjacent options are tolerated and ignored, so a header that grows a field degrades to "not sampled" rather than to "unparseable". CloudTraceOneWayPropagator.fields()returns an empty list, because the OpenTelemetry contract definesfieldsas the keysinjectwrites — and it writes none.
The official implementations this mirrors #
- Python —
opentelemetry-propagator-gcp - Go —
opentelemetry-operations-go/propagator - JavaScript —
@google-cloud/opentelemetry-cloud-trace-propagator
License #
Apache-2.0, matching OpenTelemetry and the Google Cloud OpenTelemetry packages, so that donating this package to either would need no relicensing.