1313# limitations under the License.
1414
1515import logging
16+ from datetime import datetime , timezone
1617from typing import Optional
1718from unittest import mock
1819
19- import pytest
20-
2120# Imports for StructlogHandler tests
22- from unittest .mock import Mock
23- from handlers .opentelemetry_structlog .src .exporter import LogExporter
24-
25- from datetime import datetime , timezone
26-
27- from unittest .mock import MagicMock , patch
28-
21+ from unittest .mock import MagicMock , Mock , patch
2922
23+ import pytest
3024
25+ from handlers .opentelemetry_structlog .src .exporter import (
26+ LogExporter ,
27+ StructlogHandler ,
28+ )
3129from opentelemetry .instrumentation .logging import ( # pylint: disable=no-name-in-module
3230 DEFAULT_LOGGING_FORMAT ,
3331 LoggingInstrumentor ,
3432)
3533from opentelemetry .test .test_base import TestBase
36- from opentelemetry .trace import (
37- ProxyTracer ,
38- get_tracer ,
39- )
40-
41- from handlers .opentelemetry_structlog .src .exporter import StructlogHandler
42-
34+ from opentelemetry .trace import ProxyTracer , get_tracer
4335
4436
4537class FakeTracerProvider :
@@ -115,7 +107,9 @@ def test_trace_context_injection(self):
115107 span_id = format (span .get_span_context ().span_id , "016x" )
116108 trace_id = format (span .get_span_context ().trace_id , "032x" )
117109 trace_sampled = span .get_span_context ().trace_flags .sampled
118- self .assert_trace_context_injected (span_id , trace_id , trace_sampled )
110+ self .assert_trace_context_injected (
111+ span_id , trace_id , trace_sampled
112+ )
119113
120114 def test_trace_context_injection_without_span (self ):
121115 self .assert_trace_context_injected ("0" , "0" , False )
@@ -160,7 +154,9 @@ def test_custom_format_and_level_env(self, basic_config_mock):
160154 env_patch .stop ()
161155
162156 @mock .patch ("logging.basicConfig" )
163- def test_custom_format_and_level_api (self , basic_config_mock ): # pylint: disable=no-self-use
157+ def test_custom_format_and_level_api (
158+ self , basic_config_mock
159+ ): # pylint: disable=no-self-use
164160 LoggingInstrumentor ().uninstrument ()
165161 LoggingInstrumentor ().instrument (
166162 set_logging_format = True ,
@@ -199,7 +195,9 @@ def test_uninstrumented(self):
199195 span_id = format (span .get_span_context ().span_id , "016x" )
200196 trace_id = format (span .get_span_context ().trace_id , "032x" )
201197 trace_sampled = span .get_span_context ().trace_flags .sampled
202- self .assert_trace_context_injected (span_id , trace_id , trace_sampled )
198+ self .assert_trace_context_injected (
199+ span_id , trace_id , trace_sampled
200+ )
203201
204202 LoggingInstrumentor ().uninstrument ()
205203
@@ -218,6 +216,21 @@ def test_uninstrumented(self):
218216 self .assertFalse (hasattr (record , "otelServiceName" ))
219217 self .assertFalse (hasattr (record , "otelTraceSampled" ))
220218
219+ def test_no_op_tracer_provider (self ):
220+ LoggingInstrumentor ().uninstrument ()
221+ LoggingInstrumentor ().instrument (tracer_provider = NoOpTracerProvider ())
222+
223+ with self .caplog .at_level (level = logging .INFO ):
224+ logger = logging .getLogger ("test logger" )
225+ logger .info ("hello" )
226+
227+ self .assertEqual (len (self .caplog .records ), 1 )
228+ record = self .caplog .records [0 ]
229+ self .assertEqual (record .otelSpanID , "0" )
230+ self .assertEqual (record .otelTraceID , "0" )
231+ self .assertEqual (record .otelServiceName , "" )
232+ self .assertEqual (record .otelTraceSampled , False )
233+
221234
222235# StructlogHandler Tests
223236# Test Initialization
@@ -243,7 +256,9 @@ def structlog_exporter(self):
243256 # Mock the LogExporter dependency
244257 mock_exporter = Mock (spec = LogExporter )
245258 # Instantiate the StructlogHandler with mock dependencies
246- exporter = StructlogHandler ("test_service" , "test_host" , mock_exporter )
259+ exporter = StructlogHandler (
260+ "test_service" , "test_host" , mock_exporter
261+ )
247262 return exporter
248263
249264 def test_initialization (self ):
@@ -272,7 +287,9 @@ def test_parse_exception(self):
272287 # Mocking an exception event
273288 exception = (ValueError , ValueError ("mock error" ), None )
274289 event_dict = {"exception" : exception }
275- parsed_exception = self .structlog_exporter ()._parse_exception (event_dict )
290+ parsed_exception = self .structlog_exporter ()._parse_exception (
291+ event_dict
292+ )
276293 assert (
277294 parsed_exception ["exception.type" ] == "ValueError"
278295 ), "Exception type should be parsed"
@@ -285,7 +302,9 @@ def test_parse_timestamp(self):
285302 fixed_datetime = datetime (2020 , 1 , 1 , tzinfo = timezone .utc )
286303 event_dict = {"timestamp" : fixed_datetime }
287304 timestamp = self .structlog_exporter ()._parse_timestamp (event_dict )
288- expected_timestamp = 1577836800000000000 # Expected nanoseconds since epoch
305+ expected_timestamp = (
306+ 1577836800000000000 # Expected nanoseconds since epoch
307+ )
289308 assert (
290309 timestamp == expected_timestamp
291310 ), "Timestamp should be correctly parsed to nanoseconds"
@@ -294,7 +313,9 @@ def test_call_method_processes_log_correctly(self):
294313 # Mock the logger and exporter
295314 exporter = MagicMock ()
296315 logger = MagicMock ()
297- exporter_instance = StructlogHandler ("test_service" , "test_host" , exporter )
316+ exporter_instance = StructlogHandler (
317+ "test_service" , "test_host" , exporter
318+ )
298319 exporter_instance ._logger = logger
299320
300321 # Define an event dictionary
@@ -316,11 +337,17 @@ def test_log_record_translation_attributes(self):
316337 """Verify that event_dict translates correctly into a LogRecord with the correct attributes."""
317338 exporter = MagicMock ()
318339 logger = MagicMock ()
319- exporter_instance = StructlogHandler ("test_service" , "test_host" , exporter )
340+ exporter_instance = StructlogHandler (
341+ "test_service" , "test_host" , exporter
342+ )
320343 exporter_instance ._logger = logger
321344
322345 timestamp = datetime .now (timezone .utc ).isoformat ()
323- event_dict = {"level" : "info" , "event" : "test event" , "timestamp" : timestamp }
346+ event_dict = {
347+ "level" : "info" ,
348+ "event" : "test event" ,
349+ "timestamp" : timestamp ,
350+ }
324351 # Get the StructlogHandler instance
325352
326353 # Assuming StructlogHandler has a method to process and possibly log the event_dict directly.
@@ -387,16 +414,22 @@ def test_trace_context_propogation(self):
387414 exporter_instance = self .structlog_exporter ()
388415
389416 with patch .object (exporter_instance , "_logger" ) as mocked_logger :
390- exporter_instance (event_dict = event_dict , logger = None , name = None )
417+ exporter_instance (
418+ event_dict = event_dict , logger = None , name = None
419+ )
391420 calls = mocked_logger .emit .call_args_list
392421 log_record = calls [0 ][0 ][0 ]
393422
394423 # Assert that the log record has the correct trace context
395424 actual_span_id = format (log_record .span_id , "016x" )
396- assert actual_span_id == span_id , "Span ID should be propagated"
425+ assert (
426+ actual_span_id == span_id
427+ ), "Span ID should be propagated"
397428
398429 actual_trace_id = format (log_record .trace_id , "032x" )
399- assert actual_trace_id == trace_id , "Trace ID should be propagated"
430+ assert (
431+ actual_trace_id == trace_id
432+ ), "Trace ID should be propagated"
400433
401434 assert (
402435 log_record .trace_flags == trace_sampled
0 commit comments