Skip to content

Commit

Permalink
Merge pull request #19 from michaelyeager-wf/myeager-wf/O11Y-1045
Browse files Browse the repository at this point in the history
O11Y-1045: opentelemetry-dart must manage different contexts for async code
  • Loading branch information
rmconsole4-wk authored Oct 21, 2021
2 parents cbccce6 + 8b805ca commit 79bab02
Show file tree
Hide file tree
Showing 38 changed files with 287 additions and 369 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# OpenTelemetry for Dart

This repo is intended to be the Dart implementation of the OpenTelemetry project, with a
This repo is intended to be the Dart implementation of the OpenTelemetry project, with a
long-term goal of being open sourced.

All contributions and designs should follow the
[OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification)
All contributions and designs should follow the
[OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification)
in an effort to be consistent with [all other languages](https://github.com/open-telemetry).

## Getting Started
Expand Down Expand Up @@ -115,12 +115,12 @@ withContext(setSpan(Context.current, checkoutSpan), () {
checkoutSpan.end();
```

To avoid needing to pass spans around as arguments to other functions, you can get the current span with `getSpan`.
To avoid needing to pass spans around as arguments to other functions, you can get the current span with `Context.current.span`.
```
doWork() {
Span parentSpan = getSpan(Context.current);
Span parentSpan = Context.current.span;
withContext(setSpan(Context.current, parentSpan), () {
Context.current.withSpan(parentSpan).execute(() {
Span span = tracer.startSpan('doWork');
...
span.end();
Expand Down
2 changes: 0 additions & 2 deletions lib/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ export 'src/api/context/context.dart' show Context;
export 'src/api/propagation/extractors/text_map_getter.dart' show TextMapGetter;
export 'src/api/propagation/injectors/text_map_setter.dart' show TextMapSetter;
export 'src/api/propagation/text_map_propagator.dart' show TextMapPropagator;
export 'src/api/trace/context_utils.dart'
show getSpan, getSpanContext, setSpan, withContext;
export 'src/api/trace/id_generator.dart' show IdGenerator;
export 'src/api/trace/span.dart' show Span;
export 'src/api/trace/span_context.dart' show SpanContext;
Expand Down
6 changes: 6 additions & 0 deletions lib/sdk.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export 'src/sdk/trace/exporters/collector_exporter.dart' show CollectorExporter;
export 'src/sdk/trace/exporters/console_exporter.dart' show ConsoleExporter;
export 'src/sdk/trace/propagation/w3c_trace_context_propagator.dart'
show W3CTraceContextPropagator;
export 'src/sdk/trace/propagation/injectors/fcontext_injector.dart'
show FContextInjector;
export 'src/sdk/trace/propagation/extractors/fcontext_extractor.dart'
show FContextExtractor;
export 'src/sdk/trace/samplers/always_off_sampler.dart' show AlwaysOffSampler;
export 'src/sdk/trace/samplers/always_on_sampler.dart' show AlwaysOnSampler;
export 'src/sdk/trace/span_processors/batch_processor.dart'
Expand Down
83 changes: 37 additions & 46 deletions lib/src/api/context/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,30 @@
/// directly. Other users should usually not interact with Context at all and
/// should instead manipulate it through cross-cutting concerns APIs provided by
/// OpenTelemetry SDKs.
import 'dart:async';

import 'package:opentelemetry/src/sdk/trace/span.dart';
import 'package:opentelemetry/src/sdk/trace/span_context.dart';

/// [ContextKey] used to store spans in a [Context].
final ContextKey spanKey = Context.createKey('OpenTelemetry Context Key SPAN');

class Context {
final Zone _zone;

Context._(this._zone);

/// The active context.
static Context get current => _current ?? Context._(Zone.current);
static Context _current;
static Context get current => Context._(Zone.current);

/// The root context which all other contexts are derived from.
///
/// It should generally not be required to use the root [Context] directly -
/// instead, use [Context.current] to operate on the current [Context].
/// Only use this context if you are certain you need to disregard the
/// current [Context]. For example, when instrumenting an asynchronous
/// event handler which may fire while an unrelated [Context] is "current".
static Context get root => Context._(Zone.root);

/// Returns a key to be used to read and/or write values to a context.
///
Expand All @@ -36,41 +53,6 @@ class Context {
/// identical keys.
static ContextKey createKey(String name) => ContextKey(name);

/// Makes [context] the active context (such that [current] returns this given
/// context) and returns a scope that should closed by passing it to [detach].
///
/// Every call to [attach] should result in a corresponding call to [detach].
static Scope attach(Context context) {
if (context == null) {
// Null context not allowed, so ignore it.
return Scope._noop;
}

if (context._zone == _current?._zone) {
return Scope._noop;
}

final prev = _current;
_current = context;
return Scope._(() {
_current = prev;
});
}

/// Resets the active context to the value that was active before attaching
/// the context associated with [scope].
///
/// If [scope] is associated with a context that is not the active one, an
/// error will be logged.
void detach(Scope scope) {
scope._close();
}

/// The implicit "context" that is used to implement the APIs on this class.
final Zone _zone;

Context._(this._zone);

/// Returns the value from this context identified by [key], or null if no
/// such value is set.
T getValue<T>(ContextKey key) => _zone[key];
Expand All @@ -82,18 +64,27 @@ class Context {
/// of the context values will be inherited.
Context setValue(ContextKey key, Object value) =>
Context._(_zone.fork(zoneValues: {key: value}));

/// Returns a new [Context] created from this one with the given [Span]
/// set.
Context withSpan(Span span) => setValue(spanKey, span);

/// Execute a function [fn] within this [Context] and return its result.
R execute<R>(R Function() fn) => _zone.run(fn);

/// Get the [Span] attached to this [Context], or null if no such
/// [Span] exists.
Span get span => getValue(spanKey);

/// Get the [SpanContext] from this [Context], or null if no such
/// [SpanContext] exists.
SpanContext get spanContext => getValue(spanKey)?.spanContext;
}

class ContextKey {
/// name of the context key.
/// Name of the context key.
final String name;

/// construct a [ContextKey] with a given [name].
/// Construct a [ContextKey] with a given [name].
ContextKey(this.name);
}

class Scope {
static final Scope _noop = Scope._(() {});
final void Function() _close;
Scope._(this._close);
}
27 changes: 0 additions & 27 deletions lib/src/api/trace/context_utils.dart

This file was deleted.

14 changes: 9 additions & 5 deletions lib/src/api/trace/nonrecording_span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ import 'tracer.dart';
/// [SpanContext] being injected or extracted for external calls.
class NonRecordingSpan extends Span implements api.Span {
final Attributes _attributes = sdk_attributes.Attributes.empty();
final SpanStatus _status = SpanStatus()..code = StatusCode.OK;
final SpanStatus _status = SpanStatus()..code = StatusCode.ok;
final Tracer _tracer = NoopTracer();
final SpanContext _spanContext;

NonRecordingSpan(this._spanContext)
: super('NON_RECORDING', _spanContext, null, [], NoopTracer());
: super(
'NON_RECORDING', _spanContext, SpanId.invalid(), [], NoopTracer());

@override
Attributes get attributes => _attributes;
Expand All @@ -41,13 +42,16 @@ class NonRecordingSpan extends Span implements api.Span {
}

@override
Int64 get endTime => Int64.ZERO;
Int64 get endTime => null;

@override
String get name => 'NON_RECORDING';

@override
SpanId get parentSpanId => null;
bool get isRecording => false;

@override
SpanId get parentSpanId => SpanId.invalid();

@override
void setStatus(StatusCode status, {String description}) {
Expand All @@ -58,7 +62,7 @@ class NonRecordingSpan extends Span implements api.Span {
sdk_spancontext.SpanContext get spanContext => _spanContext;

@override
Int64 get startTime => Int64.ZERO;
Int64 get startTime => null;

@override
SpanStatus get status => _status;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/api/trace/noop_tracer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class NoopTracer implements api.Tracer {
@override
api.Span startSpan(String name,
{api.Context context, api.Attributes attributes}) {
final SpanContext parentContext = api.getSpanContext(context);
final parentContext = context.spanContext;

return NonRecordingSpan(
(parentContext.isValid) ? parentContext : SpanContext.invalid());
Expand Down
2 changes: 1 addition & 1 deletion lib/src/api/trace/span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ abstract class Span {
/// Sets the status to the [Span].
///
/// If used, this will override the default [Span] status. Default status code
/// is [StatusCode.UNSET].
/// is [StatusCode.unset].
///
/// Only the value of the last call will be recorded, and implementations are
/// free to ignore previous calls.
Expand Down
10 changes: 5 additions & 5 deletions lib/src/api/trace/span_id.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import 'span.dart';
/// Class representing an ID for a single [Span].
/// See https://www.w3.org/TR/trace-context/#parent-id for full specification.
abstract class SpanId {
static const SIZE_BITS = 16;
static const SIZE_BYTES = 8;
static final List<int> INVALID =
List<int>.filled(SIZE_BYTES, 0); // 0000000000000000
static final List<int> ROOT = [];
static const sizeBits = 16;
static const sizeBytes = 8;
static final List<int> invalid =
List<int>.filled(sizeBytes, 0); // 0000000000000000
static final List<int> root = [];

/// Retrieve this SpanId as a list of byte values.
List<int> get();
Expand Down
8 changes: 4 additions & 4 deletions lib/src/api/trace/span_status.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/// The set of canonical status codes.
enum StatusCode {
/// The default status.
UNSET,
unset,

/// The operation contains an error.
ERROR,
error,

/// The operation has been validated by an Application developers or
/// Operator to have completed successfully.
OK,
ok,
}

/// A representation of the status of a Span.
class SpanStatus {
StatusCode code = StatusCode.UNSET;
StatusCode code = StatusCode.unset;
String description;
}
8 changes: 4 additions & 4 deletions lib/src/api/trace/trace_flags.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// A class which controls tracing flags for sampling, trace level, and so forth.
/// See https://www.w3.org/TR/trace-context/#trace-flags for full specification.
abstract class TraceFlags {
static const int SIZE = 2;
static const int NONE = 0x00;
static const int SAMPLED_FLAG = 0x01;
static const int INVALID = 0xff;
static const int size = 2;
static const int none = 0x00;
static const int sampledFlag = 0x01;
static const int invalid = 0xff;
}
8 changes: 4 additions & 4 deletions lib/src/api/trace/trace_id.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/// Class representing an ID for a single Trace.
/// See https://www.w3.org/TR/trace-context/#trace-id for full specification.
abstract class TraceId {
static const SIZE_BITS = 32;
static const SIZE_BYTES = 16;
static final List<int> INVALID =
List<int>.filled(SIZE_BYTES, 0); // 00000000000000000000000000000000
static const sizeBits = 32;
static const sizeBytes = 16;
static final List<int> invalid =
List<int>.filled(sizeBytes, 0); // 00000000000000000000000000000000

/// Retrieve this TraceId as a list of byte values.
List<int> get();
Expand Down
6 changes: 3 additions & 3 deletions lib/src/sdk/trace/exporters/collector_exporter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ class CollectorExporter implements SpanExporter {
pb.Status_StatusCode statusCode;

switch (span.status.code) {
case StatusCode.UNSET:
case StatusCode.unset:
statusCode = pb.Status_StatusCode.STATUS_CODE_UNSET;
break;
case StatusCode.ERROR:
case StatusCode.error:
statusCode = pb.Status_StatusCode.STATUS_CODE_ERROR;
break;
case StatusCode.OK:
case StatusCode.ok:
statusCode = pb.Status_StatusCode.STATUS_CODE_OK;
break;
}
Expand Down
8 changes: 5 additions & 3 deletions lib/src/sdk/trace/exporters/console_exporter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ class ConsoleExporter implements SpanExporter {
for (var i = 0; i < spans.length; i++) {
final span = spans[i];
print({
'traceId': span.spanContext.traceId.toString(),
'parentId': span.parentSpanId?.toString(),
'traceId': '${span.spanContext.traceId}',
'parentId': '${span.parentSpanId}',
'name': span.name,
'id': span.spanContext.spanId.toString(),
'id': '${span.spanContext.spanId}',
'timestamp': span.startTime,
'duration': span.endTime - span.startTime,
'flags': '${span.spanContext.traceFlags}',
'state': '${span.spanContext.traceState}',
'status': span.status.code
});
}
Expand Down
Loading

0 comments on commit 79bab02

Please sign in to comment.