From 91ff6195f1796a350a8285b58fdc7d29fabdb397 Mon Sep 17 00:00:00 2001 From: James Strachan Date: Mon, 11 Aug 2025 09:28:25 +0100 Subject: [PATCH 1/2] Adds the grafana stack to the microservices worker --- .../TemporalWorkerConfigurationModule.cs | 6 ++++++ .../microservice-worker/Program.cs | 18 ++++++++++++++++++ .../workflows/MicroserviceActivities.cs | 4 ++++ 3 files changed, 28 insertions(+) diff --git a/temporal-examples/microservice-worker/AutoFac/Modules/TemporalWorkerConfigurationModule.cs b/temporal-examples/microservice-worker/AutoFac/Modules/TemporalWorkerConfigurationModule.cs index 1f78316..92997ae 100644 --- a/temporal-examples/microservice-worker/AutoFac/Modules/TemporalWorkerConfigurationModule.cs +++ b/temporal-examples/microservice-worker/AutoFac/Modules/TemporalWorkerConfigurationModule.cs @@ -2,7 +2,9 @@ using Autofac.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Temporalio.Client; using Temporalio.Extensions.Hosting; +using Temporalio.Extensions.OpenTelemetry; using Temporalio.Runtime; using Workflows; @@ -29,6 +31,8 @@ protected override void Load(ContainerBuilder builder) // This is using a different queue to the other worker var taskQueue = temporalConfig["TaskQueue"] ?? "microservice-queue"; + var assemblyName = typeof(TemporalClient).Assembly.GetName(); + services .AddTemporalClient(clientHost, clientNamespace) .Configure(options => @@ -45,6 +49,8 @@ protected override void Load(ContainerBuilder builder) }, } ); + + options.Interceptors = [new TracingInterceptor()]; }); var workerBuilder = services diff --git a/temporal-examples/microservice-worker/Program.cs b/temporal-examples/microservice-worker/Program.cs index a5b6c6a..2de4d13 100644 --- a/temporal-examples/microservice-worker/Program.cs +++ b/temporal-examples/microservice-worker/Program.cs @@ -2,7 +2,11 @@ using Autofac.Extensions.DependencyInjection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; +using OpenTelemetry; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; using Shared.AutoFac.Modules; +using Temporalio.Extensions.OpenTelemetry; using TemporalWorker.AutoFac.Modules; namespace TemporalWorker; @@ -24,6 +28,20 @@ private static async Task Main(string[] args) ) .Build(); + var resourceBuilder = ResourceBuilder + .CreateDefault() + .AddService("TemporalExamples.OpenTelemetry", serviceInstanceId: "microservice-worker"); + + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .SetResourceBuilder(resourceBuilder) + .AddSource( + TracingInterceptor.ClientSource.Name, + TracingInterceptor.WorkflowsSource.Name, + TracingInterceptor.ActivitiesSource.Name + ) + .AddOtlpExporter(o => o.Endpoint = new Uri("http://host.docker.internal:4317")) + .Build(); + await host.RunAsync(); } } diff --git a/temporal-examples/workflows/MicroserviceActivities.cs b/temporal-examples/workflows/MicroserviceActivities.cs index 8a08c65..7196d04 100644 --- a/temporal-examples/workflows/MicroserviceActivities.cs +++ b/temporal-examples/workflows/MicroserviceActivities.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Logging; using Temporalio.Activities; namespace Workflows; @@ -23,6 +24,9 @@ public static async Task TransitionToApproved() [Activity] public static async Task> CreateSecondaryCosts() { + ActivityExecutionContext.Current.Logger.LogInformation( + "Executing activity for OpenTelemetry sample." + ); await Task.Delay(3000); return new Result { Value = "Created" }; } From 2f4505c5ac92e30f290490d965484ace54ab92e5 Mon Sep 17 00:00:00 2001 From: James Strachan Date: Mon, 11 Aug 2025 12:25:36 +0100 Subject: [PATCH 2/2] Add more structured logging to the microservices workflow --- .../workflows/Microservice.workflow.cs | 8 ++-- .../workflows/MicroserviceActivities.cs | 39 +++++++++++++++---- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/temporal-examples/workflows/Microservice.workflow.cs b/temporal-examples/workflows/Microservice.workflow.cs index 75df65a..89e4252 100644 --- a/temporal-examples/workflows/Microservice.workflow.cs +++ b/temporal-examples/workflows/Microservice.workflow.cs @@ -30,7 +30,7 @@ await Workflow.ExecuteActivityAsync( ); bool result = await Workflow.ExecuteActivityAsync( - () => MicroserviceActivities.ValidateTransition("Transition to validate"), + (MicroserviceActivities a) => a.ValidateTransition("Transition to validate"), new ActivityOptions { StartToCloseTimeout = TimeSpan.FromMinutes(5), @@ -40,7 +40,7 @@ await Workflow.ExecuteActivityAsync( ); await Workflow.ExecuteActivityAsync( - () => MicroserviceActivities.CreateSecondaryCosts(), + (MicroserviceActivities a) => a.CreateSecondaryCosts(), new ActivityOptions { StartToCloseTimeout = TimeSpan.FromMinutes(5), @@ -50,7 +50,7 @@ await Workflow.ExecuteActivityAsync( ); var updateUpstream = Workflow.ExecuteActivityAsync( - () => MicroserviceActivities.UpdateUpstream(), + (MicroserviceActivities a) => a.UpdateUpstream(), new ActivityOptions { StartToCloseTimeout = TimeSpan.FromMinutes(5), @@ -60,7 +60,7 @@ await Workflow.ExecuteActivityAsync( ); var transitionToApproved = Workflow.ExecuteActivityAsync( - () => MicroserviceActivities.TransitionToApproved(), + (MicroserviceActivities a) => a.TransitionToApproved(), new ActivityOptions { StartToCloseTimeout = TimeSpan.FromMinutes(5), diff --git a/temporal-examples/workflows/MicroserviceActivities.cs b/temporal-examples/workflows/MicroserviceActivities.cs index 7196d04..023f0d6 100644 --- a/temporal-examples/workflows/MicroserviceActivities.cs +++ b/temporal-examples/workflows/MicroserviceActivities.cs @@ -8,33 +8,58 @@ namespace Workflows; // allow a separation. public class MicroserviceActivities { + private readonly ILogger _logger; + + public MicroserviceActivities(ILogger logger) + { + _logger = logger; + } + [Activity] - public static async Task ValidateTransition(string transitionLocation) + public async Task ValidateTransition(string transitionLocation) { + var duration = 2000; + _logger.LogInformation("Starting delay: {Duration}", duration); await Task.Delay(1000); + _logger.LogInformation("Finished delay"); return true; } [Activity] - public static async Task TransitionToApproved() + public async Task TransitionToApproved() { + ActivityExecutionContext.Current.Logger.LogInformation( + "Executing TransitionToApproved activity for OpenTelemetry sample." + ); + var duration = 1500; + _logger.LogInformation("Starting delay: {Duration}", duration); await Task.Delay(1500); + _logger.LogInformation("Finished delay"); } [Activity] - public static async Task> CreateSecondaryCosts() + public async Task> CreateSecondaryCosts() { ActivityExecutionContext.Current.Logger.LogInformation( - "Executing activity for OpenTelemetry sample." + "Executing CreateSecondaryCosts activity for OpenTelemetry sample." ); - await Task.Delay(3000); + var duration = 3000; + _logger.LogInformation("Starting delay: {Duration}", duration); + await Task.Delay(duration); + _logger.LogInformation("Finished delay"); return new Result { Value = "Created" }; } [Activity] - public static async Task> UpdateUpstream() + public async Task> UpdateUpstream() { - await Task.Delay(5000); + ActivityExecutionContext.Current.Logger.LogInformation( + "Executing UpdateUpstream activity for OpenTelemetry sample." + ); + var duration = 5000; + _logger.LogInformation("Starting delay: {Duration}", duration); + await Task.Delay(duration); + _logger.LogInformation("Finished delay"); return new Result { Value = "updated" }; }