Skip to content

Commit

Permalink
add cross-cutting context api functions
Browse files Browse the repository at this point in the history
  • Loading branch information
blakeroberts-wk committed Jun 19, 2024
1 parent 84571dd commit 6f20d1f
Show file tree
Hide file tree
Showing 36 changed files with 391 additions and 387 deletions.
23 changes: 5 additions & 18 deletions .github/workflows/dart_ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ permissions:
contents: read
issues: write
pull-requests: write

jobs:
test-dartv2:
runs-on: ubuntu-latest
Expand All @@ -26,14 +26,8 @@ jobs:
- uses: dart-lang/setup-dart@v1
with:
sdk: 2.19.6
- name: Install protobuf-compiler
run: sudo apt install -y protobuf-compiler
- name: Install Dart dependencies
run: dart pub get
- name: Initialize protobuf
run: make init
- name: Format, analyze, and run tests
run: make format analyze test
- run: sudo apt install -y protobuf-compiler
- run: make init format analyze test
- name: Generate Coverage
run: dart test --coverage=./coverage
- name: Activate Coverage Package
Expand All @@ -56,12 +50,5 @@ jobs:
- uses: dart-lang/setup-dart@v1
with:
sdk: 3.2.0
- name: Install protobuf-compiler
run: sudo apt install -y protobuf-compiler
- name: Install Dart dependencies
run: dart pub get
- name: Initialize protobuf
run: make init
- name: Format, analyze, and run tests
run: |
make format analyze test
- run: sudo apt install -y protobuf-compiler
- run: make init format analyze test
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ init:
opentelemetry-proto/opentelemetry/proto/collector/trace/v1/trace_service.proto \
opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto \
opentelemetry-proto/opentelemetry/proto/resource/v1/resource.proto
./scripts/attach_copyright.sh

analyze:
@dart analyze
Expand Down
262 changes: 87 additions & 175 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,208 +1,120 @@
# OpenTelemetry for Dart

This repo is intended to be the Dart implementation of the OpenTelemetry project, with a
long-term goal of being open sourced.
This repository is the Dart implementation of the [OpenTelemetry project](https://opentelemetry.io/). 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).
## Project Status

## Getting Started

First, you will need to configure at least one exporter. An exporter determines what happens to the spans you collect.
The current options are:

| Exporter | Description |
| -------- | ----------- |
| [CollectorExporter](#collectorexporter) | Sends Spans to a configured opentelemetry-collector. |
| [ConsoleExporter](#consoleexporter) | Prints Spans to the console. |

### Span Exporters

#### CollectorExporter

The CollectorExporter requires a Uri of the opentelemetry-collector instance's trace collector.

```dart
import 'package:opentelemetry/sdk.dart' as otel_sdk;
final exporter = otel_sdk.CollectorExporter(Uri.parse('https://my-collector.com/v1/traces'));
```

#### ConsoleExporter

The ConsoleExporter has no requirements, and has no configuration options.

```dart
import 'package:opentelemetry/sdk.dart' as otel_sdk;
final exporter = otel_sdk.ConsoleExporter();
```

### Span Processors

Next, you will need at least one span processor. A span processor is responsible for collecting the spans you create and feeding them to the exporter.
The current options are:

| SpanProcessor | Description |
| -------- | ----------- |
| [BatchSpanProcessor](#batchspanprocessor) | Batches spans to be exported on a configured time interval. |
| [SimpleSpanProcessor](#simplespanprocessor) | Executes the provided exporter immediately upon closing the span. |

#### BatchSpanProcessor

BatchSpanProcessors collect up to 2048 spans per interval, and executes the provided exporter on a timer.
| Option | Description | Default |
| ------ | ----------- | ------- |
| maxExportBatchSize | At most, how many spans are processed per batch. | 512 |
| scheduledDelayMillis | How long to collect spans before processing them. | 5000 ms |

```dart
import 'package:opentelemetry/sdk.dart' as otel_sdk;
final exporter = otel_sdk.ConsoleExporter();
final processor = otel_sdk.BatchSpanProcessor(exporter, scheduledDelayMillis: 10000);
```

#### SimpleSpanProcessor

A SimpleSpanProcessor has no configuration options, and executes the exporter when each span is closed.

```dart
import 'package:opentelemetry/sdk.dart' as otel_sdk;
| Signal | Status |
| - | - |
| Traces | Beta |
| Metrics | Alpha |
| Logs | Unimplemented |

final exporter = otel_sdk.ConsoleExporter();
final processor = otel_sdk.SimpleSpanProcessor(exporter);
```

### Tracer Provider

A trace provider registers your span processors, and is responsible for managing any tracers.
| Option | Description | Default |
| ------ | ----------- | ------- |
| processors | A list of SpanProcessors to register. | A [SimpleSpanProcessor](#simplespanprocessor) configured with a [ConsoleExporter](#consoleexporter). |

```dart
import 'package:opentelemetry/sdk.dart' as otel_sdk;
import 'package:opentelemetry/api.dart';
final exporter = otel_sdk.CollectorExporter(Uri.parse('https://my-collector.com/v1/traces'));
final processor = otel_sdk.BatchSpanProcessor(exporter);
// Send spans to a collector every 5 seconds
final provider = otel_sdk.TracerProviderBase(processors: [processor]);
// Optionally, multiple processors can be registered
final provider = otel_sdk.TracerProviderBase(processors: [
otel_sdk.BatchSpanProcessor(otel_sdk.CollectorExporter(Uri.parse('https://my-collector.com/v1/traces'))),
otel_sdk.SimpleSpanProcessor(otel_sdk.ConsoleExporter())
]);
registerGlobalTracerProvider(provider);
final tracer = provider.getTracer('instrumentation-name');
// or
final tracer = globalTracerProvider.getTracer('instrumentation-name');
```

#### Tracer Provider with Browser Performance Features

A web-specific trace provider is also available. This trace provider makes available configurable options using the browser's performance API.

```dart
import 'package:opentelemetry/sdk.dart' as otel_sdk;
import 'package:opentelemetry/web_sdk.dart' as web_sdk;
import 'package:opentelemetry/api.dart';
final exporter = otel_sdk.CollectorExporter(Uri.parse('https://my-collector.com/v1/traces'));
final processor = otel_sdk.BatchSpanProcessor(exporter);
// This provider is configured to create tracers which use the browser's
// performance API instead of Dart's DateTime class when determining
// timestamps for any spans they create.
final provider = web_sdk.WebTracerProvider(
processors: [processor],
timeProvider: web_sdk.WebTimeProvider()
);
// This tracer has been configured to use the browser's performance API when
// determining timestamps for any spans it creates.
final tracer = provider.getTracer('instrumentation-name');
// Or, these trace providers can also be registered globally.
registerGlobalTracerProvider(provider);
final tracer = globalTracerProvider.getTracer('instrumentation-name');
```

Important Note: Span timestamps resulting from use of this trace provider may be inaccurate if the executing system is suspended for sleep.
See [https://github.com/open-telemetry/opentelemetry-js/issues/852](https://github.com/open-telemetry/opentelemetry-js/issues/852) for more information.
## Getting Started

## Collecting Spans
This section will show you how to initialize the OpenTelemetry SDK, capture a span, and propagate context.

To start a span, execute `startSpan` on the tracer with the name of what you are tracing. When complete, call `end` on the span.
### Initialize the OpenTelemetry SDK

```dart
final span = tracer.startSpan('doingWork');
...
span.end();
import 'package:opentelemetry/sdk.dart'
show
BatchSpanProcessor,
CollectorExporter,
ConsoleExporter,
SimpleSpanProcessor,
TracerProviderBase;
import 'package:opentelemetry/api.dart'
show registerGlobalTracerProvider, globalTracerProvider;
void main(List<String> args) {
final tracerProvider = TracerProviderBase(processors: [
BatchSpanProcessor(
CollectorExporter(Uri.parse('https://my-collector.com/v1/traces'))),
SimpleSpanProcessor(ConsoleExporter())
]);
registerGlobalTracerProvider(tracerProvider);
final tracer = globalTracerProvider.getTracer('instrumentation-name');
}
```

To create children spans, use `Context.withSpan` and `Context.execute()` to execute work with a given span.
### Capture a Span

```dart
final checkoutSpan = tracer.startSpan('checkout');
Context.current.withSpan(checkoutSpan).execute(() {
final ringUpSpan = tracer.startSpan('ringUp');
...
ringUpSpan.end();
final receiveSpan = tracer.startSpan('receiveCash');
...
receiveSpan.end();
final returnSpan = tracer.startSpan('returnChange');
...
returnSpan.end();
});
checkoutSpan.end();
import 'package:opentelemetry/api.dart' show StatusCode, globalTracerProvider;
void main(List<String> args) {
final tracer = globalTracerProvider.getTracer('instrumentation-name');
final span = tracer.startSpan('main');
try {
// do some work
span.addEvent('some work');
} catch (e, s) {
span
..setStatus(StatusCode.error, e.toString())
..recordException(e, stackTrace: s);
rethrow;
} finally {
span.end();
}
}
```

To avoid needing to pass spans around as arguments to other functions, you can get the current span with `Context.current.span`.
### Propagate Context

```dart
doWork() {
Span parentSpan = Context.current.span;
Context.current.withSpan(parentSpan).execute(() {
Span span = tracer.startSpan('doWork');
...
import 'package:opentelemetry/api.dart'
show
Context,
StatusCode,
contextWithSpan,
globalTracerProvider,
spanFromContext;
import 'package:opentelemetry/src/experimental_api.dart'
show globalContextManager;
void main(List<String> args) {
final tracer = globalTracerProvider.getTracer('instrumentation-name');
final span = tracer.startSpan('work');
final context = contextWithSpan(globalContextManager.active, span);
try {
// do some work
asyncWork(context);
} catch (e, s) {
span
..setStatus(StatusCode.error, e.toString())
..recordException(e, stackTrace: s);
rethrow;
} finally {
span.end();
});
}
}
Future asyncWork(Context context) async {
spanFromContext(context).addEvent('some async work');
}
```

### Span Events
#### High Resolution Timestamps

A Span Event is a human-readable message on an Span that represents a discrete event with no duration that can be tracked by a single timestamp. You can think of it like a primitive log.
A tracer provider can register a web-specific time provider that uses the browser's [performance API](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) instead of [DateTime](https://api.dart.dev/stable/dart-core/DateTime-class.html) when recording timestamps for a span's start timestamp, end timestamp, and span events.

```dart
span.addEvent('Doing something');
import 'package:opentelemetry/web_sdk.dart' as web_sdk;
const result = doWork();
final tracerProvider =
web_sdk.WebTracerProvider(timeProvider: web_sdk.WebTimeProvider());
```

You can also create Span Events with additional Attributes:
```dart
span.addEvent('some log', attributes: {
'log.severity': 'error',
'log.message': 'Data not found',
'request.id': requestId,
});
```
Important Note: Span timestamps may be inaccurate if the executing system is suspended for sleep. See [https://github.com/open-telemetry/opentelemetry-js/issues/852](https://github.com/open-telemetry/opentelemetry-js/issues/852) for more information.

## Development
## Contributing

In order to generate protobuf definitions, you must have [protoc](https://github.com/protocolbuffers/protobuf/releases) installed and available in your path.

### Publishing New Versions
See https://github.com/Workiva/Observability/blob/master/doc/publishing_opentelemetry_dart.md

Only Workiva maintainers can publish new versions of opentelemetry-dart.
Only Workiva maintainers can publish new versions of opentelemetry-dart. See [Publishing opentelemetry-dart](https://github.com/Workiva/Observability/blob/master/doc/publishing_opentelemetry_dart.md)
13 changes: 11 additions & 2 deletions lib/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@
export 'src/api/common/attribute.dart' show Attribute;
export 'src/api/common/resource_attributes.dart' show ResourceAttributes;
export 'src/api/common/semantic_attributes.dart' show SemanticAttributes;
export 'src/api/context/context.dart' show Context, ContextKey;
export 'src/api/context/context.dart'
show
Context,
ContextKey,
contextWithSpan,
contextWithSpanContext,
spanContextFromContext,
spanFromContext;
export 'src/api/exporters/span_exporter.dart' show SpanExporter;
export 'src/api/instrumentation_library.dart' show InstrumentationLibrary;
export 'src/api/open_telemetry.dart'
Expand All @@ -14,7 +21,9 @@ export 'src/api/open_telemetry.dart'
registerGlobalTextMapPropagator,
registerGlobalTracerProvider,
trace,
traceSync;
traceContext,
traceSync,
traceSyncContext;
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;
Expand Down
Loading

0 comments on commit 6f20d1f

Please sign in to comment.