Skip to content

Commit 277bd28

Browse files
Alex Wangwangyb-A
authored andcommitted
feat: move log filter attachment to init
1 parent c2682b8 commit 277bd28

3 files changed

Lines changed: 19 additions & 18 deletions

File tree

packages/aws-durable-execution-sdk-python-examples/src/otel/otel_logger_example.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"""Demonstrates OTel-enriched logging in a durable execution.
22
3-
The DurableExecutionOtelPlugin wraps the execution logger (enrich_logger=True
4-
by default) so every log line emitted through context.logger / step_context.logger
5-
is automatically enriched with the active OpenTelemetry trace context
6-
(otel.trace_id, otel.span_id, otel.trace_sampled). This lets logs correlate to
7-
the spans the plugin emits without any user code changes.
3+
The DurableExecutionOtelPlugin installs a logging filter on the root logger
4+
(enrich_logger=True by default) when the plugin is constructed. The filter
5+
stamps the active OpenTelemetry trace context (otel_trace_id, otel_span_id,
6+
otel_trace_sampled) onto every log record that flows through the root handler.
7+
This includes logs emitted via context.logger / step_context.logger as well as
8+
direct logging.getLogger() calls and third-party library logs, so logs
9+
correlate to the spans the plugin emits without any user code changes.
810
911
Logs emitted:
1012
- at the top level correlate to the invocation span

packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/plugin.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ def __init__(
117117
self._operation_spans: dict[str | None, Span] = {}
118118
self._operation_spans_lock = threading.RLock()
119119

120+
if self._enrich_logger:
121+
# Install the root-logger filter so every log record is stamped with
122+
# the active span context. The Lambda runtime attaches its root
123+
# handler before the handler module is imported (and thus before the
124+
# plugin is constructed), so the handlers are available here.
125+
install_log_filter(self)
126+
120127
def _set_span(self, operation_id: str | None, span: Span) -> None:
121128
"""Register the active span for an operation ID."""
122129
with self._operation_spans_lock:
@@ -284,12 +291,6 @@ def on_invocation_start(self, info: InvocationStartInfo) -> None:
284291
self._extracted_context = self._context_extractor(info)
285292
self._id_generator.set_trace_id(self._execution_arn, info.start_time)
286293

287-
if self._enrich_logger:
288-
# Install (idempotently) the root-logger filter so every log record
289-
# emitted during this invocation is stamped with the active span
290-
# context. Safe to call on every invocation, including warm reuse.
291-
install_log_filter(self)
292-
293294
self._start_span(
294295
operation_id=None,
295296
name="invocation",

packages/aws-durable-execution-sdk-python-otel/tests/test_log_filter.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -200,14 +200,13 @@ def test_install_log_filter_returns_none_without_handlers():
200200
assert install_log_filter(plugin, target_logger=target) is None
201201

202202

203-
def test_on_invocation_start_installs_filter_on_root_logger():
204-
"""The plugin installs the filter on the root logger at invocation start."""
205-
plugin, _ = _create_plugin(enrich_logger=True)
203+
def test_plugin_installs_filter_on_root_logger_at_construction():
204+
"""The plugin installs the filter on the root logger when constructed."""
206205
root = logging.getLogger()
207206
handler = logging.NullHandler()
208207
root.addHandler(handler)
209208
try:
210-
plugin.on_invocation_start(_invocation_start_info())
209+
_create_plugin(enrich_logger=True)
211210

212211
assert any(isinstance(f, OtelContextLogFilter) for f in handler.filters)
213212
finally:
@@ -216,14 +215,13 @@ def test_on_invocation_start_installs_filter_on_root_logger():
216215
root.removeHandler(handler)
217216

218217

219-
def test_on_invocation_start_skips_filter_when_disabled():
218+
def test_plugin_skips_filter_when_disabled():
220219
"""No filter is installed when enrich_logger is disabled."""
221-
plugin, _ = _create_plugin(enrich_logger=False)
222220
root = logging.getLogger()
223221
handler = logging.NullHandler()
224222
root.addHandler(handler)
225223
try:
226-
plugin.on_invocation_start(_invocation_start_info())
224+
_create_plugin(enrich_logger=False)
227225

228226
assert not any(isinstance(f, OtelContextLogFilter) for f in handler.filters)
229227
finally:

0 commit comments

Comments
 (0)