Skip to content

Commit 0bed7a1

Browse files
change to StructlogHandler, updates
1 parent 1ac0121 commit 0bed7a1

4 files changed

Lines changed: 35 additions & 26 deletions

File tree

instrumentation/opentelemetry-instrumentation-structlog/src/opentelemetry/instrumentation/structlog/__init__.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def std_to_otel(levelno: int) -> SeverityNumber:
137137
return _STD_TO_OTEL[levelno]
138138

139139

140-
class OpenTelemetryProcessor:
140+
class StructlogHandler:
141141
"""
142142
A structlog processor that translates structlog events into OpenTelemetry LogRecords.
143143
@@ -255,7 +255,7 @@ def _translate(self, event_dict: dict) -> LogRecord:
255255
attributes = self._get_attributes(event_dict)
256256

257257
# Get the current OTel context (includes trace context and baggage)
258-
context = get_current() or None
258+
context = get_current()
259259

260260
return LogRecord(
261261
timestamp=timestamp,
@@ -286,7 +286,7 @@ class StructlogInstrumentor(BaseInstrumentor):
286286
"""
287287
An instrumentor for the structlog logging library.
288288
289-
This instrumentor adds an OpenTelemetryProcessor to the structlog processor
289+
This instrumentor adds an StructlogHandler to the structlog processor
290290
chain, enabling automatic emission of structlog events as OpenTelemetry logs.
291291
292292
Example:
@@ -305,21 +305,35 @@ def instrumentation_dependencies(self) -> Collection[str]:
305305

306306
def _instrument(self, **kwargs):
307307
"""
308-
Add the OpenTelemetryProcessor to structlog's processor chain.
308+
Add the StructlogHandler to structlog's processor chain.
309+
310+
The handler is inserted before the last processor in the current chain.
311+
This assumes the last processor is a renderer (e.g. ConsoleRenderer,
312+
JSONRenderer). The handler must run before rendering so it receives the
313+
raw event dict rather than a formatted string.
314+
315+
If your chain does not end with a renderer, or has post-processing steps
316+
after the renderer, configure the chain manually instead of relying on
317+
auto-instrumentation:
318+
319+
structlog.configure(processors=[
320+
structlog.stdlib.add_log_level,
321+
StructlogHandler(logger_provider=provider),
322+
structlog.dev.ConsoleRenderer(),
323+
])
309324
310325
Args:
311326
logger_provider: Optional LoggerProvider to use.
312327
"""
313328
# Create the OTel processor
314329
logger_provider = kwargs.get("logger_provider")
315-
processor = OpenTelemetryProcessor(logger_provider=logger_provider)
330+
processor = StructlogHandler(logger_provider=logger_provider)
316331

317332
# Get current structlog configuration
318333
config = structlog.get_config()
319334
current_processors = list(config.get("processors", []))
320335

321-
# Insert the OTel processor before the last processor (typically the renderer)
322-
# This ensures we capture the event before it's formatted
336+
# Insert before the last processor, assumed to be the renderer.
323337
if current_processors:
324338
insert_position = len(current_processors) - 1
325339
else:
@@ -335,7 +349,7 @@ def _instrument(self, **kwargs):
335349

336350
def _uninstrument(self, **kwargs):
337351
"""
338-
Remove the OpenTelemetryProcessor from structlog's processor chain.
352+
Remove the StructlogHandler from structlog's processor chain.
339353
"""
340354
if StructlogInstrumentor._processor is None:
341355
return
@@ -344,10 +358,10 @@ def _uninstrument(self, **kwargs):
344358
config = structlog.get_config()
345359
current_processors = list(config.get("processors", []))
346360

347-
# Remove all OpenTelemetryProcessor instances
361+
# Remove all StructlogHandler instances
348362
new_processors = [
349363
p for p in current_processors
350-
if not isinstance(p, OpenTelemetryProcessor)
364+
if not isinstance(p, StructlogHandler)
351365
]
352366

353367
# Reconfigure structlog

instrumentation/opentelemetry-instrumentation-structlog/src/opentelemetry/instrumentation/structlog/package.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# limitations under the License.
1414

1515

16-
_instruments = ("structlog ~= 21.1",)
16+
_instruments = ("structlog >= 21.1",)

instrumentation/opentelemetry-instrumentation-structlog/src/opentelemetry/instrumentation/structlog/version.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,3 @@
1313
# limitations under the License.
1414

1515
__version__ = "0.59b0.dev"
16-
17-
_instruments = ("structlog ~= 21.1",)

instrumentation/opentelemetry-instrumentation-structlog/tests/test_structlog.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
from opentelemetry._logs import SeverityNumber
2020
from opentelemetry.instrumentation.structlog import (
21-
OpenTelemetryProcessor,
21+
StructlogHandler,
2222
StructlogInstrumentor,
2323
)
2424
from opentelemetry.sdk._logs import LoggerProvider
@@ -28,8 +28,8 @@
2828
from opentelemetry.trace import TraceFlags
2929

3030

31-
class TestOpenTelemetryProcessor(TestBase):
32-
"""Tests for the OpenTelemetryProcessor class."""
31+
class TestStructlogHandler(TestBase):
32+
"""Tests for the StructlogHandler class."""
3333

3434
def setUp(self):
3535
super().setUp()
@@ -41,7 +41,7 @@ def setUp(self):
4141
)
4242

4343
# Configure structlog with OTel processor
44-
self.processor = OpenTelemetryProcessor(
44+
self.processor = StructlogHandler(
4545
logger_provider=self.logger_provider
4646
)
4747
structlog.configure(
@@ -285,7 +285,7 @@ def test_flush(self):
285285

286286
mock_provider = Mock()
287287
mock_provider.force_flush = Mock()
288-
processor = OpenTelemetryProcessor(logger_provider=mock_provider)
288+
processor = StructlogHandler(logger_provider=mock_provider)
289289

290290
processor.flush()
291291

@@ -340,9 +340,9 @@ def test_instrument_adds_processor(self):
340340
new_processors = structlog.get_config()["processors"]
341341
self.assertEqual(len(new_processors), initial_count + 1)
342342

343-
# Check that an OpenTelemetryProcessor is in the chain
343+
# Check that a StructlogHandler is in the chain
344344
has_otel_processor = any(
345-
isinstance(p, OpenTelemetryProcessor) for p in new_processors
345+
isinstance(p, StructlogHandler) for p in new_processors
346346
)
347347
self.assertTrue(has_otel_processor)
348348

@@ -361,7 +361,7 @@ def test_uninstrument_removes_processor(self):
361361
# Verify processor was added
362362
config_after_instrument = structlog.get_config()["processors"]
363363
has_otel = any(
364-
isinstance(p, OpenTelemetryProcessor) for p in config_after_instrument
364+
isinstance(p, StructlogHandler) for p in config_after_instrument
365365
)
366366
self.assertTrue(has_otel)
367367

@@ -371,7 +371,7 @@ def test_uninstrument_removes_processor(self):
371371
# Verify processor was removed
372372
config_after_uninstrument = structlog.get_config()["processors"]
373373
has_otel = any(
374-
isinstance(p, OpenTelemetryProcessor) for p in config_after_uninstrument
374+
isinstance(p, StructlogHandler) for p in config_after_uninstrument
375375
)
376376
self.assertFalse(has_otel)
377377

@@ -401,10 +401,7 @@ def test_custom_logger_provider(self):
401401
custom_provider = LoggerProvider()
402402
custom_exporter = InMemoryLogRecordExporter()
403403
custom_provider.add_log_record_processor(
404-
LoggingHandler(
405-
level=0,
406-
logger_provider=custom_provider,
407-
)
404+
SimpleLogRecordProcessor(custom_exporter)
408405
)
409406

410407
structlog.configure(

0 commit comments

Comments
 (0)