2929 NoOpLogger ,
3030 SynchronousMultiLogRecordProcessor ,
3131)
32+ from opentelemetry ._logs import (
33+ SeverityNumber ,
34+ )
3235from opentelemetry .sdk .environment_variables import OTEL_SDK_DISABLED
3336from opentelemetry .sdk .resources import Resource
3437from opentelemetry .sdk .util .instrumentation import InstrumentationScope
@@ -74,6 +77,8 @@ def test_get_logger(self):
7477 self .assertEqual (
7578 logger ._instrumentation_scope .attributes , {"key" : "value" }
7679 )
80+ self .assertEqual (logger ._min_severity_level , SeverityNumber .UNSPECIFIED )
81+ self .assertFalse (logger ._trace_based )
7782
7883 @patch .dict ("os.environ" , {OTEL_SDK_DISABLED : "true" })
7984 def test_get_logger_with_sdk_disabled (self ):
@@ -83,7 +88,7 @@ def test_get_logger_with_sdk_disabled(self):
8388
8489 @patch .object (Resource , "create" )
8590 def test_logger_provider_init (self , resource_patch ):
86- logger_provider = LoggerProvider ()
91+ logger_provider = LoggerProvider (min_severity_level = SeverityNumber . DEBUG4 , trace_based = True )
8792 resource_patch .assert_called_once ()
8893 self .assertIsNotNone (logger_provider ._resource )
8994 self .assertTrue (
@@ -92,6 +97,8 @@ def test_logger_provider_init(self, resource_patch):
9297 SynchronousMultiLogRecordProcessor ,
9398 )
9499 )
100+ self .assertEqual (logger_provider ._min_severity_level , SeverityNumber .DEBUG4 )
101+ self .assertTrue (logger_provider ._trace_based )
95102 self .assertIsNotNone (logger_provider ._at_exit_handler )
96103
97104
@@ -171,3 +178,193 @@ def test_can_emit_with_keywords_arguments(self):
171178 self .assertEqual (log_record .attributes , {"some" : "attributes" })
172179 self .assertEqual (log_record .event_name , "event_name" )
173180 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