Skip to content

Commit 96548d6

Browse files
authored
Merge pull request #2 from carolinecgilbert/structlog-testing
Structlog testing
2 parents 8515ee0 + 45aa0a3 commit 96548d6

File tree

2 files changed

+89
-62
lines changed

2 files changed

+89
-62
lines changed

handlers/opentelemetry_structlog/src/test_logging.py

Lines changed: 0 additions & 55 deletions
This file was deleted.

instrumentation/opentelemetry-instrumentation-logging/tests/test_logging.py

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
# Imports for StructlogHandler tests
2222
from unittest.mock import Mock
2323
from 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

Comments
 (0)