Add replay-safe logging#295
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request adds a replay-safe orchestration logging capability to the Durable Task Java client by providing a Logger wrapper that suppresses log emissions during orchestration replay, reducing duplicated log output.
Changes:
- Introduces
ReplaySafeLoggerand aTaskOrchestrationContext#createReplaySafeLogger(Logger)convenience API. - Documents replay-safe logging usage patterns (including Azure Functions guidance) in the README and adds a changelog entry.
- Adds unit and integration tests validating suppression during replay and single emission during live segments.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| samples-azure-functions/src/main/java/com/functions/AzureFunctions.java | Updates the Azure Functions sample orchestrator to use createReplaySafeLogger for replay-safe logs. |
| README.md | Adds documentation and examples for replay-safe orchestration logging. |
| client/src/main/java/com/microsoft/durabletask/TaskOrchestrationContext.java | Adds the createReplaySafeLogger(Logger) default method API. |
| client/src/main/java/com/microsoft/durabletask/ReplaySafeLogger.java | Implements the replay-suppressing Logger wrapper. |
| client/src/test/java/com/microsoft/durabletask/ReplaySafeLoggerTest.java | Adds focused unit tests for suppression behavior and delegation semantics. |
| client/src/test/java/com/microsoft/durabletask/TaskOrchestrationExecutorTest.java | Adds an executor-level test validating replay suppression vs live emission. |
| client/src/test/java/com/microsoft/durabletask/IntegrationTests.java | Adds an end-to-end integration test covering parent/child orchestrations and activity logging behavior. |
| CHANGELOG.md | Records the new createReplaySafeLogger API addition. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
YunchuWang
left a comment
There was a problem hiding this comment.
Thanks for this — the design is careful and the test coverage is genuinely strong (the reflection-based allPublicLoggerMethodsAreClassified guard is a nice touch for pinning JDK behavior). A few things worth confirming before merge; nothing here is a hard blocker.
Strengths
isReplayingis read lazily per call viathis::getIsReplaying, so replay state is evaluated at log time on the orchestrator thread — correct timing.- Using the protected
Logger(name, null)constructor avoidsLogManagerregistration, so creating a wrapper on every replay is cheap and leak-free. Good call. - Supplier-based overloads are correctly short-circuited before evaluation during replay, and that's explicitly tested.
- Executor-level + integration tests validate suppress-on-replay vs emit-on-live, including asserting that replay actually occurred (
parentExecutions/childExecutions >= 2).
Main thing to confirm — Java 8 target vs Java 9+ API
client/build.gradle sets sourceCompatibility/targetCompatibility = 1.8, but ReplaySafeLogger overrides Logger methods introduced in Java 9:
log(Level, Throwable, Supplier)logp(Level, String, String, Throwable, Supplier)logrb(Level, String, String, ResourceBundle, String, Throwable)(plus the inheritedlogrb(Level, ResourceBundle, …)overloads the tests exercise)
This compiles in CI because the build runs on JDK 11 with -source/-target 8 (not --release 8), so the newer Logger API is on the compile classpath. The published artifact is therefore Java 8 bytecode that references Java 9+ methods. On a Java 8 runtime the class loads and the Java 8 methods work fine, but those specific overloads would throw NoSuchMethodError if invoked. Practical risk is low — a Java 8-compiled caller can't reach them through a Logger-typed reference, and JUL never routes into them internally — but it's inconsistent with the stated Java 8 target.
Could we confirm the intended minimum JDK? If Java 8 must be supported, this isn't a faithful drop-in there; if it doesn't need to be, using options.release = 8 (or bumping the target) would remove the ambiguity and catch this class of issue at compile time.
Minor / documented tradeoffs (fine to leave — just flagging)
isLoggable(Level)ignores replay, so the guard idiomif (logger.isLoggable(FINE)) logger.fine(expensive())still builds the message during replay before it's suppressed. The javadoc already steers users to supplier methods, which is reasonable — just confirming it's intentional rather than makingisLoggablereplay-aware.- Source class/method inference is lost for everything except
logp(records get attributed toReplaySafeLogger.log). Immaterial for the Azure FunctionsExecutionContext.getLogger()path and it's documented, so no action needed.
Nits
ReplaySafeLogger.javaandReplaySafeLoggerTest.javaare missing a trailing newline.- The CHANGELOG entry could include the
([#295](…))link to match the style of the entry below it.
This pull request introduces a new replay-safe logging feature for orchestrations, ensuring that log output is suppressed during replay segments to prevent duplicate log entries. It includes the implementation of a
ReplaySafeLogger, integration into the orchestration context, comprehensive documentation, and a new integration test to validate the behavior.Replay-safe logging feature:
ReplaySafeLoggerclass, which wraps a standardLoggerand suppresses log output when the orchestration is replaying. This prevents duplicate logs during state reconstruction. (client/src/main/java/com/microsoft/durabletask/ReplaySafeLogger.java)createReplaySafeLoggerdefault method to theTaskOrchestrationContextinterface, allowing orchestrator code to easily obtain a replay-safe logger. (client/src/main/java/com/microsoft/durabletask/TaskOrchestrationContext.java)README.md)createReplaySafeLoggerAPI. (CHANGELOG.md)Testing:
client/src/test/java/com/microsoft/durabletask/IntegrationTests.java)These changes improve the reliability and usability of orchestration logging by preventing duplicate log entries during replay, while providing clear documentation and tests for the new functionality.
Pull request checklist
CHANGELOG.mdAdditional information
Additional PR information