Line data Source code
1 : // Copyright The OpenTelemetry Authors
2 : // SPDX-License-Identifier: Apache-2.0
3 :
4 : import '../span.dart';
5 : import 'span_exporter.dart';
6 :
7 : /// A simple span exporter that prints spans to the console.
8 : ///
9 : /// This exporter is primarily used for debugging and testing, as it formats
10 : /// and prints span information to the standard output rather than sending them
11 : /// to a telemetry backend.
12 : ///
13 : /// The output includes span name, trace ID, span ID, parent span ID, duration,
14 : /// status, and attributes for better debugging visibility.
15 : class ConsoleExporter extends SpanExporter {
16 2 : @override
17 : Future<void> export(List<Span> spans) async {
18 4 : for (final span in spans) {
19 2 : _printSpan(span);
20 : }
21 : }
22 :
23 2 : void _printSpan(Span span) {
24 2 : final buffer = StringBuffer();
25 2 : buffer.writeln('=== OpenTelemetry Span ===');
26 6 : buffer.writeln('Name: ${span.name}');
27 8 : buffer.writeln('Trace ID: ${span.spanContext.traceId}');
28 8 : buffer.writeln('Span ID: ${span.spanContext.spanId}');
29 :
30 4 : if (span.spanContext.parentSpanId != null &&
31 6 : span.spanContext.parentSpanId!.isValid) {
32 4 : buffer.writeln('Parent Span ID: ${span.spanContext.parentSpanId}');
33 : } else {
34 2 : buffer.writeln('Parent Span ID: (root span)');
35 : }
36 :
37 6 : buffer.writeln('Kind: ${span.kind}');
38 6 : buffer.writeln('Status: ${span.status}');
39 :
40 2 : if (span.statusDescription != null) {
41 3 : buffer.writeln('Status Description: ${span.statusDescription}');
42 : }
43 :
44 8 : buffer.writeln('Start Time: ${span.startTime.toIso8601String()}');
45 :
46 2 : if (span.endTime != null) {
47 8 : buffer.writeln('End Time: ${span.endTime!.toIso8601String()}');
48 6 : final duration = span.endTime!.difference(span.startTime);
49 2 : buffer.writeln(
50 6 : 'Duration: ${duration.inMicroseconds}μs (${duration.inMilliseconds}ms)',
51 : );
52 : } else {
53 1 : buffer.writeln('End Time: (not ended)');
54 : }
55 :
56 : // Print attributes if any
57 4 : final attributes = span.attributes.toList();
58 2 : if (attributes.isNotEmpty) {
59 2 : buffer.writeln('Attributes:');
60 4 : for (final attr in attributes) {
61 8 : buffer.writeln(' ${attr.key}: ${attr.value}');
62 : }
63 : }
64 :
65 : // Print events if any
66 2 : final events = span.spanEvents;
67 2 : if (events != null && events.isNotEmpty) {
68 2 : buffer.writeln('Events:');
69 4 : for (final event in events) {
70 10 : buffer.writeln(' ${event.timestamp.toIso8601String()}: ${event.name}');
71 2 : if (event.attributes != null) {
72 3 : for (final attr in event.attributes!.toList()) {
73 4 : buffer.writeln(' ${attr.key}: ${attr.value}');
74 : }
75 : }
76 : }
77 : }
78 :
79 : // Print links if any
80 2 : final links = span.spanLinks;
81 1 : if (links != null && links.isNotEmpty) {
82 1 : buffer.writeln('Links:');
83 2 : for (final link in links) {
84 1 : buffer.writeln(
85 5 : ' -> Trace: ${link.spanContext.traceId}, Span: ${link.spanContext.spanId}',
86 : );
87 3 : for (final attr in link.attributes.toList()) {
88 4 : buffer.writeln(' ${attr.key}: ${attr.value}');
89 : }
90 : }
91 : }
92 :
93 2 : buffer.writeln('==========================');
94 2 : print(buffer);
95 : }
96 :
97 2 : @override
98 : Future<void> forceFlush() async {
99 : // ConsoleExporter writes immediately, so nothing to flush
100 : }
101 :
102 3 : @override
103 : Future<void> shutdown() async {
104 : // ConsoleExporter has no resources to clean up
105 : }
106 : }
|