|
1 | 1 | # OpenTelemetry for Dart
|
2 | 2 |
|
3 |
| -This repo is intended to be the Dart implementation of the OpenTelemetry project, with a |
4 |
| -long-term goal of being open sourced. |
| 3 | +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). |
5 | 4 |
|
6 |
| -All contributions and designs should follow the |
7 |
| -[OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification) |
8 |
| -in an effort to be consistent with [all other languages](https://github.com/open-telemetry). |
| 5 | +## Project Status |
9 | 6 |
|
10 |
| -## Getting Started |
11 |
| - |
12 |
| -First, you will need to configure at least one exporter. An exporter determines what happens to the spans you collect. |
13 |
| -The current options are: |
14 |
| - |
15 |
| -| Exporter | Description | |
16 |
| -| -------- | ----------- | |
17 |
| -| [CollectorExporter](#collectorexporter) | Sends Spans to a configured opentelemetry-collector. | |
18 |
| -| [ConsoleExporter](#consoleexporter) | Prints Spans to the console. | |
19 |
| - |
20 |
| -### Span Exporters |
21 |
| - |
22 |
| -#### CollectorExporter |
23 |
| - |
24 |
| -The CollectorExporter requires a Uri of the opentelemetry-collector instance's trace collector. |
25 |
| - |
26 |
| -```dart |
27 |
| -import 'package:opentelemetry/sdk.dart' as otel_sdk; |
28 |
| -
|
29 |
| -final exporter = otel_sdk.CollectorExporter(Uri.parse('https://my-collector.com/v1/traces')); |
30 |
| -``` |
31 |
| - |
32 |
| -#### ConsoleExporter |
33 |
| - |
34 |
| -The ConsoleExporter has no requirements, and has no configuration options. |
35 |
| - |
36 |
| -```dart |
37 |
| -import 'package:opentelemetry/sdk.dart' as otel_sdk; |
38 |
| -
|
39 |
| -final exporter = otel_sdk.ConsoleExporter(); |
40 |
| -``` |
41 |
| - |
42 |
| -### Span Processors |
| 7 | +| Signal | Status | |
| 8 | +| - | - | |
| 9 | +| Traces | Beta | |
| 10 | +| Metrics | Alpha | |
| 11 | +| Logs | Unimplemented | |
43 | 12 |
|
44 |
| -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. |
45 |
| -The current options are: |
46 |
| - |
47 |
| -| SpanProcessor | Description | |
48 |
| -| -------- | ----------- | |
49 |
| -| [BatchSpanProcessor](#batchspanprocessor) | Batches spans to be exported on a configured time interval. | |
50 |
| -| [SimpleSpanProcessor](#simplespanprocessor) | Executes the provided exporter immediately upon closing the span. | |
| 13 | +## Getting Started |
51 | 14 |
|
52 |
| -#### BatchSpanProcessor |
| 15 | +This section will show you how to initialize the OpenTelemetry SDK, capture a span, and propagate context. |
53 | 16 |
|
54 |
| -BatchSpanProcessors collect up to 2048 spans per interval, and executes the provided exporter on a timer. |
55 |
| -| Option | Description | Default | |
56 |
| -| ------ | ----------- | ------- | |
57 |
| -| maxExportBatchSize | At most, how many spans are processed per batch. | 512 | |
58 |
| -| scheduledDelayMillis | How long to collect spans before processing them. | 5000 ms | |
| 17 | +### Initialize the OpenTelemetry SDK |
59 | 18 |
|
60 | 19 | ```dart
|
61 |
| -import 'package:opentelemetry/sdk.dart' as otel_sdk; |
62 |
| -
|
63 |
| -final exporter = otel_sdk.ConsoleExporter(); |
64 |
| -final processor = otel_sdk.BatchSpanProcessor(exporter, scheduledDelayMillis: 10000); |
| 20 | +import 'package:opentelemetry/sdk.dart' |
| 21 | + show |
| 22 | + BatchSpanProcessor, |
| 23 | + CollectorExporter, |
| 24 | + ConsoleExporter, |
| 25 | + SimpleSpanProcessor, |
| 26 | + TracerProviderBase; |
| 27 | +import 'package:opentelemetry/api.dart' |
| 28 | + show registerGlobalTracerProvider, globalTracerProvider; |
| 29 | +
|
| 30 | +void main(List<String> args) { |
| 31 | + final tracerProvider = TracerProviderBase(processors: [ |
| 32 | + BatchSpanProcessor( |
| 33 | + CollectorExporter(Uri.parse('https://my-collector.com/v1/traces'))), |
| 34 | + SimpleSpanProcessor(ConsoleExporter()) |
| 35 | + ]); |
| 36 | +
|
| 37 | + registerGlobalTracerProvider(tracerProvider); |
| 38 | + final tracer = globalTracerProvider.getTracer('instrumentation-name'); |
| 39 | +} |
65 | 40 | ```
|
66 | 41 |
|
67 |
| -#### SimpleSpanProcessor |
68 |
| - |
69 |
| -A SimpleSpanProcessor has no configuration options, and executes the exporter when each span is closed. |
| 42 | +### Capture a Span |
70 | 43 |
|
71 | 44 | ```dart
|
72 |
| -import 'package:opentelemetry/sdk.dart' as otel_sdk; |
73 |
| -
|
74 |
| -final exporter = otel_sdk.ConsoleExporter(); |
75 |
| -final processor = otel_sdk.SimpleSpanProcessor(exporter); |
| 45 | +import 'package:opentelemetry/api.dart' show StatusCode, globalTracerProvider; |
| 46 | +
|
| 47 | +void main(List<String> args) { |
| 48 | + final tracer = globalTracerProvider.getTracer('instrumentation-name'); |
| 49 | +
|
| 50 | + final span = tracer.startSpan('main'); |
| 51 | + try { |
| 52 | + // do some work |
| 53 | + span.addEvent('some work'); |
| 54 | + } catch (e, s) { |
| 55 | + span |
| 56 | + ..setStatus(StatusCode.error, e.toString()) |
| 57 | + ..recordException(e, stackTrace: s); |
| 58 | + rethrow; |
| 59 | + } finally { |
| 60 | + span.end(); |
| 61 | + } |
| 62 | +} |
76 | 63 | ```
|
77 | 64 |
|
78 |
| -### Tracer Provider |
79 |
| - |
80 |
| -A trace provider registers your span processors, and is responsible for managing any tracers. |
81 |
| -| Option | Description | Default | |
82 |
| -| ------ | ----------- | ------- | |
83 |
| -| processors | A list of SpanProcessors to register. | A [SimpleSpanProcessor](#simplespanprocessor) configured with a [ConsoleExporter](#consoleexporter). | |
| 65 | +### Propagate Context |
84 | 66 |
|
85 |
| -```dart |
86 |
| -import 'package:opentelemetry/sdk.dart' as otel_sdk; |
87 |
| -import 'package:opentelemetry/api.dart'; |
| 67 | +### Intra-process |
88 | 68 |
|
89 |
| -final exporter = otel_sdk.CollectorExporter(Uri.parse('https://my-collector.com/v1/traces')); |
90 |
| -final processor = otel_sdk.BatchSpanProcessor(exporter); |
| 69 | +In order to parent spans, context must be propagated. Propagation can be achieved by manually passing an instance of `Context` or by using Dart [`Zones`](https://dart.dev/libraries/async/zones). |
91 | 70 |
|
92 |
| -// Send spans to a collector every 5 seconds |
93 |
| -final provider = otel_sdk.TracerProviderBase(processors: [processor]); |
| 71 | +See the [noop context manager example](./example/noop_context_manager.dart) and [zone context manager example](./example/zone_context_manager.dart) for more information. |
94 | 72 |
|
95 |
| -// Optionally, multiple processors can be registered |
96 |
| -final provider = otel_sdk.TracerProviderBase(processors: [ |
97 |
| - otel_sdk.BatchSpanProcessor(otel_sdk.CollectorExporter(Uri.parse('https://my-collector.com/v1/traces'))), |
98 |
| - otel_sdk.SimpleSpanProcessor(otel_sdk.ConsoleExporter()) |
99 |
| -]); |
| 73 | +### Inter-process |
100 | 74 |
|
101 |
| -registerGlobalTracerProvider(provider); |
| 75 | +In order to parent spans between processes, context can be serialized and deserialized using a `TextMapPropagator`, `TextMapSetter`, and `TextMapGetter`. |
102 | 76 |
|
103 |
| -final tracer = provider.getTracer('instrumentation-name'); |
104 |
| -// or |
105 |
| -final tracer = globalTracerProvider.getTracer('instrumentation-name'); |
106 |
| -``` |
| 77 | +See the [W3C context propagation example](./example/w3c_context_propagation.dart) for more information. |
107 | 78 |
|
108 |
| -#### Tracer Provider with Browser Performance Features |
| 79 | +#### High Resolution Timestamps |
109 | 80 |
|
110 |
| -A web-specific trace provider is also available. This trace provider makes available configurable options using the browser's performance API. |
| 81 | +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. |
111 | 82 |
|
112 | 83 | ```dart
|
113 |
| -import 'package:opentelemetry/sdk.dart' as otel_sdk; |
114 | 84 | import 'package:opentelemetry/web_sdk.dart' as web_sdk;
|
115 |
| -import 'package:opentelemetry/api.dart'; |
116 |
| -
|
117 |
| -final exporter = otel_sdk.CollectorExporter(Uri.parse('https://my-collector.com/v1/traces')); |
118 |
| -final processor = otel_sdk.BatchSpanProcessor(exporter); |
119 |
| -
|
120 |
| -// This provider is configured to create tracers which use the browser's |
121 |
| -// performance API instead of Dart's DateTime class when determining |
122 |
| -// timestamps for any spans they create. |
123 |
| -final provider = web_sdk.WebTracerProvider( |
124 |
| - processors: [processor], |
125 |
| - timeProvider: web_sdk.WebTimeProvider() |
126 |
| -); |
127 |
| -
|
128 |
| -// This tracer has been configured to use the browser's performance API when |
129 |
| -// determining timestamps for any spans it creates. |
130 |
| -final tracer = provider.getTracer('instrumentation-name'); |
131 |
| -
|
132 |
| -// Or, these trace providers can also be registered globally. |
133 |
| -registerGlobalTracerProvider(provider); |
134 |
| -final tracer = globalTracerProvider.getTracer('instrumentation-name'); |
135 |
| -``` |
136 |
| - |
137 |
| -Important Note: Span timestamps resulting from use of this trace provider may be inaccurate if the executing system is suspended for sleep. |
138 |
| -See [https://github.com/open-telemetry/opentelemetry-js/issues/852](https://github.com/open-telemetry/opentelemetry-js/issues/852) for more information. |
139 |
| - |
140 |
| -## Collecting Spans |
141 |
| - |
142 |
| -To start a span, execute `startSpan` on the tracer with the name of what you are tracing. When complete, call `end` on the span. |
143 |
| - |
144 |
| -```dart |
145 |
| -final span = tracer.startSpan('doingWork'); |
146 |
| -... |
147 |
| -span.end(); |
148 |
| -``` |
149 |
| - |
150 |
| -To create children spans, use `Context.withSpan` and `Context.execute()` to execute work with a given span. |
151 |
| - |
152 |
| -```dart |
153 |
| -final checkoutSpan = tracer.startSpan('checkout'); |
154 |
| -Context.current.withSpan(checkoutSpan).execute(() { |
155 |
| - final ringUpSpan = tracer.startSpan('ringUp'); |
156 |
| - ... |
157 |
| - ringUpSpan.end(); |
158 |
| - final receiveSpan = tracer.startSpan('receiveCash'); |
159 |
| - ... |
160 |
| - receiveSpan.end(); |
161 |
| - final returnSpan = tracer.startSpan('returnChange'); |
162 |
| - ... |
163 |
| - returnSpan.end(); |
164 |
| -}); |
165 |
| -checkoutSpan.end(); |
166 |
| -``` |
167 | 85 |
|
168 |
| -To avoid needing to pass spans around as arguments to other functions, you can get the current span with `Context.current.span`. |
169 |
| - |
170 |
| -```dart |
171 |
| -doWork() { |
172 |
| - Span parentSpan = Context.current.span; |
173 |
| -
|
174 |
| - Context.current.withSpan(parentSpan).execute(() { |
175 |
| - Span span = tracer.startSpan('doWork'); |
176 |
| - ... |
177 |
| - span.end(); |
178 |
| - }); |
179 |
| -} |
| 86 | +final tracerProvider = |
| 87 | + web_sdk.WebTracerProvider(timeProvider: web_sdk.WebTimeProvider()); |
180 | 88 | ```
|
181 | 89 |
|
182 |
| -### Span Events |
183 |
| - |
184 |
| -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. |
185 |
| - |
186 |
| -```dart |
187 |
| -span.addEvent('Doing something'); |
188 |
| -
|
189 |
| -const result = doWork(); |
190 |
| -``` |
191 |
| - |
192 |
| -You can also create Span Events with additional Attributes: |
193 |
| -```dart |
194 |
| -span.addEvent('some log', attributes: { |
195 |
| - 'log.severity': 'error', |
196 |
| - 'log.message': 'Data not found', |
197 |
| - 'request.id': requestId, |
198 |
| -}); |
199 |
| -``` |
| 90 | +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. |
200 | 91 |
|
201 |
| -## Development |
| 92 | +## Contributing |
202 | 93 |
|
203 | 94 | In order to generate protobuf definitions, you must have [protoc](https://github.com/protocolbuffers/protobuf/releases) installed and available in your path.
|
204 | 95 |
|
205 | 96 | ### Publishing New Versions
|
206 |
| -See https://github.com/Workiva/Observability/blob/master/doc/publishing_opentelemetry_dart.md |
207 | 97 |
|
208 |
| -Only Workiva maintainers can publish new versions of opentelemetry-dart. |
| 98 | +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) |
0 commit comments