29
29
NoOpLogger ,
30
30
SynchronousMultiLogRecordProcessor ,
31
31
)
32
+ from opentelemetry ._logs import (
33
+ SeverityNumber ,
34
+ )
32
35
from opentelemetry .sdk .environment_variables import OTEL_SDK_DISABLED
33
36
from opentelemetry .sdk .resources import Resource
34
37
from opentelemetry .sdk .util .instrumentation import InstrumentationScope
@@ -74,6 +77,8 @@ def test_get_logger(self):
74
77
self .assertEqual (
75
78
logger ._instrumentation_scope .attributes , {"key" : "value" }
76
79
)
80
+ self .assertEqual (logger ._min_severity_level , SeverityNumber .UNSPECIFIED )
81
+ self .assertFalse (logger ._trace_based )
77
82
78
83
@patch .dict ("os.environ" , {OTEL_SDK_DISABLED : "true" })
79
84
def test_get_logger_with_sdk_disabled (self ):
@@ -83,7 +88,7 @@ def test_get_logger_with_sdk_disabled(self):
83
88
84
89
@patch .object (Resource , "create" )
85
90
def test_logger_provider_init (self , resource_patch ):
86
- logger_provider = LoggerProvider ()
91
+ logger_provider = LoggerProvider (min_severity_level = SeverityNumber . DEBUG4 , trace_based = True )
87
92
resource_patch .assert_called_once ()
88
93
self .assertIsNotNone (logger_provider ._resource )
89
94
self .assertTrue (
@@ -92,6 +97,8 @@ def test_logger_provider_init(self, resource_patch):
92
97
SynchronousMultiLogRecordProcessor ,
93
98
)
94
99
)
100
+ self .assertEqual (logger_provider ._min_severity_level , SeverityNumber .DEBUG4 )
101
+ self .assertTrue (logger_provider ._trace_based )
95
102
self .assertIsNotNone (logger_provider ._at_exit_handler )
96
103
97
104
@@ -171,3 +178,193 @@ def test_can_emit_with_keywords_arguments(self):
171
178
self .assertEqual (log_record .attributes , {"some" : "attributes" })
172
179
self .assertEqual (log_record .event_name , "event_name" )
173
180
self .assertEqual (log_record .resource , logger .resource )
181
+
182
+ def test_emit_logrecord_with_min_severity_filtering (self ):
183
+ """Test that logs below minimum severity are filtered out"""
184
+ logger , log_record_processor_mock = self ._get_logger ()
185
+ logger ._min_severity_level = SeverityNumber .DEBUG4
186
+
187
+ log_record_info = LogRecord (
188
+ observed_timestamp = 0 ,
189
+ body = "info log line" ,
190
+ severity_number = SeverityNumber .DEBUG ,
191
+ severity_text = "DEBUG" ,
192
+ )
193
+
194
+ logger .emit (log_record_info )
195
+ log_record_processor_mock .on_emit .assert_not_called ()
196
+
197
+ log_record_processor_mock .reset_mock ()
198
+
199
+ log_record_error = LogRecord (
200
+ observed_timestamp = 0 ,
201
+ body = "error log line" ,
202
+ severity_number = SeverityNumber .ERROR ,
203
+ severity_text = "ERROR" ,
204
+ )
205
+
206
+ logger .emit (log_record_error )
207
+
208
+ log_record_processor_mock .on_emit .assert_called_once ()
209
+ log_data = log_record_processor_mock .on_emit .call_args .args [0 ]
210
+ self .assertTrue (isinstance (log_data .log_record , LogRecord ))
211
+ self .assertEqual (log_data .log_record .severity_number , SeverityNumber .ERROR )
212
+
213
+ def test_emit_logrecord_with_min_severity_unspecified (self ):
214
+ """Test that when min severity is UNSPECIFIED, all logs are emitted"""
215
+ logger , log_record_processor_mock = self ._get_logger ()
216
+ log_record = LogRecord (
217
+ observed_timestamp = 0 ,
218
+ body = "debug log line" ,
219
+ severity_number = SeverityNumber .DEBUG ,
220
+ severity_text = "DEBUG" ,
221
+ )
222
+ logger .emit (log_record )
223
+ log_record_processor_mock .on_emit .assert_called_once ()
224
+
225
+ def test_emit_logrecord_with_trace_based_filtering (self ):
226
+ """Test that logs are filtered based on trace sampling state"""
227
+ logger , log_record_processor_mock = self ._get_logger ()
228
+ logger ._trace_based = True
229
+
230
+ mock_span_context = Mock ()
231
+ mock_span_context .is_valid = True
232
+ mock_span_context .trace_flags .sampled = False
233
+
234
+ mock_span = Mock ()
235
+ mock_span .get_span_context .return_value = mock_span_context
236
+
237
+ mock_context = Mock ()
238
+
239
+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
240
+ log_record = LogRecord (
241
+ observed_timestamp = 0 ,
242
+ body = "should be dropped" ,
243
+ severity_number = SeverityNumber .INFO ,
244
+ severity_text = "INFO" ,
245
+ context = mock_context ,
246
+ )
247
+
248
+ logger .emit (log_record )
249
+ log_record_processor_mock .on_emit .assert_not_called ()
250
+
251
+ log_record_processor_mock .reset_mock ()
252
+
253
+ mock_span_context = Mock ()
254
+ mock_span_context .is_valid = True
255
+ mock_span_context .trace_flags .sampled = True
256
+
257
+ mock_span = Mock ()
258
+ mock_span .get_span_context .return_value = mock_span_context
259
+
260
+ def test_emit_logrecord_trace_filtering_disabled (self ):
261
+ """Test that when trace-based filtering is disabled, all logs are emitted"""
262
+ logger , log_record_processor_mock = self ._get_logger ()
263
+
264
+ mock_span_context = Mock ()
265
+ mock_span_context .is_valid = False
266
+ mock_span_context .trace_flags .sampled = False
267
+
268
+ mock_span = Mock ()
269
+ mock_span .get_span_context .return_value = mock_span_context
270
+
271
+ mock_context = Mock ()
272
+
273
+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
274
+ log_record = LogRecord (
275
+ observed_timestamp = 0 ,
276
+ body = "should be emitted when filtering disabled" ,
277
+ severity_number = SeverityNumber .INFO ,
278
+ severity_text = "INFO" ,
279
+ context = mock_context ,
280
+ )
281
+
282
+ logger .emit (log_record )
283
+ log_record_processor_mock .on_emit .assert_called_once ()
284
+
285
+ def test_emit_logrecord_trace_filtering_edge_cases (self ):
286
+ """Test edge cases for trace-based filtering"""
287
+ logger , log_record_processor_mock = self ._get_logger ()
288
+ logger ._trace_based = True
289
+
290
+ mock_span_context = Mock ()
291
+ mock_span_context .is_valid = False
292
+ mock_span_context .trace_flags .sampled = True
293
+
294
+ mock_span = Mock ()
295
+ mock_span .get_span_context .return_value = mock_span_context
296
+
297
+ mock_context = Mock ()
298
+
299
+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
300
+ log_record = LogRecord (
301
+ observed_timestamp = 0 ,
302
+ body = "invalid but sampled" ,
303
+ severity_number = SeverityNumber .INFO ,
304
+ severity_text = "INFO" ,
305
+ context = mock_context ,
306
+ )
307
+
308
+ logger .emit (log_record )
309
+ log_record_processor_mock .on_emit .assert_called_once ()
310
+
311
+ log_record_processor_mock .reset_mock ()
312
+
313
+ mock_span_context = Mock ()
314
+ mock_span_context .is_valid = True
315
+ mock_span_context .trace_flags .sampled = False
316
+
317
+ mock_span = Mock ()
318
+ mock_span .get_span_context .return_value = mock_span_context
319
+
320
+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
321
+ log_record = LogRecord (
322
+ observed_timestamp = 0 ,
323
+ body = "valid but not sampled" ,
324
+ severity_number = SeverityNumber .INFO ,
325
+ severity_text = "INFO" ,
326
+ context = mock_context ,
327
+ )
328
+
329
+ logger .emit (log_record )
330
+ log_record_processor_mock .on_emit .assert_not_called ()
331
+
332
+ def test_emit_both_min_severity_and_trace_based_filtering (self ):
333
+ """Test that both min severity and trace-based filtering work together"""
334
+ logger , log_record_processor_mock = self ._get_logger ()
335
+ logger ._min_severity_level = SeverityNumber .WARN
336
+ logger ._trace_based = True
337
+
338
+ mock_span_context = Mock ()
339
+ mock_span_context .is_valid = True
340
+ mock_span_context .trace_flags .sampled = True
341
+
342
+ mock_span = Mock ()
343
+ mock_span .get_span_context .return_value = mock_span_context
344
+
345
+ mock_context = Mock ()
346
+
347
+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
348
+ log_record_info = LogRecord (
349
+ observed_timestamp = 0 ,
350
+ body = "info log line" ,
351
+ severity_number = SeverityNumber .INFO ,
352
+ severity_text = "INFO" ,
353
+ context = mock_context ,
354
+ )
355
+
356
+ logger .emit (log_record_info )
357
+ log_record_processor_mock .on_emit .assert_not_called ()
358
+
359
+ log_record_processor_mock .reset_mock ()
360
+
361
+ log_record_error = LogRecord (
362
+ observed_timestamp = 0 ,
363
+ body = "error log line" ,
364
+ severity_number = SeverityNumber .ERROR ,
365
+ severity_text = "ERROR" ,
366
+ context = mock_context ,
367
+ )
368
+
369
+ logger .emit (log_record_error )
370
+ log_record_processor_mock .on_emit .assert_called_once ()
0 commit comments