Line data Source code
1 : // Copyright The OpenTelemetry Authors
2 : // SPDX-License-Identifier: Apache-2.0
3 :
4 : library;
5 :
6 : import 'package:fixnum/fixnum.dart';
7 : import 'package:meta/meta.dart';
8 :
9 : import '../../dartastic_opentelemetry.dart';
10 :
11 : part 'logger_create.dart';
12 :
13 : /// SDK implementation of the APILogger interface.
14 : ///
15 : /// The OTelLogger is responsible for emitting log records. It holds a reference
16 : /// to the LoggerProvider to access resource, processors, and other configuration.
17 : ///
18 : /// This implementation delegates some functionality to the API OTelLogger
19 : /// implementation while adding SDK-specific behaviors like processor notification.
20 : ///
21 : /// More information:
22 : /// https://opentelemetry.io/docs/specs/otel/logs/sdk/#logger
23 : class OTelLogger implements APILogger {
24 : /// The underlying API OTelLogger implementation.
25 : final APILogger _delegate;
26 :
27 : /// The LoggerProvider that created this logger.
28 : final LoggerProvider _provider;
29 :
30 : /// Private constructor for creating OTelLogger instances.
31 : ///
32 : /// @param delegate The API OTelLogger implementation to delegate to
33 : /// @param provider The LoggerProvider that created this logger
34 9 : OTelLogger._({
35 : required APILogger delegate,
36 : required LoggerProvider provider,
37 : }) : _delegate = delegate,
38 : _provider = provider {
39 9 : if (OTelLog.isDebug()) {
40 27 : OTelLog.debug('OTelLogger: Created with name: ${delegate.name}');
41 : }
42 : }
43 :
44 : /// Gets the LoggerProvider that created this logger.
45 8 : LoggerProvider get provider => _provider;
46 :
47 : /// Gets the resource associated with this logger.
48 3 : Resource? get resource => _provider.resource;
49 :
50 8 : @override
51 16 : String get name => _delegate.name;
52 :
53 8 : @override
54 16 : String? get version => _delegate.version;
55 :
56 8 : @override
57 16 : String? get schemaUrl => _delegate.schemaUrl;
58 :
59 8 : @override
60 16 : Attributes? get attributes => _delegate.attributes;
61 :
62 8 : @override
63 : bool isEnabled(
64 : {Context? context, Severity? severityNumber, String? eventName}) {
65 : // Check if provider is enabled
66 32 : if (!_provider.enabled || _provider.isShutdown) {
67 : return false;
68 : }
69 :
70 : // Check if any processors are registered
71 24 : if (_provider.logRecordProcessors.isEmpty) {
72 : return false;
73 : }
74 :
75 : // Check if all processors return false for enabled
76 24 : final allDisabled = _provider.logRecordProcessors.every(
77 16 : (processor) => !processor.enabled(
78 8 : instrumentationScope: OTel.instrumentationScope(
79 8 : name: name,
80 8 : version: version ?? '1.0.0',
81 8 : schemaUrl: schemaUrl,
82 8 : attributes: attributes,
83 : ),
84 : ),
85 : );
86 :
87 : return !allDisabled;
88 : }
89 :
90 8 : @override
91 : void emit({
92 : DateTime? timeStamp,
93 : DateTime? observedTimestamp,
94 : Context? context,
95 : Severity? severityNumber,
96 : String? severityText,
97 : dynamic body,
98 : Attributes? attributes,
99 : String? eventName,
100 : }) {
101 8 : if (!isEnabled()) {
102 1 : if (OTelLog.isDebug()) {
103 1 : OTelLog.debug('OTelLogger: emit called but logger is disabled');
104 : }
105 : return;
106 : }
107 :
108 : // Convert DateTime to nanoseconds since Unix epoch (Int64)
109 : final timestampNanos = timeStamp != null
110 4 : ? Int64(timeStamp.microsecondsSinceEpoch) * Int64(1000)
111 : : null;
112 :
113 : // Set observed timestamp to now if not provided
114 : final observedNanos = observedTimestamp != null
115 4 : ? Int64(observedTimestamp.microsecondsSinceEpoch) * Int64(1000)
116 40 : : Int64(DateTime.now().microsecondsSinceEpoch) * Int64(1000);
117 :
118 : // Use current context if not provided
119 8 : final effectiveContext = context ?? Context.current;
120 :
121 : // Create the instrumentation scope
122 8 : final instrumentationScope = OTel.instrumentationScope(
123 8 : name: name,
124 8 : version: version ?? '1.0.0',
125 8 : schemaUrl: schemaUrl,
126 8 : attributes: this.attributes,
127 : );
128 :
129 : // Create the log record
130 8 : final logRecord = SDKLogRecord(
131 : instrumentationScope: instrumentationScope,
132 16 : resource: _provider.resource,
133 : timestamp: timestampNanos,
134 : observedTimestamp: observedNanos,
135 : context: effectiveContext,
136 : severityNumber: severityNumber,
137 : severityText: severityText,
138 : body: body,
139 : attributes: attributes,
140 : eventName: eventName,
141 : );
142 :
143 8 : if (OTelLog.isDebug()) {
144 16 : OTelLog.debug('OTelLogger: Emitting log record: $logRecord');
145 : }
146 :
147 : // Notify all processors
148 24 : for (final processor in _provider.logRecordProcessors) {
149 : try {
150 8 : processor.onEmit(logRecord, effectiveContext);
151 : } catch (e) {
152 1 : if (OTelLog.isError()) {
153 1 : OTelLog.error(
154 2 : 'OTelLogger: Error in processor ${processor.runtimeType}: $e');
155 : }
156 : }
157 : }
158 : }
159 :
160 : /// Emits a log record with TRACE severity.
161 : ///
162 : /// @param body The log message body
163 : /// @param attributes Optional attributes
164 : /// @param eventName Optional event name
165 1 : void trace(dynamic body, {Attributes? attributes, String? eventName}) {
166 1 : emit(
167 : severityNumber: Severity.TRACE,
168 : severityText: 'TRACE',
169 : body: body,
170 : attributes: attributes,
171 : eventName: eventName,
172 : );
173 : }
174 :
175 : /// Emits a log record with DEBUG severity.
176 : ///
177 : /// @param body The log message body
178 : /// @param attributes Optional attributes
179 : /// @param eventName Optional event name
180 1 : void debug(dynamic body, {Attributes? attributes, String? eventName}) {
181 1 : emit(
182 : severityNumber: Severity.DEBUG,
183 : severityText: 'DEBUG',
184 : body: body,
185 : attributes: attributes,
186 : eventName: eventName,
187 : );
188 : }
189 :
190 : /// Emits a log record with INFO severity.
191 : ///
192 : /// @param body The log message body
193 : /// @param attributes Optional attributes
194 : /// @param eventName Optional event name
195 2 : void info(dynamic body, {Attributes? attributes, String? eventName}) {
196 2 : emit(
197 : severityNumber: Severity.INFO,
198 : severityText: 'INFO',
199 : body: body,
200 : attributes: attributes,
201 : eventName: eventName,
202 : );
203 : }
204 :
205 : /// Emits a log record with WARN severity.
206 : ///
207 : /// @param body The log message body
208 : /// @param attributes Optional attributes
209 : /// @param eventName Optional event name
210 1 : void warn(dynamic body, {Attributes? attributes, String? eventName}) {
211 1 : emit(
212 : severityNumber: Severity.WARN,
213 : severityText: 'WARN',
214 : body: body,
215 : attributes: attributes,
216 : eventName: eventName,
217 : );
218 : }
219 :
220 : /// Emits a log record with ERROR severity.
221 : ///
222 : /// @param body The log message body
223 : /// @param attributes Optional attributes
224 : /// @param eventName Optional event name
225 1 : void error(dynamic body, {Attributes? attributes, String? eventName}) {
226 1 : emit(
227 : severityNumber: Severity.ERROR,
228 : severityText: 'ERROR',
229 : body: body,
230 : attributes: attributes,
231 : eventName: eventName,
232 : );
233 : }
234 :
235 : /// Emits a log record with FATAL severity.
236 : ///
237 : /// @param body The log message body
238 : /// @param attributes Optional attributes
239 : /// @param eventName Optional event name
240 1 : void fatal(dynamic body, {Attributes? attributes, String? eventName}) {
241 1 : emit(
242 : severityNumber: Severity.FATAL,
243 : severityText: 'FATAL',
244 : body: body,
245 : attributes: attributes,
246 : eventName: eventName,
247 : );
248 : }
249 : }
|