Line data Source code
1 : // Copyright The OpenTelemetry Authors
2 : // SPDX-License-Identifier: Apache-2.0
3 :
4 : import 'package:dartastic_opentelemetry_api/dartastic_opentelemetry_api.dart';
5 :
6 : import '../environment/environment_service.dart';
7 : import '../environment/otel_env.dart';
8 : import 'native_detectors.dart';
9 : import 'resource.dart';
10 : import 'web_detector.dart';
11 :
12 : // Re-export the platform-conditional native detectors so existing
13 : // imports of `package:dartastic_opentelemetry/src/resource/resource_detector.dart`
14 : // continue to find `ProcessResourceDetector` and `HostResourceDetector`.
15 : export 'native_detectors.dart'
16 : show HostResourceDetector, ProcessResourceDetector;
17 :
18 : /// Interface for resource detectors that automatically discover resource information.
19 : ///
20 : /// Resource detectors are used to automatically populate resource attributes
21 : /// based on the environment (operating system, platform, etc.).
22 : ///
23 : /// More information:
24 : /// https://opentelemetry.io/docs/specs/otel/resource/sdk/#detecting-resource-information-from-the-environment
25 : abstract class ResourceDetector {
26 : /// Detects resource information from the environment.
27 : ///
28 : /// @return A resource containing the detected attributes
29 : Future<Resource> detect();
30 : }
31 :
32 : /// Detects resource information from environment variables.
33 : ///
34 : /// This detector looks for the OTEL_RESOURCE_ATTRIBUTES environment variable
35 : /// and parses its contents into resource attributes.
36 : ///
37 : /// More information:
38 : /// https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration
39 : class EnvVarResourceDetector implements ResourceDetector {
40 : final EnvironmentService _environmentService;
41 :
42 : /// Creates a new EnvVarResourceDetector with the specified environment service.
43 : ///
44 : /// If no environment service is provided, the singleton instance will be used.
45 : ///
46 : /// @param environmentService Optional service for accessing environment variables
47 153 : EnvVarResourceDetector([EnvironmentService? environmentService])
48 153 : : _environmentService = environmentService ?? EnvironmentService.instance;
49 :
50 153 : @override
51 : Future<Resource> detect() async {
52 153 : if (OTelFactory.otelFactory == null) {
53 1 : throw StateError('OTel initialize must be called first.');
54 : }
55 :
56 : //TODO - OTEL_RESOURCE_ATTRIBUTES?
57 306 : final resourceAttrs = _environmentService.getValue(
58 : 'OTEL_RESOURCE_ATTRIBUTES',
59 : );
60 4 : if (resourceAttrs == null || resourceAttrs.isEmpty) {
61 152 : return Resource.empty;
62 : }
63 :
64 4 : final attributes = OTelEnv.parseResourceAttributesString(resourceAttrs);
65 4 : return ResourceCreate.create(
66 8 : OTelFactory.otelFactory!.attributesFromMap(attributes));
67 : }
68 : }
69 :
70 : /// Composite detector that combines multiple resource detectors.
71 : ///
72 : /// This detector runs multiple detectors and merges their results.
73 : /// This is useful for combining resource information from different sources.
74 : ///
75 : /// More information:
76 : /// https://opentelemetry.io/docs/specs/otel/resource/sdk/#resource-creation
77 : class CompositeResourceDetector implements ResourceDetector {
78 : final List<ResourceDetector> _detectors;
79 :
80 : /// Creates a new CompositeResourceDetector with the specified detectors.
81 : ///
82 : /// @param detectors The list of detectors to run
83 153 : CompositeResourceDetector(this._detectors);
84 :
85 153 : @override
86 : Future<Resource> detect() async {
87 153 : if (OTelFactory.otelFactory == null) {
88 1 : throw StateError('OTel initialize must be called first.');
89 : }
90 153 : var result = Resource.empty;
91 :
92 306 : for (final detector in _detectors) {
93 : try {
94 153 : final resource = await detector.detect();
95 153 : result = result.merge(resource);
96 : } catch (e) {
97 : // Log error but continue with other detectors
98 9 : if (OTelLog.isError()) OTelLog.error('Error in resource detector: $e');
99 : }
100 : }
101 :
102 : return result;
103 : }
104 : }
105 :
106 : /// Factory for creating platform-appropriate resource detectors.
107 : ///
108 : /// This factory creates a composite detector with the appropriate
109 : /// detectors for the current platform (web or native).
110 : class PlatformResourceDetector {
111 : /// Creates a composite detector with platform-appropriate detectors.
112 : ///
113 : /// @return A ResourceDetector that combines all appropriate detectors
114 58 : static ResourceDetector create() {
115 116 : final detectors = <ResourceDetector>[EnvVarResourceDetector()];
116 :
117 : // For non-web platforms (native)
118 : if (!const bool.fromEnvironment('dart.library.js_interop')) {
119 : try {
120 232 : detectors.addAll([ProcessResourceDetector(), HostResourceDetector()]);
121 : } catch (e) {
122 0 : if (OTelLog.isError()) {
123 0 : OTelLog.error('Error adding native detectors: $e');
124 : }
125 : }
126 : }
127 : // For web platforms
128 : else {
129 : try {
130 0 : detectors.add(WebResourceDetector());
131 : } catch (e) {
132 0 : if (OTelLog.isError()) OTelLog.error('Error adding web detector: $e');
133 : }
134 : }
135 :
136 58 : return CompositeResourceDetector(detectors);
137 : }
138 : }
|