2121# Imports for StructlogHandler tests
2222from unittest .mock import Mock
2323from handlers .opentelemetry_structlog .src .exporter import LogExporter
24- from datetime import datetime , timezone
25- from unittest .mock import MagicMock
24+ from datetime import datetime , timezone , timedelta
25+ from unittest .mock import MagicMock , patch
2626
2727
2828
@@ -247,7 +247,6 @@ def structlog_exporter(self):
247247 exporter = StructlogHandler ("test_service" , "test_host" , mock_exporter )
248248 return exporter
249249
250-
251250 def test_initialization (self ):
252251 exporter = self .structlog_exporter ()
253252 assert exporter ._logger_provider is not None , "LoggerProvider should be initialized"
@@ -271,7 +270,6 @@ def test_parse_exception(self):
271270 parsed_exception = self .structlog_exporter ()._parse_exception (event_dict )
272271 assert parsed_exception ["exception.type" ] == "ValueError" , "Exception type should be parsed"
273272 assert parsed_exception ["exception.message" ] == "mock error" , "Exception message should be parsed"
274- # Further assertions can be added for stack trace
275273
276274 def test_parse_timestamp (self ):
277275 # Assuming a specific datetime for consistency
@@ -296,7 +294,91 @@ def test_call_method_processes_log_correctly(self):
296294
297295 # Assert that the logger's emit method was called with the processed event
298296 logger .emit .assert_called_once ()
297+
299298
300-
301-
302-
299+ def test_log_record_translation_attributes (self ):
300+ """Verify that event_dict translates correctly into a LogRecord with the correct attributes."""
301+ exporter = MagicMock ()
302+ logger = MagicMock ()
303+ exporter_instance = StructlogHandler ("test_service" , "test_host" , exporter )
304+ exporter_instance ._logger = logger
305+
306+ timestamp = datetime .now (timezone .utc ).isoformat ()
307+ event_dict = {
308+ "level" : "info" ,
309+ "event" : "test event" ,
310+ "timestamp" : timestamp
311+ }
312+ # Get the StructlogHandler instance
313+
314+ # Assuming StructlogHandler has a method to process and possibly log the event_dict directly.
315+ # Use the instance to process the event_dict.
316+ # Mocking the internal logger's emit method to capture the log record
317+ with patch .object (exporter_instance ._logger , 'emit' ) as mock_emit :
318+ exporter_instance (event_dict = event_dict , logger = logger , name = None )
319+ calls = mock_emit .call_args_list
320+ assert len (calls ) > 0 , "Emit should be called"
321+ log_record = calls [0 ][0 ][0 ] # First call, first arg
322+
323+ # Assuming log_record is the structured log that would have been emitted,
324+ # and you need to verify its contents.
325+ # Need to adjust the assertion depending on how log records are structured.
326+ # I am assuming log_record is a dictionary that was passed to logger.emit.
327+ assert log_record .body == event_dict ["event" ], "LogRecord body should match event"
328+
329+ assert log_record .attributes ["level" ] == event_dict ["level" ], "LogRecord level should match event"
330+
331+ def test_filtering_of_excluded_attributes (self ):
332+ """Ensure specified attributes are not passed to the log record."""
333+ event_dict = {
334+ "level" : "error" ,
335+ "event" : "Something happened!" ,
336+ "timestamp" : datetime .now (timezone .utc ),
337+ "exception" : (ValueError , ValueError ("An error occurred" ), None )
338+ }
339+
340+ # Get the StructlogHandler instance
341+ exporter_instance = self .structlog_exporter ()
342+
343+ with patch .object (exporter_instance ._logger , "emit" ) as mocked_emit :
344+ # Call the exporter_instance with the event_dict
345+ exporter_instance (event_dict = event_dict , logger = None , name = None )
346+
347+ # Check if emit method was called
348+ mocked_emit .assert_called_once ()
349+
350+ # Get the log record passed to emit method
351+ log_record = mocked_emit .call_args .args [0 ]
352+
353+ # Check if the exception attribute is not present in the log record
354+ assert "exception" not in log_record .attributes , "Excluded attributes should not be in the log record"
355+
356+
357+ def test_trace_context_propogation (self ):
358+ """Ensure trace context is correctly propagated to the log record."""
359+ with self .tracer .start_as_current_span ("test_span" ) as span :
360+ span_id = format (span .get_span_context ().span_id , "016x" )
361+ trace_id = format (span .get_span_context ().trace_id , "032x" )
362+ trace_sampled = span .get_span_context ().trace_flags .sampled
363+ event_dict = {
364+ "level" : "info" ,
365+ "event" : "test event" ,
366+ "timestamp" : datetime .now (timezone .utc )
367+ }
368+
369+ # Get the StructlogHandler instance
370+ exporter_instance = self .structlog_exporter ()
371+
372+ with patch .object (exporter_instance , "_logger" ) as mocked_logger :
373+ exporter_instance (event_dict = event_dict , logger = None , name = None )
374+ calls = mocked_logger .emit .call_args_list
375+ log_record = calls [0 ][0 ][0 ]
376+
377+ # Assert that the log record has the correct trace context
378+ actual_span_id = format (log_record .span_id , "016x" )
379+ assert actual_span_id == span_id , "Span ID should be propagated"
380+
381+ actual_trace_id = format (log_record .trace_id , "032x" )
382+ assert actual_trace_id == trace_id , "Trace ID should be propagated"
383+
384+ assert log_record .trace_flags == trace_sampled , "Trace flags should be propagated"
0 commit comments