Skip to content

Commit 4ed1b41

Browse files
authored
Expose ILogger creation on TaskOrchestrationContext (#106)
1 parent b3ca9c7 commit 4ed1b41

File tree

5 files changed

+28
-22
lines changed

5 files changed

+28
-22
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## v1.0.0
44

5+
- `TaskOrchestrationContext.CreateReplaySafeLogger` now creates `ILogger` directly (as opposed to wrapping an existing `ILogger`).
56
- Durable Functions class-based syntax now resolves `ITaskActivity` instances from `IServiceProvider`, if available there.
67
- `DurableTaskClient` methods have been touched up to ensure `CancellationToken` is included, as well as is the last parameter.
78

src/Abstractions/TaskOrchestrationContext.cs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ public abstract class TaskOrchestrationContext
5858
/// </value>
5959
public abstract bool IsReplaying { get; }
6060

61+
/// <summary>
62+
/// Gets the logger factory for this context.
63+
/// </summary>
64+
protected abstract ILoggerFactory LoggerFactory { get; }
65+
6166
/// <summary>
6267
/// Gets the deserialized input of the orchestrator.
6368
/// </summary>
@@ -364,18 +369,20 @@ public Task CallSubOrchestratorAsync(
364369
/// Returns an instance of <see cref="ILogger"/> that is replay-safe, meaning that the logger only
365370
/// writes logs when the orchestrator is not replaying previous history.
366371
/// </summary>
367-
/// <remarks>
368-
/// This method wraps the provider <paramref name="logger"/> instance with a new <see cref="ILogger"/>
369-
/// implementation that only writes log messages when <see cref="IsReplaying"/> is <c>false</c>.
370-
/// The resulting logger can be used normally in orchestrator code without needing to worry about duplicate
371-
/// log messages caused by orchestrator replays.
372-
/// </remarks>
373-
/// <param name="logger">The <see cref="ILogger"/> to be wrapped for use by the orchestration.</param>
374-
/// <returns>An instance of <see cref="ILogger"/> that wraps the specified <paramref name="logger"/>.</returns>
375-
public ILogger CreateReplaySafeLogger(ILogger logger)
376-
{
377-
return new ReplaySafeLogger(this, logger);
378-
}
372+
/// <param name="categoryName">The logger's category name.</param>
373+
/// <returns>An instance of <see cref="ILogger"/> that is replay-safe.</returns>
374+
public ILogger CreateReplaySafeLogger(string categoryName)
375+
=> new ReplaySafeLogger(this, this.LoggerFactory.CreateLogger(categoryName));
376+
377+
/// <inheritdoc cref="CreateReplaySafeLogger(string)" />
378+
/// <param name="type">The type to derive the category name from.</param>
379+
public virtual ILogger CreateReplaySafeLogger(Type type)
380+
=> new ReplaySafeLogger(this, this.LoggerFactory.CreateLogger(type));
381+
382+
/// <inheritdoc cref="CreateReplaySafeLogger(string)" />
383+
/// <typeparam name="T">The type to derive category name from.</typeparam>
384+
public virtual ILogger CreateReplaySafeLogger<T>()
385+
=> new ReplaySafeLogger(this, this.LoggerFactory.CreateLogger<T>());
379386

380387
class ReplaySafeLogger : ILogger
381388
{

src/Abstractions/TaskOrchestrator.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ public interface ITaskOrchestrator
8181
/// input.
8282
/// </item>
8383
/// <item>
84-
/// Avoid logging directly in the orchestrator code because log messages will be duplicated on each replay.
85-
/// Instead, use the <see cref="TaskOrchestrationContext.CreateReplaySafeLogger"/> method to wrap an existing
86-
/// <see cref="ILogger"/> into a new <c>ILogger</c> that automatically filters out replay logs.
84+
/// When logging, ensure you use only loggers created from
85+
/// <see cref="TaskOrchestrationContext.CreateReplaySafeLogger(string)"/> or other overloads, as this will ensure
86+
/// logging is not duplicated on each replay.
8787
/// </item>
8888
/// </list>
8989
/// </para>

src/Worker/Core/Shims/TaskOrchestrationContextWrapper.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,15 @@ sealed partial class TaskOrchestrationContextWrapper : TaskOrchestrationContext
3131
/// </summary>
3232
/// <param name="innerContext">The inner orchestration context.</param>
3333
/// <param name="invocationContext">The invocation context.</param>
34-
/// <param name="logger">The logger.</param>
3534
/// <param name="deserializedInput">The deserialized input.</param>
3635
public TaskOrchestrationContextWrapper(
3736
OrchestrationContext innerContext,
3837
OrchestrationInvocationContext invocationContext,
39-
ILogger logger,
4038
object? deserializedInput)
4139
{
4240
this.innerContext = Check.NotNull(innerContext);
4341
this.invocationContext = Check.NotNull(invocationContext);
44-
this.logger = this.CreateReplaySafeLogger(Check.NotNull(logger));
42+
this.logger = this.CreateReplaySafeLogger("Microsoft.DurableTask");
4543
this.deserializedInput = deserializedInput;
4644
}
4745

@@ -60,9 +58,10 @@ public TaskOrchestrationContextWrapper(
6058
/// <inheritdoc/>
6159
public override DateTime CurrentUtcDateTime => this.innerContext.CurrentUtcDateTime;
6260

63-
DataConverter DataConverter => this.invocationContext.Options.DataConverter;
61+
/// <inheritdoc/>
62+
protected override ILoggerFactory LoggerFactory => this.invocationContext.LoggerFactory;
6463

65-
ILoggerFactory LoggerFactory => this.invocationContext.LoggerFactory;
64+
DataConverter DataConverter => this.invocationContext.Options.DataConverter;
6665

6766
/// <inheritdoc/>
6867
public override T GetInput<T>() => (T)this.deserializedInput!;

src/Worker/Core/Shims/TaskOrchestrationShim.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ public TaskOrchestrationShim(
4545
innerContext.ErrorDataConverter = converterShim;
4646

4747
object? input = this.DataConverter.Deserialize(rawInput, this.implementation.InputType);
48-
ILogger contextLogger = this.LoggerFactory.CreateLogger("Microsoft.DurableTask");
49-
this.wrapperContext = new(innerContext, this.invocationContext, contextLogger, input);
48+
this.wrapperContext = new(innerContext, this.invocationContext, input);
5049
object? output = await this.implementation.RunAsync(this.wrapperContext, input);
5150

5251
// Return the output (if any) as a serialized string.

0 commit comments

Comments
 (0)