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 : // ignore: invalid_use_of_visible_for_testing_member
58 4 : final attributes = span.attributes.toList();
59 2 : if (attributes.isNotEmpty) {
60 2 : buffer.writeln('Attributes:');
61 4 : for (final attr in attributes) {
62 8 : buffer.writeln(' ${attr.key}: ${attr.value}');
63 : }
64 : }
65 :
66 : // Print events if any
67 2 : final events = span.spanEvents;
68 2 : if (events != null && events.isNotEmpty) {
69 2 : buffer.writeln('Events:');
70 4 : for (final event in events) {
71 10 : buffer.writeln(' ${event.timestamp.toIso8601String()}: ${event.name}');
72 2 : if (event.attributes != null) {
73 3 : for (final attr in event.attributes!.toList()) {
74 4 : buffer.writeln(' ${attr.key}: ${attr.value}');
75 : }
76 : }
77 : }
78 : }
79 :
80 : // Print links if any
81 2 : final links = span.spanLinks;
82 1 : if (links != null && links.isNotEmpty) {
83 1 : buffer.writeln('Links:');
84 2 : for (final link in links) {
85 1 : buffer.writeln(
86 5 : ' -> Trace: ${link.spanContext.traceId}, Span: ${link.spanContext.spanId}',
87 : );
88 3 : for (final attr in link.attributes.toList()) {
89 4 : buffer.writeln(' ${attr.key}: ${attr.value}');
90 : }
91 : }
92 : }
93 :
94 2 : buffer.writeln('==========================');
95 2 : print(buffer);
96 : }
97 :
98 2 : @override
99 : Future<void> forceFlush() async {
100 : // ConsoleExporter writes immediately, so nothing to flush
101 : }
102 :
103 2 : @override
104 : Future<void> shutdown() async {
105 : // ConsoleExporter has no resources to clean up
106 : }
107 : }
|