2525from handlers .opentelemetry_structlog .src .exporter import LogExporter
2626
2727from datetime import datetime , timezone
28+
2829from unittest .mock import MagicMock , patch
2930
3031
@@ -253,7 +254,6 @@ def structlog_exporter(self):
253254 exporter = StructlogHandler ("test_service" , "test_host" , mock_exporter )
254255 return exporter
255256
256-
257257 def test_initialization (self ):
258258 exporter = self .structlog_exporter ()
259259 assert exporter ._logger_provider is not None , "LoggerProvider should be initialized"
@@ -277,7 +277,6 @@ def test_parse_exception(self):
277277 parsed_exception = self .structlog_exporter ()._parse_exception (event_dict )
278278 assert parsed_exception ["exception.type" ] == "ValueError" , "Exception type should be parsed"
279279 assert parsed_exception ["exception.message" ] == "mock error" , "Exception message should be parsed"
280- # Further assertions can be added for stack trace
281280
282281 def test_parse_timestamp (self ):
283282 # Assuming a specific datetime for consistency
@@ -302,9 +301,94 @@ def test_call_method_processes_log_correctly(self):
302301
303302 # Assert that the logger's emit method was called with the processed event
304303 logger .emit .assert_called_once ()
305-
306-
307-
304+
305+ def test_log_record_translation_attributes (self ):
306+ """Verify that event_dict translates correctly into a LogRecord with the correct attributes."""
307+ exporter = MagicMock ()
308+ logger = MagicMock ()
309+ exporter_instance = StructlogHandler ("test_service" , "test_host" , exporter )
310+ exporter_instance ._logger = logger
311+
312+ timestamp = datetime .now (timezone .utc ).isoformat ()
313+ event_dict = {
314+ "level" : "info" ,
315+ "event" : "test event" ,
316+ "timestamp" : timestamp
317+ }
318+ # Get the StructlogHandler instance
319+
320+ # Assuming StructlogHandler has a method to process and possibly log the event_dict directly.
321+ # Use the instance to process the event_dict.
322+ # Mocking the internal logger's emit method to capture the log record
323+ with patch .object (exporter_instance ._logger , 'emit' ) as mock_emit :
324+ exporter_instance (event_dict = event_dict , logger = logger , name = None )
325+ calls = mock_emit .call_args_list
326+ assert len (calls ) > 0 , "Emit should be called"
327+ log_record = calls [0 ][0 ][0 ] # First call, first arg
328+
329+ # Assuming log_record is the structured log that would have been emitted,
330+ # and you need to verify its contents.
331+ # Need to adjust the assertion depending on how log records are structured.
332+ # I am assuming log_record is a dictionary that was passed to logger.emit.
333+ assert log_record .body == event_dict ["event" ], "LogRecord body should match event"
334+
335+ assert log_record .attributes ["level" ] == event_dict ["level" ], "LogRecord level should match event"
336+
337+ def test_filtering_of_excluded_attributes (self ):
338+ """Ensure specified attributes are not passed to the log record."""
339+ event_dict = {
340+ "level" : "error" ,
341+ "event" : "Something happened!" ,
342+ "timestamp" : datetime .now (timezone .utc ),
343+ "exception" : (ValueError , ValueError ("An error occurred" ), None )
344+ }
345+
346+ # Get the StructlogHandler instance
347+ exporter_instance = self .structlog_exporter ()
348+
349+ with patch .object (exporter_instance ._logger , "emit" ) as mocked_emit :
350+ # Call the exporter_instance with the event_dict
351+ exporter_instance (event_dict = event_dict , logger = None , name = None )
352+
353+ # Check if emit method was called
354+ mocked_emit .assert_called_once ()
355+
356+ # Get the log record passed to emit method
357+ log_record = mocked_emit .call_args .args [0 ]
358+
359+ # Check if the exception attribute is not present in the log record
360+ assert "exception" not in log_record .attributes , "Excluded attributes should not be in the log record"
361+
362+
363+ def test_trace_context_propogation (self ):
364+ """Ensure trace context is correctly propagated to the log record."""
365+ with self .tracer .start_as_current_span ("test_span" ) as span :
366+ span_id = format (span .get_span_context ().span_id , "016x" )
367+ trace_id = format (span .get_span_context ().trace_id , "032x" )
368+ trace_sampled = span .get_span_context ().trace_flags .sampled
369+ event_dict = {
370+ "level" : "info" ,
371+ "event" : "test event" ,
372+ "timestamp" : datetime .now (timezone .utc )
373+ }
374+
375+ # Get the StructlogHandler instance
376+ exporter_instance = self .structlog_exporter ()
377+
378+ with patch .object (exporter_instance , "_logger" ) as mocked_logger :
379+ exporter_instance (event_dict = event_dict , logger = None , name = None )
380+ calls = mocked_logger .emit .call_args_list
381+ log_record = calls [0 ][0 ][0 ]
382+
383+ # Assert that the log record has the correct trace context
384+ actual_span_id = format (log_record .span_id , "016x" )
385+ assert actual_span_id == span_id , "Span ID should be propagated"
386+
387+ actual_trace_id = format (log_record .trace_id , "032x" )
388+ assert actual_trace_id == trace_id , "Trace ID should be propagated"
389+
390+ assert log_record .trace_flags == trace_sampled , "Trace flags should be propagated"
391+
308392
309393
310394class TestLoguruHandler (TestBase ):
@@ -403,8 +487,4 @@ def test_sink(self, mock_get_current_span, mock_emit):
403487 #mock_emit.assert_called_once()
404488 handler ._logger .emit .assert_called_once ()
405489
406- # # Running the tests
407- # if __name__ == '__main__':
408- # unittest.main()
409-
410490
0 commit comments