23
23
NoOpLogger ,
24
24
SynchronousMultiLogRecordProcessor ,
25
25
)
26
+ from opentelemetry ._logs import (
27
+ SeverityNumber ,
28
+ )
26
29
from opentelemetry .sdk .environment_variables import OTEL_SDK_DISABLED
27
30
from opentelemetry .sdk .resources import Resource
28
31
from opentelemetry .sdk .util .instrumentation import InstrumentationScope
@@ -68,6 +71,8 @@ def test_get_logger(self):
68
71
self .assertEqual (
69
72
logger ._instrumentation_scope .attributes , {"key" : "value" }
70
73
)
74
+ self .assertEqual (logger ._min_severity_level , SeverityNumber .UNSPECIFIED )
75
+ self .assertFalse (logger ._trace_based )
71
76
72
77
@patch .dict ("os.environ" , {OTEL_SDK_DISABLED : "true" })
73
78
def test_get_logger_with_sdk_disabled (self ):
@@ -77,7 +82,7 @@ def test_get_logger_with_sdk_disabled(self):
77
82
78
83
@patch .object (Resource , "create" )
79
84
def test_logger_provider_init (self , resource_patch ):
80
- logger_provider = LoggerProvider ()
85
+ logger_provider = LoggerProvider (min_severity_level = SeverityNumber . DEBUG4 , trace_based = True )
81
86
resource_patch .assert_called_once ()
82
87
self .assertIsNotNone (logger_provider ._resource )
83
88
self .assertTrue (
@@ -86,6 +91,8 @@ def test_logger_provider_init(self, resource_patch):
86
91
SynchronousMultiLogRecordProcessor ,
87
92
)
88
93
)
94
+ self .assertEqual (logger_provider ._min_severity_level , SeverityNumber .DEBUG4 )
95
+ self .assertTrue (logger_provider ._trace_based )
89
96
self .assertIsNotNone (logger_provider ._at_exit_handler )
90
97
91
98
@@ -127,3 +134,193 @@ def test_can_emit_api_logrecord(self):
127
134
log_record_processor_mock .on_emit .assert_called_once ()
128
135
log_data = log_record_processor_mock .on_emit .call_args .args [0 ]
129
136
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