Cherry-pick replay-aware logger into feature branch#2405
Merged
GarrettBeatty merged 2 commits intoJun 3, 2026
Conversation
Implement context.Logger, the replay-aware ILogger described in
Docs/durable-execution-design.md and shipped by the Python / Java / JS
reference SDKs. Messages emitted while the workflow is replaying prior
operations are suppressed, so a 30-step workflow re-invoked 30 times
emits each LogInformation line once instead of 30 times.
Public API:
- IDurableContext.Logger — was NullLogger.Instance, now a replay-safe
ILogger backed by Amazon.Lambda.Core.LambdaLogger so logs flow into
the standard runtime pipeline (JSON when AWS_LAMBDA_LOG_FORMAT=JSON,
level-filtered by AWS_LAMBDA_LOG_LEVEL).
- IDurableContext.ConfigureLogger(LoggerConfig) — swap the inner
ILogger (Serilog, Powertools, etc.) and/or disable replay-aware
filtering (ModeAware = false) for debugging. Matches the API shape
documented in the design doc.
Internals:
- ReplayAwareLogger — ILogger decorator that consults
ExecutionState.IsReplaying on every Log call. Short-circuits both
Log<TState> and IsEnabled during replay so LoggerExtensions.LogXxx
doesn't even format the string. BeginScope always passes through so
the scope stack stays balanced.
- LambdaCoreLogger — minimal in-package adapter that delegates to
Amazon.Lambda.Core.LambdaLogger.Log. Avoids forcing a dependency on
Amazon.Lambda.Logging.AspNetCore.
- DurableFunction.WrapAsyncCore opens a BeginScope around the workflow
body carrying durableExecutionArn + awsRequestId. StepOperation
opens a per-step scope (operationId, operationName, attempt) around
the user-func invocation only. Structured log providers (the
runtime's JSON formatter, Serilog, etc.) tag every log line emitted
by user code with that metadata automatically.
Tests:
- ReplayAwareLoggerTests — 7 unit tests: replay suppression, execution
passthrough, ModeAware=false, IsEnabled short-circuit, scope
passthrough, mid-workflow REPLAY→NEW transition (mirrors Python's
test_logger_replay_then_new_logging).
- DurableContextTests — coverage for the default logger, ConfigureLogger
with a custom logger, and ConfigureLogger { ModeAware = false }
enabling logs during replay.
- ReplayAwareLoggerTest (integration) — deploys a Step → Wait → Step
workflow that pairs each context.Logger.LogInformation line with a
Console.WriteLine "control" line. After the durable execution
completes, queries CloudWatch Logs and asserts each replay-aware
line appears exactly once across both invocations while each control
line appears once per invocation, proving the suppression works
end-to-end.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Forward template + args from LambdaCoreLogger
When state is FormattedLogValues, extract {OriginalFormat} and pass the
original template + named-argument values through to LambdaLogger.Log
instead of pre-rendering. Mirrors the pattern in
Amazon.Lambda.Logging.AspNetCore.LambdaILogger so the runtime's JSON
formatter can surface {OrderId}-style placeholders as top-level
structured attributes.
Make LambdaCoreLogger scope-aware
BeginScope now maintains an AsyncLocal chain of scope state. On Log,
KVP-shaped scope state is appended to the template as named placeholders
(inner→outer order, inner wins on key collision; explicit message args
win over scope keys). The runtime's JSON formatter promotes the keys
to top-level fields, so durableExecutionArn / operationId / etc. show
up as structured attributes without callers having to swap in a
third-party logger.
Unit tests cover ordering, nested scopes, message-arg precedence,
AsyncLocal isolation, and non-KVP fallback. The integration test now
sets AWS_LAMBDA_LOG_FORMAT=JSON, adds a step-internal log line, and
asserts the scope-derived fields land on the parsed JSON record.
| # etc.) appear as top-level fields. | ||
| ENV AWS_LAMBDA_LOG_FORMAT=JSON | ||
|
|
||
| ENTRYPOINT ["/var/task/bootstrap"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
feature/durablefunctionGarrettBeatty/stack/4) but never made it into the feature branchTest plan