Closed blakeroberts-wk closed 1 day ago
The following demonstrates the current APIs and revised APIs for automatic and manual context propagation.
Current APIs:
Span parent = tracer.startSpan('parent')..end();
Context context = contextWithSpan(globalContextManager.active, parent);
(context as ZoneContext).run((_) {
tracer.startSpan('child').end();
});
Revised APIs:
Span parent = tracer.startSpan('parent')..end();
Zone zone = zoneWithSpan(parent);
..run(() {
tracer.startSpan('child').end();
});
The brevity of this example makes the differences subtle:
Context
class is removed/replaced by using the standard library Zone
directly.ContextManager
is removed. Under the proposed changes, an OTel "context" in Dart is a Zone
. So, like Context
, the concept of a ContextManager
is superfluous.Manual propagation is simplified to a lesser extent:
Current APIs:
Span parent = tracer.startSpan('parent')..end();
Context context = contextWithSpan(globalContextManager.active, parent);
tracer.startSpan('child', context: context).end();
Proposed APIs:
Span parent = tracer.startSpan('parent')..end();
Zone zone = zoneWithSpan(parent);
Span child = tracer.startSpan('child', zone: zone)..end();
I agree that based on the spec for Context, Dart Zones fit all the requirements as-is. And the spec even says:
Languages are expected to use the single, widely used Context implementation if one exists for them. In the cases where an extremely clear, pre-existing option is not available, OpenTelemetry MUST provide its own Context implementation.
If we wanted a middle ground that would allow for custom context management without having to use Dart Zone
s, we could still keep the abstract Context
class and provide helpers to wrap a Zone so that it implements Context
? Not sure if that's worth it, though. I lean towards the simpler approach of using Zones directly and we can always change course if a compelling use case appears.
Is your feature request related to a problem?
The current
Context
implementation is as an interface where a registeredContextManager
supplies the implementation. This allows a consumer (such as a library) to rely on theContext
interface without needing to worry about the concrete implementation. In other words, the consumer does not need to worry about whether theContext
implementation is aZoneContext
orMapContext
.However, in order to propagate context using zones, code must execute from the scope of
Zone.run()
. But to manually propagate context using aMapContext
, no such requirement exists. As a result, theContext
API has to supply arun()
method to support one of the two context propagation methods.Now, let's take a closer look at the two supported modes of context propagation: zone context propagation and map context propagation. Zone context propagation uses zones, simple enough. Map context propagation isn't really a unique propagation strategy. It is manual propagation. The Context stores its values in a map, but this has nothing to do with propagation. Rather than using a map, a zone can hold those values too. That
ZoneContext
can be propagated manually just the same as aMapContext
.So if a
ZoneContext
can do anything aMapContext
can do, and aZoneContext
can propagate context automatically too, what's the point of having aMapContext
?(1) isn't the case since Dart supports zones natively. I haven't seen evidence to support (2). All that remains are unknowns, (3). I don't think it's wise to code against unknown considerations. To code for extensibility is good. But again, "anything [a map] can do [a zone] can do better 🎵."
Describe the solution you'd like
Simple, intuitive APIs.
Describe alternatives you've considered
The above shows cross-cutting API additions that allow a
Context
to propagate via aZone
. This would allowContext
to be a single concrete implementation.We could take this even further and remove
Context
altogether in favor of usingZone
directly in all cases. This would be achieved by replacing the current cross-cutting APIs forContext
withZone
specifics:The code snippet above:
Zone
is immutable and capable of getting and setting values.Here are some example usages of this set of APIs:
Additional context
https://github.com/Workiva/opentelemetry-dart/pull/176