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

Generated by: LCOV version 2.0-1