diff --git a/src/Client/Grpc/GrpcDurableEntityClient.cs b/src/Client/Grpc/GrpcDurableEntityClient.cs index fd8e63926..a12665eaf 100644 --- a/src/Client/Grpc/GrpcDurableEntityClient.cs +++ b/src/Client/Grpc/GrpcDurableEntityClient.cs @@ -55,10 +55,10 @@ public override async Task SignalEntityAsync( RequestId = requestId.ToString(), Name = operationName, Input = this.dataConverter.Serialize(input), - ScheduledTime = scheduledTime?.ToTimestamp(), + ScheduledTime = scheduledTime?.ToTimestamp(), RequestTime = DateTimeOffset.UtcNow.ToTimestamp(), - }; - + }; + if (Activity.Current is { } activity) { request.ParentTraceContext ??= new P.TraceContext(); @@ -66,7 +66,7 @@ public override async Task SignalEntityAsync( request.ParentTraceContext.TraceState = activity.TraceStateString; } - // TODO this.logger.LogSomething + this.logger.SignalingEntity(id.ToString(), operationName); try { await this.sidecarClient.SignalEntityAsync(request, cancellationToken: cancellation); @@ -107,6 +107,7 @@ public override async Task CleanEntityStorageAsync( int emptyEntitiesRemoved = 0; int orphanedLocksReleased = 0; + this.logger.CleaningEntityStorage(); try { do @@ -156,6 +157,7 @@ public override async Task CleanEntityStorageAsync( IncludeState = includeState, }; + this.logger.GettingEntity(id.ToString()); try { P.GetEntityResponse response = await this.sidecarClient @@ -180,6 +182,7 @@ AsyncPageable GetAllEntitiesCoreAsync( DateTimeOffset? lastModifiedFrom = filter?.LastModifiedFrom; DateTimeOffset? lastModifiedTo = filter?.LastModifiedTo; + this.logger.QueryingEntities(startsWith, lastModifiedFrom, lastModifiedTo); return Pageable.Create(async (continuation, pageSize, cancellation) => { pageSize ??= filter?.PageSize; diff --git a/src/Client/Grpc/Logs.cs b/src/Client/Grpc/Logs.cs index 8887f17d9..2a8594e07 100644 --- a/src/Client/Grpc/Logs.cs +++ b/src/Client/Grpc/Logs.cs @@ -39,6 +39,18 @@ static partial class Logs [LoggerMessage(EventId = 46, Level = LogLevel.Information, Message = "Purging instances with filter: {{ CreatedFrom = {createdFrom}, CreatedTo = {createdTo}, Statuses = {statuses} }}")] public static partial void PurgingInstances(this ILogger logger, DateTimeOffset? createdFrom, DateTimeOffset? createdTo, string? statuses); + [LoggerMessage(EventId = 47, Level = LogLevel.Information, Message = "Signaling entity '{instanceId}' with operation '{operationName}'.")] + public static partial void SignalingEntity(this ILogger logger, string instanceId, string operationName); + + [LoggerMessage(EventId = 48, Level = LogLevel.Information, Message = "Getting entity '{instanceId}'.")] + public static partial void GettingEntity(this ILogger logger, string instanceId); + + [LoggerMessage(EventId = 49, Level = LogLevel.Information, Message = "Querying entities with filter: {{ StartsWith = {startsWith}, LastModifiedFrom = {lastModifiedFrom}, LastModifiedTo = {lastModifiedTo} }}")] + public static partial void QueryingEntities(this ILogger logger, string? startsWith, DateTimeOffset? lastModifiedFrom, DateTimeOffset? lastModifiedTo); + + [LoggerMessage(EventId = 50, Level = LogLevel.Information, Message = "Cleaning entity storage.")] + public static partial void CleaningEntityStorage(this ILogger logger); + /// /// . /// diff --git a/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs b/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs index 0f2baa0b2..b601f9560 100644 --- a/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs +++ b/src/ScheduledTasks/Orchestrations/ExecuteScheduleOperationOrchestrator.cs @@ -2,10 +2,10 @@ // Licensed under the MIT License. using Microsoft.DurableTask.Entities; +using Microsoft.Extensions.Logging; namespace Microsoft.DurableTask.ScheduledTasks; -// TODO: logging // TODO: May need separate orchs, result is obj now /// @@ -18,7 +18,22 @@ public class ExecuteScheduleOperationOrchestrator : TaskOrchestrator public override async Task RunAsync(TaskOrchestrationContext context, ScheduleOperationRequest input) { - return await context.Entities.CallEntityAsync(input.EntityId, input.OperationName, input.Input); + ILogger logger = context.CreateReplaySafeLogger(); + string scheduleId = input.EntityId.Key; + + logger.ScheduleOperationInfo(scheduleId, input.OperationName, "Executing schedule operation via orchestrator"); + + try + { + object result = await context.Entities.CallEntityAsync(input.EntityId, input.OperationName, input.Input); + logger.ScheduleOperationInfo(scheduleId, input.OperationName, "Schedule operation completed successfully"); + return result; + } + catch (Exception ex) + { + logger.ScheduleOperationError(scheduleId, input.OperationName, "Failed to execute schedule operation via orchestrator", ex); + throw; + } } } diff --git a/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs b/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs index 89b6024d3..914c7650f 100644 --- a/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs +++ b/test/ScheduledTasks.Tests/Orchestrations/ExecuteScheduleOperationOrchestratorTests.cs @@ -4,6 +4,7 @@ using Microsoft.DurableTask.Client; using Microsoft.DurableTask.Client.Entities; using Microsoft.DurableTask.Entities; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; @@ -20,6 +21,9 @@ public ExecuteScheduleOperationOrchestratorTests() this.mockContext = new Mock(MockBehavior.Strict); this.mockEntityClient = new Mock(MockBehavior.Loose); this.mockContext.Setup(c => c.Entities).Returns(this.mockEntityClient.Object); + this.mockContext + .Setup(c => c.CreateReplaySafeLogger()) + .Returns(NullLogger.Instance); this.orchestrator = new ExecuteScheduleOperationOrchestrator(); }