LCOV - code coverage report
Current view: top level - lib/src/trace - tracer_provider.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 95.7 % 115 110
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:meta/meta.dart';
       7              : import '../../dartastic_opentelemetry.dart';
       8              : import 'tracer.dart';
       9              : 
      10              : part 'tracer_provider_create.dart';
      11              : 
      12              : /// SDK implementation of the APITracerProvider interface.
      13              : ///
      14              : /// The TracerProvider is the entry point to the tracing API. It is responsible
      15              : /// for creating and managing Tracers, as well as configuring the tracing
      16              : /// pipeline via SpanProcessors and Exporters.
      17              : ///
      18              : /// This implementation delegates some functionality to the API TracerProvider
      19              : /// implementation while adding SDK-specific behaviors like span processor management
      20              : /// and resource association.
      21              : ///
      22              : /// Note: Per [OTEP 0265](https://opentelemetry.io/docs/specs/semconv/general/events/),
      23              : /// span events are being deprecated and will be replaced by the Logging API in future versions.
      24              : ///
      25              : /// More information:
      26              : /// https://opentelemetry.io/docs/specs/otel/trace/sdk/
      27              : class TracerProvider implements APITracerProvider {
      28              :   /// Registry of tracers managed by this provider.
      29              :   final Map<String, Tracer> _tracers = {};
      30              : 
      31              :   /// Span processors registered with this provider.
      32              :   final List<SpanProcessor> _spanProcessors = [];
      33              : 
      34              :   /// The underlying API TracerProvider implementation.
      35              :   final APITracerProvider _delegate;
      36              : 
      37              :   /// The resource associated with this provider.
      38              :   Resource? resource;
      39              : 
      40              :   /// The default sampler to use for new tracers.
      41              :   Sampler? sampler;
      42              : 
      43              :   /// The default exception handling options applied by [Tracer.withSpan] /
      44              :   /// [Tracer.withSpanAsync] for tracers created by this provider when no
      45              :   /// per-call options are supplied.
      46              :   ///
      47              :   /// Set globally via `OTel.initialize(spanExceptionOptions: ...)`. When
      48              :   /// null, a default [SpanExceptionOptions] (record exception + set error
      49              :   /// status) is used.
      50              :   SpanExceptionOptions? spanExceptionOptions;
      51              : 
      52              :   /// Clock used for span start, end, and event timestamps. Delegates to the
      53              :   /// underlying [APITracerProvider] so the SDK and API share a single
      54              :   /// source of truth. Defaults are platform-aware (native:
      55              :   /// `SystemTimeProvider`; web: `WebTimeProvider`); override via
      56              :   /// `OTel.initialize(timeProvider: ...)` or by assigning here.
      57            1 :   @override
      58            2 :   TimeProvider get timeProvider => _delegate.timeProvider;
      59            1 :   @override
      60            2 :   set timeProvider(TimeProvider value) => _delegate.timeProvider = value;
      61              : 
      62          128 :   @override
      63          256 :   bool get isShutdown => _delegate.isShutdown;
      64              : 
      65          126 :   @override
      66              :   set isShutdown(bool value) {
      67          252 :     _delegate.isShutdown = value;
      68              :   }
      69              : 
      70              :   /// Private constructor for creating TracerProvider instances.
      71              :   ///
      72              :   /// @param delegate The API TracerProvider implementation to delegate to
      73              :   /// @param resource Optional Resource describing the entity producing telemetry
      74              :   /// @param sampler Optional default sampler for tracers created by this provider
      75          128 :   TracerProvider._({
      76              :     required APITracerProvider delegate,
      77              :     this.resource,
      78              :     Sampler? sampler,
      79              :   }) : _delegate = delegate {
      80          128 :     if (OTelLog.isDebug()) {
      81          124 :       OTelLog.debug(
      82          248 :         'TracerProvider: Created with resource: $resource, sampler: $sampler',
      83              :       );
      84          124 :       if (resource != null) {
      85            0 :         OTelLog.debug('Resource attributes:');
      86            0 :         resource!.attributes.toList().forEach((attr) {
      87            0 :           OTelLog.debug('  ${attr.key}: ${attr.value}');
      88              :         });
      89              :       }
      90              :     }
      91              :   }
      92              : 
      93          126 :   @override
      94              :   Future<bool> shutdown() async {
      95          126 :     if (OTelLog.isDebug()) {
      96          125 :       OTelLog.debug(
      97          375 :         'TracerProvider: Shutting down with ${_spanProcessors.length} processors',
      98              :       );
      99              :     }
     100          126 :     if (OTelLog.isDebug()) {
     101          125 :       OTelLog.debug(
     102          375 :         'TracerProvider: Shutting down with ${_spanProcessors.length} processors',
     103              :       );
     104              :     }
     105              : 
     106          126 :     if (!isShutdown) {
     107              :       // Shutdown all span processors
     108          252 :       for (final processor in _spanProcessors) {
     109          126 :         if (OTelLog.isDebug()) {
     110          125 :           OTelLog.debug(
     111          250 :             'TracerProvider: Shutting down processor ${processor.runtimeType}',
     112              :           );
     113              :         }
     114          126 :         if (OTelLog.isDebug()) {
     115          125 :           OTelLog.debug(
     116          250 :             'SDKTracerProvider: Shutting down processor ${processor.runtimeType}',
     117              :           );
     118              :         }
     119              :         try {
     120          126 :           await processor.shutdown();
     121          126 :           if (OTelLog.isDebug()) {
     122          125 :             OTelLog.debug(
     123          250 :               'TracerProvider: Successfully shut down processor ${processor.runtimeType}',
     124              :             );
     125              :           }
     126              :         } catch (e) {
     127            1 :           if (OTelLog.isDebug()) {
     128            1 :             OTelLog.debug(
     129            2 :               'TracerProvider: Error shutting down processor ${processor.runtimeType}: $e',
     130              :             );
     131              :           }
     132              :         }
     133              :       }
     134              : 
     135              :       // Clear cached tracers
     136          252 :       _tracers.clear();
     137          126 :       if (OTelLog.isDebug()) {
     138          125 :         OTelLog.debug('TracerProvider: Cleared cached tracers');
     139              :       }
     140              : 
     141              :       try {
     142          252 :         await _delegate.shutdown();
     143          126 :         if (OTelLog.isDebug()) {
     144          125 :           OTelLog.debug('TracerProvider: Delegate shutdown complete');
     145              :         }
     146              :       } catch (e) {
     147            0 :         if (OTelLog.isDebug()) {
     148            0 :           OTelLog.debug('TracerProvider: Error during delegate shutdown: $e');
     149              :         }
     150              :       }
     151              : 
     152          126 :       isShutdown = true;
     153          251 :       if (OTelLog.isDebug()) OTelLog.debug('TracerProvider: Shutdown complete');
     154              :     } else {
     155          157 :       if (OTelLog.isDebug()) OTelLog.debug('TracerProvider: Already shut down');
     156              :     }
     157          126 :     return isShutdown;
     158              :   }
     159              : 
     160           49 :   @override
     161              :   Tracer getTracer(
     162              :     String name, {
     163              :     String? version,
     164              :     String? schemaUrl,
     165              :     Attributes? attributes,
     166              :     Sampler? sampler,
     167              :   }) {
     168           49 :     if (OTelLog.isDebug()) {
     169           49 :       OTelLog.debug(
     170           49 :         'TracerProvider: Getting tracer with name: $name, version: $version, schemaUrl: $schemaUrl',
     171              :       );
     172              :     }
     173           49 :     if (isShutdown) {
     174            1 :       throw StateError('TracerProvider has been shut down');
     175              :     }
     176              : 
     177              :     // Ensure resource is set before creating tracer
     178           49 :     ensureResourceIsSet();
     179              : 
     180           49 :     final key = '$name:${version ?? ''}';
     181           98 :     return _tracers.putIfAbsent(
     182              :       key,
     183           98 :       () => SDKTracerCreate.create(
     184           98 :         delegate: _delegate.getTracer(
     185              :           name,
     186              :           version: version,
     187              :           schemaUrl: schemaUrl,
     188              :           attributes: attributes,
     189              :         ),
     190              :         provider: this,
     191              :         sampler: sampler,
     192              :       ) as Tracer,
     193              :     );
     194              :   }
     195              : 
     196              :   /// Adds a span processor to this provider.
     197              :   ///
     198              :   /// Span processors are notified of span lifecycle events and are responsible
     199              :   /// for additional processing of spans, such as exporting them.
     200              :   ///
     201              :   /// @param processor The span processor to add
     202          128 :   void addSpanProcessor(SpanProcessor processor) {
     203          128 :     if (isShutdown) {
     204            1 :       throw StateError('TracerProvider has been shut down');
     205              :     }
     206          128 :     if (OTelLog.isDebug()) {
     207          125 :       OTelLog.debug(
     208          250 :         'SDKTracerProvider: Adding span processor of type ${processor.runtimeType}',
     209              :       );
     210              :     }
     211          256 :     _spanProcessors.add(processor);
     212              :   }
     213              : 
     214              :   /// Gets all registered span processors.
     215              :   ///
     216              :   /// @return An unmodifiable list of all span processors
     217          150 :   List<SpanProcessor> get spanProcessors => List.unmodifiable(_spanProcessors);
     218              : 
     219              :   /// Ensures the resource for this provider is properly set.
     220              :   ///
     221              :   /// If no resource has been set, the default resource will be used.
     222           49 :   void ensureResourceIsSet() {
     223           49 :     if (resource == null) {
     224            3 :       resource = OTel.defaultResource;
     225            3 :       if (OTelLog.isDebug()) {
     226            3 :         OTelLog.debug('TracerProvider: Setting resource from default');
     227            3 :         if (resource != null) {
     228            2 :           OTelLog.debug('Resource attributes:');
     229           10 :           resource!.attributes.toList().forEach((attr) {
     230            8 :             if (attr.key == 'tenant_id' || attr.key == 'service.name') {
     231            8 :               OTelLog.debug('  ${attr.key}: ${attr.value}');
     232              :             }
     233              :           });
     234              :         }
     235              :       }
     236              :     }
     237              :   }
     238              : 
     239            1 :   @override
     240            2 :   String get endpoint => _delegate.endpoint;
     241              : 
     242            1 :   @override
     243              :   set endpoint(String value) {
     244            2 :     _delegate.endpoint = value;
     245              :   }
     246              : 
     247            1 :   @override
     248            2 :   String get serviceName => _delegate.serviceName;
     249              : 
     250            1 :   @override
     251              :   set serviceName(String value) {
     252            2 :     _delegate.serviceName = value;
     253              :   }
     254              : 
     255            1 :   @override
     256            2 :   String? get serviceVersion => _delegate.serviceVersion;
     257              : 
     258            1 :   @override
     259              :   set serviceVersion(String? value) {
     260            2 :     _delegate.serviceVersion = value;
     261              :   }
     262              : 
     263            1 :   @override
     264            2 :   bool get enabled => _delegate.enabled;
     265              : 
     266            1 :   @override
     267              :   set enabled(bool value) {
     268            2 :     _delegate.enabled = value;
     269              :   }
     270              : 
     271              :   /// Forces all span processors to flush any queued spans.
     272              :   ///
     273              :   /// This method is useful for ensuring that all spans are exported
     274              :   /// before the application terminates or when immediate visibility
     275              :   /// of spans is required.
     276              :   ///
     277              :   /// @return A Future that completes when all processors have been flushed
     278          126 :   Future<void> forceFlush() async {
     279          126 :     if (OTelLog.isDebug()) {
     280          125 :       OTelLog.debug(
     281          375 :         'TracerProvider: Force flushing ${_spanProcessors.length} processors',
     282              :       );
     283              :     }
     284              : 
     285          126 :     if (isShutdown) {
     286           79 :       if (OTelLog.isDebug()) {
     287           78 :         OTelLog.debug(
     288              :           'TracerProvider: Cannot force flush - provider is shut down',
     289              :         );
     290              :       }
     291              :       return;
     292              :     }
     293              : 
     294          242 :     for (var processor in _spanProcessors) {
     295              :       try {
     296          121 :         if (OTelLog.isDebug()) {
     297          120 :           OTelLog.debug(
     298          240 :             'TracerProvider: Flushing processor ${processor.runtimeType}',
     299              :           );
     300              :         }
     301          121 :         await processor.forceFlush();
     302          121 :         if (OTelLog.isDebug()) {
     303          120 :           OTelLog.debug(
     304          240 :             'TracerProvider: Successfully flushed processor ${processor.runtimeType}',
     305              :           );
     306              :         }
     307              :       } catch (e) {
     308            1 :         if (OTelLog.isDebug()) {
     309            1 :           OTelLog.debug(
     310            2 :             'TracerProvider: Error flushing processor ${processor.runtimeType}: $e',
     311              :           );
     312              :         }
     313              :       }
     314              :     }
     315              : 
     316          121 :     if (OTelLog.isDebug()) {
     317          120 :       OTelLog.debug('TracerProvider: Force flush complete');
     318              :     }
     319              :   }
     320              : }
        

Generated by: LCOV version 2.0-1