LCOV - code coverage report
Current view: top level - src/trace - span.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 82.6 % 138 114
Test Date: 2025-11-15 13:23:01 Functions: - 0 0

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

Generated by: LCOV version 2.0-1