LCOV - code coverage report
Current view: top level - lib/src/trace - span.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.6 % 138 136
Test Date: 2026-07-11 13:35:19 Functions: - 0 0

            Line data    Source code
       1              : // Copyright The OpenTelemetry Authors
       2              : // SPDX-License-Identifier: Apache-2.0
       3              : 
       4              : library;
       5              : 
       6              : import 'package:dartastic_opentelemetry_api/dartastic_opentelemetry_api.dart';
       7              : import 'package:meta/meta.dart';
       8              : 
       9              : import '../resource/resource.dart';
      10              : import 'tracer.dart';
      11              : 
      12              : part 'span_create.dart';
      13              : 
      14              : /// SDK implementation of the APISpan interface.
      15              : ///
      16              : /// A Span represents a single operation within a trace. Spans can be nested
      17              : /// to form a trace tree. Each trace contains a root span, which typically
      18              : /// describes the entire operation and, optionally, one or more sub-spans
      19              : /// for its sub-operations.
      20              : ///
      21              : /// This implementation delegates most functionality to the API Span implementation
      22              : /// while adding SDK-specific behaviors like span processor notification.
      23              : ///
      24              : /// Note: Per [OTEP 0265](https://opentelemetry.io/docs/specs/semconv/general/events/),
      25              : /// span events are being deprecated and will be replaced by the Logging API in future versions.
      26              : ///
      27              : /// More information:
      28              : /// https://opentelemetry.io/docs/specs/otel/trace/sdk/
      29              : class Span implements APISpan {
      30              :   final APISpan _delegate;
      31              :   final Tracer _sdkTracer;
      32              : 
      33              :   /// Private constructor for creating Span instances.
      34              :   ///
      35              :   /// @param delegate The API Span implementation to delegate to
      36              :   /// @param sdkTracer The SDK Tracer that created this Span
      37           48 :   Span._(APISpan delegate, Tracer sdkTracer)
      38              :       : _delegate = delegate,
      39              :         _sdkTracer = sdkTracer {
      40           48 :     if (OTelLog.isDebug()) {
      41          144 :       OTelLog.debug('SDKSpan: Created new span with name ${delegate.name}');
      42              :     }
      43              :   }
      44              : 
      45              :   /// Gets the resource associated with this span's tracer.
      46              :   ///
      47              :   /// @return The resource associated with this span
      48          111 :   Resource? get resource => _sdkTracer.resource;
      49              : 
      50           42 :   @override
      51              :   void end({DateTime? endTime, SpanStatusCode? spanStatus}) {
      52           42 :     if (OTelLog.isDebug()) {
      53           42 :       OTelLog.debug(
      54          168 :         'SDKSpan: Starting to end span ${spanContext.spanId} with name $name',
      55              :       );
      56              :     }
      57              : 
      58              :     if (spanStatus != null) {
      59            1 :       setStatus(spanStatus);
      60              :     }
      61              : 
      62              :     try {
      63           42 :       if (OTelLog.isDebug()) {
      64          126 :         OTelLog.debug('SDKSpan: Calling delegate.end() for span $name');
      65              :       }
      66           84 :       _delegate.end(endTime: endTime, spanStatus: spanStatus);
      67           42 :       if (OTelLog.isDebug()) {
      68          126 :         OTelLog.debug('SDKSpan: Delegate.end() completed for span $name');
      69              :       }
      70              : 
      71              :       // Notify span processors that this span has ended
      72           84 :       final provider = _sdkTracer.provider;
      73           42 :       if (OTelLog.isDebug()) {
      74           42 :         OTelLog.debug(
      75          126 :           'SDKSpan: Notifying ${provider.spanProcessors.length} span processors',
      76              :         );
      77              :       }
      78           82 :       for (final processor in provider.spanProcessors) {
      79              :         try {
      80           40 :           if (OTelLog.isDebug()) {
      81           40 :             OTelLog.debug(
      82           80 :               'SDKSpan: Calling onEnd for processor ${processor.runtimeType}',
      83              :             );
      84              :           }
      85           40 :           processor.onEnd(this);
      86           40 :           if (OTelLog.isDebug()) {
      87           40 :             OTelLog.debug(
      88           80 :               'SDKSpan: Successfully called onEnd for processor ${processor.runtimeType}',
      89              :             );
      90              :           }
      91              :         } catch (e, stackTrace) {
      92            1 :           if (OTelLog.isError()) {
      93            1 :             OTelLog.error(
      94            2 :               'SDKSpan: Error calling onEnd for processor ${processor.runtimeType}: $e',
      95              :             );
      96            2 :             OTelLog.error('Stack trace: $stackTrace');
      97              :           }
      98              :         }
      99              :       }
     100              :     } catch (e, stackTrace) {
     101            0 :       if (OTelLog.isError()) OTelLog.error('SDKSpan: Error during end(): $e');
     102            0 :       if (OTelLog.isError()) OTelLog.error('Stack trace: $stackTrace');
     103              :       rethrow;
     104              :     }
     105              :   }
     106              : 
     107            1 :   @override
     108              :   set attributes(Attributes newAttributes) =>
     109            2 :       _delegate.attributes = newAttributes;
     110              : 
     111            4 :   @override
     112              :   void addAttributes(Attributes attributes) =>
     113            8 :       _delegate.addAttributes(attributes);
     114              : 
     115            3 :   @override
     116            6 :   void addEvent(SpanEvent spanEvent) => _delegate.addEvent(spanEvent);
     117              : 
     118            6 :   @override
     119              :   void addEventNow(String name, [Attributes? attributes]) =>
     120           12 :       _delegate.addEventNow(name, attributes);
     121              : 
     122            1 :   @override
     123              :   void addEvents(Map<String, Attributes?> spanEvents) =>
     124            2 :       _delegate.addEvents(spanEvents);
     125              : 
     126            4 :   @override
     127              :   void addLink(SpanContext spanContext, [Attributes? attributes]) =>
     128            8 :       _delegate.addLink(spanContext, attributes);
     129              : 
     130            2 :   @override
     131            4 :   void addSpanLink(SpanLink spanLink) => _delegate.addSpanLink(spanLink);
     132              : 
     133           44 :   @override
     134           88 :   DateTime? get endTime => _delegate.endTime;
     135              : 
     136            9 :   @override
     137           18 :   bool get isEnded => _delegate.isEnded;
     138              : 
     139            7 :   @override
     140           14 :   bool get isRecording => _delegate.isRecording;
     141              : 
     142           39 :   @override
     143           78 :   SpanKind get kind => _delegate.kind;
     144              : 
     145           46 :   @override
     146           92 :   String get name => _delegate.name;
     147              : 
     148           38 :   @override
     149           76 :   APISpan? get parentSpan => _delegate.parentSpan;
     150              : 
     151            8 :   @override
     152              :   void recordException(
     153              :     Object exception, {
     154              :     StackTrace? stackTrace,
     155              :     Attributes? attributes,
     156              :     bool? escaped,
     157              :   }) =>
     158           16 :       _delegate.recordException(
     159              :         exception,
     160              :         stackTrace: stackTrace,
     161              :         attributes: attributes,
     162              :         escaped: escaped,
     163              :       );
     164              : 
     165            3 :   @override
     166              :   void setBoolAttribute(String name, bool value) =>
     167            6 :       _delegate.setBoolAttribute(name, value);
     168              : 
     169            2 :   @override
     170              :   void setBoolListAttribute(String name, List<bool> value) =>
     171            4 :       _delegate.setBoolListAttribute(name, value);
     172              : 
     173            3 :   @override
     174              :   void setDoubleAttribute(String name, double value) =>
     175            6 :       _delegate.setDoubleAttribute(name, value);
     176              : 
     177            2 :   @override
     178              :   void setDoubleListAttribute(String name, List<double> value) =>
     179            4 :       _delegate.setDoubleListAttribute(name, value);
     180              : 
     181            5 :   @override
     182              :   void setIntAttribute(String name, int value) =>
     183           10 :       _delegate.setIntAttribute(name, value);
     184              : 
     185            2 :   @override
     186              :   void setIntListAttribute(String name, List<int> value) =>
     187            4 :       _delegate.setIntListAttribute(name, value);
     188              : 
     189           10 :   @override
     190              :   void setStatus(SpanStatusCode statusCode, [String? description]) {
     191           20 :     _delegate.setStatus(statusCode, description);
     192           10 :     if (OTelLog.isDebug()) {
     193           10 :       OTelLog.debug(
     194           30 :         'SDKSpan: Set status to $statusCode for span ${spanContext.spanId}',
     195              :       );
     196              :     }
     197              :   }
     198              : 
     199            5 :   @override
     200              :   void setStringAttribute<T>(String name, String value) =>
     201           10 :       _delegate.setStringAttribute<T>(name, value);
     202              : 
     203            2 :   @override
     204              :   void setStringListAttribute<T>(String name, List<String> value) =>
     205            4 :       _delegate.setStringListAttribute<T>(name, value);
     206              : 
     207            2 :   @override
     208              :   void setDateTimeAsStringAttribute(String name, DateTime value) =>
     209            4 :       _delegate.setDateTimeAsStringAttribute(name, value);
     210              : 
     211           48 :   @override
     212           96 :   SpanContext get spanContext => _delegate.spanContext;
     213              : 
     214           41 :   @override
     215           82 :   List<SpanEvent>? get spanEvents => _delegate.spanEvents;
     216              : 
     217            3 :   @override
     218            6 :   SpanId get spanId => _delegate.spanId;
     219              : 
     220           39 :   @override
     221           78 :   List<SpanLink>? get spanLinks => _delegate.spanLinks;
     222              : 
     223           39 :   @override
     224           78 :   DateTime get startTime => _delegate.startTime;
     225              : 
     226           41 :   @override
     227           82 :   SpanStatusCode get status => _delegate.status;
     228              : 
     229           41 :   @override
     230           82 :   String? get statusDescription => _delegate.statusDescription;
     231              : 
     232            2 :   @override
     233              :   void updateName(String name) {
     234            4 :     _delegate.updateName(name);
     235              : 
     236            4 :     final provider = _sdkTracer.provider;
     237            4 :     for (final processor in provider.spanProcessors) {
     238            2 :       processor.onNameUpdate(this, name);
     239              :     }
     240              :   }
     241              : 
     242           38 :   @override
     243              :   InstrumentationScope get instrumentationScope =>
     244           76 :       _delegate.instrumentationScope;
     245              : 
     246            6 :   @override
     247           12 :   SpanContext? get parentSpanContext => _delegate.parentSpanContext;
     248              : 
     249           34 :   @override
     250              :   String toString() {
     251              :     final indent = '  ';
     252           34 :     final buffer = StringBuffer()
     253           34 :       ..writeln('Span {')
     254          102 :       ..writeln('$indent name: $name,')
     255          102 :       ..writeln('$indent spanContext: $spanContext,')
     256          102 :       ..writeln('$indent kind: $kind,')
     257          112 :       ..writeln('$indent parentSpan: ${parentSpan?.spanContext ?? "none"},')
     258          102 :       ..writeln('$indent instrumentationScope: $instrumentationScope,')
     259          102 :       ..writeln('$indent startTime: $startTime,')
     260          102 :       ..writeln('$indent endTime: $endTime,')
     261          102 :       ..writeln('$indent status: $status,')
     262          102 :       ..writeln('$indent statusDescription: $statusDescription,')
     263          102 :       ..writeln('$indent attributes: $attributes,');
     264              : 
     265              :     // Span Events
     266           42 :     if (spanEvents?.isNotEmpty ?? false) {
     267           16 :       buffer.writeln('$indent spanEvents: [');
     268           24 :       for (final e in spanEvents!) {
     269           16 :         buffer.writeln('$indent$indent$e,');
     270              :       }
     271           16 :       buffer.writeln('$indent ],');
     272              :     } else {
     273           66 :       buffer.writeln('$indent spanEvents: [],');
     274              :     }
     275              : 
     276              :     // Span Links
     277           39 :     if (spanLinks?.isNotEmpty ?? false) {
     278           10 :       buffer.writeln('$indent spanLinks: [');
     279           15 :       for (final l in spanLinks!) {
     280           10 :         buffer.writeln('$indent$indent$l,');
     281              :       }
     282           10 :       buffer.writeln('$indent ]');
     283              :     } else {
     284           66 :       buffer.writeln('$indent spanLinks: []');
     285              :     }
     286              : 
     287           34 :     buffer.writeln('}');
     288           34 :     return buffer.toString();
     289              :   }
     290              : 
     291              :   /// Returns whether this span context is valid
     292              :   /// A span context is valid when it has a non-zero traceId and a non-zero spanId.
     293            9 :   @override
     294           18 :   bool get isValid => spanContext.isValid;
     295              : 
     296           40 :   @visibleForTesting
     297              :   @override
     298              :   // ignore: invalid_use_of_visible_for_testing_member
     299           80 :   Attributes get attributes => _delegate.attributes;
     300              : 
     301              :   // This check is always true because the method is part of the interface implementation
     302              :   // and the delegate is already an APISpan.
     303              :   /// Checks if this object is an instance of the specified type.
     304              :   ///
     305              :   /// This method is used for type checking and compatibility with the API Span implementation.
     306              :   /// It returns true if the specified type is APISpan or the exact runtime type of this object.
     307              :   ///
     308              :   /// @param type The type to check against
     309              :   /// @return true if this object is an instance of the specified type, false otherwise
     310            4 :   bool isInstanceOf(Type type) => type == APISpan || runtimeType == type;
     311              : }
        

Generated by: LCOV version 2.0-1