2323 NoOpLogger ,
2424 SynchronousMultiLogRecordProcessor ,
2525)
26+ from opentelemetry ._logs import (
27+ SeverityNumber ,
28+ )
2629from opentelemetry .sdk .environment_variables import OTEL_SDK_DISABLED
2730from opentelemetry .sdk .resources import Resource
2831from opentelemetry .sdk .util .instrumentation import InstrumentationScope
@@ -68,6 +71,8 @@ def test_get_logger(self):
6871 self .assertEqual (
6972 logger ._instrumentation_scope .attributes , {"key" : "value" }
7073 )
74+ self .assertEqual (logger ._min_severity_level , SeverityNumber .UNSPECIFIED )
75+ self .assertFalse (logger ._trace_based )
7176
7277 @patch .dict ("os.environ" , {OTEL_SDK_DISABLED : "true" })
7378 def test_get_logger_with_sdk_disabled (self ):
@@ -77,7 +82,7 @@ def test_get_logger_with_sdk_disabled(self):
7782
7883 @patch .object (Resource , "create" )
7984 def test_logger_provider_init (self , resource_patch ):
80- logger_provider = LoggerProvider ()
85+ logger_provider = LoggerProvider (min_severity_level = SeverityNumber . DEBUG4 , trace_based = True )
8186 resource_patch .assert_called_once ()
8287 self .assertIsNotNone (logger_provider ._resource )
8388 self .assertTrue (
@@ -86,6 +91,8 @@ def test_logger_provider_init(self, resource_patch):
8691 SynchronousMultiLogRecordProcessor ,
8792 )
8893 )
94+ self .assertEqual (logger_provider ._min_severity_level , SeverityNumber .DEBUG4 )
95+ self .assertTrue (logger_provider ._trace_based )
8996 self .assertIsNotNone (logger_provider ._at_exit_handler )
9097
9198
@@ -127,3 +134,193 @@ def test_can_emit_api_logrecord(self):
127134 log_record_processor_mock .on_emit .assert_called_once ()
128135 log_data = log_record_processor_mock .on_emit .call_args .args [0 ]
129136 self .assertTrue (isinstance (log_data .log_record , LogRecord ))
137+
138+ def test_emit_logrecord_with_min_severity_filtering (self ):
139+ """Test that logs below minimum severity are filtered out"""
140+ logger , log_record_processor_mock = self ._get_logger ()
141+ logger ._min_severity_level = SeverityNumber .DEBUG4
142+
143+ log_record_info = LogRecord (
144+ observed_timestamp = 0 ,
145+ body = "info log line" ,
146+ severity_number = SeverityNumber .DEBUG ,
147+ severity_text = "DEBUG" ,
148+ )
149+
150+ logger .emit (log_record_info )
151+ log_record_processor_mock .on_emit .assert_not_called ()
152+
153+ log_record_processor_mock .reset_mock ()
154+
155+ log_record_error = LogRecord (
156+ observed_timestamp = 0 ,
157+ body = "error log line" ,
158+ severity_number = SeverityNumber .ERROR ,
159+ severity_text = "ERROR" ,
160+ )
161+
162+ logger .emit (log_record_error )
163+
164+ log_record_processor_mock .on_emit .assert_called_once ()
165+ log_data = log_record_processor_mock .on_emit .call_args .args [0 ]
166+ self .assertTrue (isinstance (log_data .log_record , LogRecord ))
167+ self .assertEqual (log_data .log_record .severity_number , SeverityNumber .ERROR )
168+
169+ def test_emit_logrecord_with_min_severity_unspecified (self ):
170+ """Test that when min severity is UNSPECIFIED, all logs are emitted"""
171+ logger , log_record_processor_mock = self ._get_logger ()
172+ log_record = LogRecord (
173+ observed_timestamp = 0 ,
174+ body = "debug log line" ,
175+ severity_number = SeverityNumber .DEBUG ,
176+ severity_text = "DEBUG" ,
177+ )
178+ logger .emit (log_record )
179+ log_record_processor_mock .on_emit .assert_called_once ()
180+
181+ def test_emit_logrecord_with_trace_based_filtering (self ):
182+ """Test that logs are filtered based on trace sampling state"""
183+ logger , log_record_processor_mock = self ._get_logger ()
184+ logger ._trace_based = True
185+
186+ mock_span_context = Mock ()
187+ mock_span_context .is_valid = True
188+ mock_span_context .trace_flags .sampled = False
189+
190+ mock_span = Mock ()
191+ mock_span .get_span_context .return_value = mock_span_context
192+
193+ mock_context = Mock ()
194+
195+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
196+ log_record = LogRecord (
197+ observed_timestamp = 0 ,
198+ body = "should be dropped" ,
199+ severity_number = SeverityNumber .INFO ,
200+ severity_text = "INFO" ,
201+ context = mock_context ,
202+ )
203+
204+ logger .emit (log_record )
205+ log_record_processor_mock .on_emit .assert_not_called ()
206+
207+ log_record_processor_mock .reset_mock ()
208+
209+ mock_span_context = Mock ()
210+ mock_span_context .is_valid = True
211+ mock_span_context .trace_flags .sampled = True
212+
213+ mock_span = Mock ()
214+ mock_span .get_span_context .return_value = mock_span_context
215+
216+ def test_emit_logrecord_trace_filtering_disabled (self ):
217+ """Test that when trace-based filtering is disabled, all logs are emitted"""
218+ logger , log_record_processor_mock = self ._get_logger ()
219+
220+ mock_span_context = Mock ()
221+ mock_span_context .is_valid = False
222+ mock_span_context .trace_flags .sampled = False
223+
224+ mock_span = Mock ()
225+ mock_span .get_span_context .return_value = mock_span_context
226+
227+ mock_context = Mock ()
228+
229+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
230+ log_record = LogRecord (
231+ observed_timestamp = 0 ,
232+ body = "should be emitted when filtering disabled" ,
233+ severity_number = SeverityNumber .INFO ,
234+ severity_text = "INFO" ,
235+ context = mock_context ,
236+ )
237+
238+ logger .emit (log_record )
239+ log_record_processor_mock .on_emit .assert_called_once ()
240+
241+ def test_emit_logrecord_trace_filtering_edge_cases (self ):
242+ """Test edge cases for trace-based filtering"""
243+ logger , log_record_processor_mock = self ._get_logger ()
244+ logger ._trace_based = True
245+
246+ mock_span_context = Mock ()
247+ mock_span_context .is_valid = False
248+ mock_span_context .trace_flags .sampled = True
249+
250+ mock_span = Mock ()
251+ mock_span .get_span_context .return_value = mock_span_context
252+
253+ mock_context = Mock ()
254+
255+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
256+ log_record = LogRecord (
257+ observed_timestamp = 0 ,
258+ body = "invalid but sampled" ,
259+ severity_number = SeverityNumber .INFO ,
260+ severity_text = "INFO" ,
261+ context = mock_context ,
262+ )
263+
264+ logger .emit (log_record )
265+ log_record_processor_mock .on_emit .assert_called_once ()
266+
267+ log_record_processor_mock .reset_mock ()
268+
269+ mock_span_context = Mock ()
270+ mock_span_context .is_valid = True
271+ mock_span_context .trace_flags .sampled = False
272+
273+ mock_span = Mock ()
274+ mock_span .get_span_context .return_value = mock_span_context
275+
276+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
277+ log_record = LogRecord (
278+ observed_timestamp = 0 ,
279+ body = "valid but not sampled" ,
280+ severity_number = SeverityNumber .INFO ,
281+ severity_text = "INFO" ,
282+ context = mock_context ,
283+ )
284+
285+ logger .emit (log_record )
286+ log_record_processor_mock .on_emit .assert_not_called ()
287+
288+ def test_emit_both_min_severity_and_trace_based_filtering (self ):
289+ """Test that both min severity and trace-based filtering work together"""
290+ logger , log_record_processor_mock = self ._get_logger ()
291+ logger ._min_severity_level = SeverityNumber .WARN
292+ logger ._trace_based = True
293+
294+ mock_span_context = Mock ()
295+ mock_span_context .is_valid = True
296+ mock_span_context .trace_flags .sampled = True
297+
298+ mock_span = Mock ()
299+ mock_span .get_span_context .return_value = mock_span_context
300+
301+ mock_context = Mock ()
302+
303+ with patch ('opentelemetry.sdk._logs._internal.get_current_span' , return_value = mock_span ):
304+ log_record_info = LogRecord (
305+ observed_timestamp = 0 ,
306+ body = "info log line" ,
307+ severity_number = SeverityNumber .INFO ,
308+ severity_text = "INFO" ,
309+ context = mock_context ,
310+ )
311+
312+ logger .emit (log_record_info )
313+ log_record_processor_mock .on_emit .assert_not_called ()
314+
315+ log_record_processor_mock .reset_mock ()
316+
317+ log_record_error = LogRecord (
318+ observed_timestamp = 0 ,
319+ body = "error log line" ,
320+ severity_number = SeverityNumber .ERROR ,
321+ severity_text = "ERROR" ,
322+ context = mock_context ,
323+ )
324+
325+ logger .emit (log_record_error )
326+ log_record_processor_mock .on_emit .assert_called_once ()
0 commit comments