2024-09-23 09:35:43 +00:00
|
|
|
using System.Diagnostics;
|
2024-09-23 21:35:30 +00:00
|
|
|
using Elsa.Common.Contracts;
|
2024-09-23 09:35:43 +00:00
|
|
|
using Elsa.OpenTelemetry.Helpers;
|
|
|
|
|
using Elsa.Workflows;
|
|
|
|
|
using Elsa.Workflows.Contracts;
|
|
|
|
|
using Elsa.Workflows.Pipelines.ActivityExecution;
|
|
|
|
|
using Elsa.Workflows.Pipelines.WorkflowExecution;
|
|
|
|
|
using JetBrains.Annotations;
|
2024-09-23 21:35:30 +00:00
|
|
|
using Newtonsoft.Json;
|
2024-09-23 09:35:43 +00:00
|
|
|
using Activity = System.Diagnostics.Activity;
|
|
|
|
|
using ActivityKind = System.Diagnostics.ActivityKind;
|
|
|
|
|
|
|
|
|
|
namespace Elsa.OpenTelemetry.Middleware;
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
[UsedImplicitly]
|
2024-09-23 21:35:30 +00:00
|
|
|
public class OpenTelemetryTracingActivityExecutionMiddleware(ActivityMiddlewareDelegate next, ISystemClock systemClock) : IActivityExecutionMiddleware
|
2024-09-23 09:35:43 +00:00
|
|
|
{
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public async ValueTask InvokeAsync(ActivityExecutionContext context)
|
|
|
|
|
{
|
|
|
|
|
var activity = context.Activity;
|
2024-09-23 21:35:30 +00:00
|
|
|
using var span = ElsaOpenTelemetry.ActivitySource.StartActivity($"ActivityExecution", ActivityKind.Internal, Activity.Current?.Context ?? default);
|
|
|
|
|
|
|
|
|
|
if (span == null)
|
|
|
|
|
{
|
|
|
|
|
await next(context);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
span.SetTag("activity.nodeId", activity.NodeId);
|
|
|
|
|
span.SetTag("activity.type", activity.Type);
|
|
|
|
|
span.SetTag("activity.name", activity.Name);
|
|
|
|
|
span.SetTag("activityInstance.id", context.Id);
|
|
|
|
|
|
|
|
|
|
span.AddEvent(new ActivityEvent("Executing", tags: new ActivityTagsCollection(new Dictionary<string, object?>
|
|
|
|
|
{
|
|
|
|
|
["activityInstance.status"] = context.Status.ToString(),
|
|
|
|
|
})));
|
|
|
|
|
|
2024-09-23 09:35:43 +00:00
|
|
|
await next(context);
|
2024-09-23 21:35:30 +00:00
|
|
|
|
|
|
|
|
if (context.Status == ActivityStatus.Faulted)
|
|
|
|
|
{
|
|
|
|
|
span.AddEvent(new ActivityEvent("Faulted"));
|
|
|
|
|
span.SetStatus(ActivityStatusCode.Error);
|
|
|
|
|
span.SetTag("error", true);
|
|
|
|
|
span.SetTag("hasIncidents", true);
|
|
|
|
|
|
|
|
|
|
var errorMessage = string.IsNullOrWhiteSpace(context.Exception?.Message) ? "Unknown error" : context.Exception.Message;
|
|
|
|
|
span.SetTag("error.message", errorMessage);
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(context.Exception?.StackTrace))
|
|
|
|
|
span.SetTag("error.stackTrace", context.Exception.StackTrace);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
span.AddEvent(new ActivityEvent("Executed", tags: new ActivityTagsCollection(new Dictionary<string, object?>
|
|
|
|
|
{
|
|
|
|
|
["activityInstance.status"] = context.Status.ToString(),
|
|
|
|
|
})));
|
|
|
|
|
|
|
|
|
|
span.SetTag("activityExecution.durationMs", (systemClock.UtcNow - span.StartTimeUtc).TotalMilliseconds);
|
2024-09-23 09:35:43 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Contains extension methods for <see cref="OpenTelemetryTracingActivityExecutionMiddleware"/>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[UsedImplicitly]
|
|
|
|
|
public static class OpenTelemetryTracingActivityExecutionMiddlewareExtensions
|
|
|
|
|
{
|
|
|
|
|
/// Installs the <see cref="OpenTelemetryTracingActivityExecutionMiddleware"/> component in the workflow execution pipeline.
|
|
|
|
|
public static IActivityExecutionPipelineBuilder UseActivityExecutionTracing(this IActivityExecutionPipelineBuilder pipelineBuilder) => pipelineBuilder.Insert<OpenTelemetryTracingActivityExecutionMiddleware>(0);
|
2024-09-23 21:35:30 +00:00
|
|
|
}
|