|
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