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 get enabled {
64 : // Check if provider is enabled
65 32 : if (!_provider.enabled || _provider.isShutdown) {
66 : return false;
67 : }
68 :
69 : // Check if any processors are registered
70 24 : if (_provider.logRecordProcessors.isEmpty) {
71 : return false;
72 : }
73 :
74 : // Check if all processors return false for enabled
75 24 : final allDisabled = _provider.logRecordProcessors.every(
76 16 : (processor) => !processor.enabled(
77 8 : instrumentationScope: OTel.instrumentationScope(
78 8 : name: name,
79 8 : version: version ?? '1.0.0',
80 8 : schemaUrl: schemaUrl,
81 8 : attributes: attributes,
82 : ),
83 : ),
84 : );
85 :
86 : return !allDisabled;
87 : }
88 :
89 8 : @override
90 : void emit({
91 : DateTime? timeStamp,
92 : DateTime? observedTimestamp,
93 : Context? context,
94 : Severity? severityNumber,
95 : String? severityText,
96 : dynamic body,
97 : Attributes? attributes,
98 : String? eventName,
99 : }) {
100 8 : if (!enabled) {
101 1 : if (OTelLog.isDebug()) {
102 1 : OTelLog.debug('OTelLogger: emit called but logger is disabled');
103 : }
104 : return;
105 : }
106 :
107 : // Convert DateTime to nanoseconds since Unix epoch (Int64)
108 : final timestampNanos = timeStamp != null
109 4 : ? Int64(timeStamp.microsecondsSinceEpoch) * Int64(1000)
110 : : null;
111 :
112 : // Set observed timestamp to now if not provided
113 : final observedNanos = observedTimestamp != null
114 4 : ? Int64(observedTimestamp.microsecondsSinceEpoch) * Int64(1000)
115 40 : : Int64(DateTime.now().microsecondsSinceEpoch) * Int64(1000);
116 :
117 : // Use current context if not provided
118 8 : final effectiveContext = context ?? Context.current;
119 :
120 : // Create the instrumentation scope
121 8 : final instrumentationScope = OTel.instrumentationScope(
122 8 : name: name,
123 8 : version: version ?? '1.0.0',
124 8 : schemaUrl: schemaUrl,
125 8 : attributes: this.attributes,
126 : );
127 :
128 : // Create the log record
129 8 : final logRecord = SDKLogRecord(
130 : instrumentationScope: instrumentationScope,
131 16 : resource: _provider.resource,
132 : timestamp: timestampNanos,
133 : observedTimestamp: observedNanos,
134 : context: effectiveContext,
135 : severityNumber: severityNumber,
136 : severityText: severityText,
137 : body: body,
138 : attributes: attributes,
139 : eventName: eventName,
140 : );
141 :
142 8 : if (OTelLog.isDebug()) {
143 16 : OTelLog.debug('OTelLogger: Emitting log record: $logRecord');
144 : }
145 :
146 : // Notify all processors
147 24 : for (final processor in _provider.logRecordProcessors) {
148 : try {
149 8 : processor.onEmit(logRecord, effectiveContext);
150 : } catch (e) {
151 1 : if (OTelLog.isError()) {
152 1 : OTelLog.error(
153 2 : 'OTelLogger: Error in processor ${processor.runtimeType}: $e');
154 : }
155 : }
156 : }
157 : }
158 :
159 : /// Emits a log record with TRACE severity.
160 : ///
161 : /// @param body The log message body
162 : /// @param attributes Optional attributes
163 : /// @param eventName Optional event name
164 1 : void trace(dynamic body, {Attributes? attributes, String? eventName}) {
165 1 : emit(
166 : severityNumber: Severity.TRACE,
167 : severityText: 'TRACE',
168 : body: body,
169 : attributes: attributes,
170 : eventName: eventName,
171 : );
172 : }
173 :
174 : /// Emits a log record with DEBUG severity.
175 : ///
176 : /// @param body The log message body
177 : /// @param attributes Optional attributes
178 : /// @param eventName Optional event name
179 1 : void debug(dynamic body, {Attributes? attributes, String? eventName}) {
180 1 : emit(
181 : severityNumber: Severity.DEBUG,
182 : severityText: 'DEBUG',
183 : body: body,
184 : attributes: attributes,
185 : eventName: eventName,
186 : );
187 : }
188 :
189 : /// Emits a log record with INFO severity.
190 : ///
191 : /// @param body The log message body
192 : /// @param attributes Optional attributes
193 : /// @param eventName Optional event name
194 2 : void info(dynamic body, {Attributes? attributes, String? eventName}) {
195 2 : emit(
196 : severityNumber: Severity.INFO,
197 : severityText: 'INFO',
198 : body: body,
199 : attributes: attributes,
200 : eventName: eventName,
201 : );
202 : }
203 :
204 : /// Emits a log record with WARN severity.
205 : ///
206 : /// @param body The log message body
207 : /// @param attributes Optional attributes
208 : /// @param eventName Optional event name
209 1 : void warn(dynamic body, {Attributes? attributes, String? eventName}) {
210 1 : emit(
211 : severityNumber: Severity.WARN,
212 : severityText: 'WARN',
213 : body: body,
214 : attributes: attributes,
215 : eventName: eventName,
216 : );
217 : }
218 :
219 : /// Emits a log record with ERROR severity.
220 : ///
221 : /// @param body The log message body
222 : /// @param attributes Optional attributes
223 : /// @param eventName Optional event name
224 1 : void error(dynamic body, {Attributes? attributes, String? eventName}) {
225 1 : emit(
226 : severityNumber: Severity.ERROR,
227 : severityText: 'ERROR',
228 : body: body,
229 : attributes: attributes,
230 : eventName: eventName,
231 : );
232 : }
233 :
234 : /// Emits a log record with FATAL severity.
235 : ///
236 : /// @param body The log message body
237 : /// @param attributes Optional attributes
238 : /// @param eventName Optional event name
239 1 : void fatal(dynamic body, {Attributes? attributes, String? eventName}) {
240 1 : emit(
241 : severityNumber: Severity.FATAL,
242 : severityText: 'FATAL',
243 : body: body,
244 : attributes: attributes,
245 : eventName: eventName,
246 : );
247 : }
248 : }
|