diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Instrumentation.Hangfire/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt index 15f3ca1d06..f5f2649209 100644 --- a/src/OpenTelemetry.Instrumentation.Hangfire/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt +++ b/src/OpenTelemetry.Instrumentation.Hangfire/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt @@ -1,4 +1,6 @@ OpenTelemetry.Trace.HangfireInstrumentationOptions +OpenTelemetry.Trace.HangfireInstrumentationOptions.DisplayNameFunc.get -> System.Func +OpenTelemetry.Trace.HangfireInstrumentationOptions.DisplayNameFunc.set -> void OpenTelemetry.Trace.HangfireInstrumentationOptions.HangfireInstrumentationOptions() -> void OpenTelemetry.Trace.HangfireInstrumentationOptions.RecordException.get -> bool OpenTelemetry.Trace.HangfireInstrumentationOptions.RecordException.set -> void diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.Hangfire/CHANGELOG.md index fec9b5658e..03bb6fff97 100644 --- a/src/OpenTelemetry.Instrumentation.Hangfire/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.Hangfire/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Add support for custom job display names + ([#756](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/756)) + ## 1.0.0-beta.3 Released 2022-Oct-26 diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/HangfireInstrumentationOptions.cs b/src/OpenTelemetry.Instrumentation.Hangfire/HangfireInstrumentationOptions.cs index 94d14f569d..d08bd5a4f7 100644 --- a/src/OpenTelemetry.Instrumentation.Hangfire/HangfireInstrumentationOptions.cs +++ b/src/OpenTelemetry.Instrumentation.Hangfire/HangfireInstrumentationOptions.cs @@ -14,6 +14,10 @@ // limitations under the License. // +using System; +using Hangfire; +using OpenTelemetry.Instrumentation.Hangfire.Implementation; + namespace OpenTelemetry.Trace; /// @@ -28,4 +32,12 @@ public class HangfireInstrumentationOptions /// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/exceptions.md. /// public bool RecordException { get; set; } + + /// + /// Gets or sets a delegate used to format the job name. + /// + /// + /// Defaults to {backgroundJob.Job.Type.Name}.{backgroundJob.Job.Method.Name}. + /// + public Func DisplayNameFunc { get; set; } = HangfireInstrumentation.DefaultDisplayNameFunc; } diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentation.cs b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentation.cs index 0fc54b23f3..c58d8d1c91 100644 --- a/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentation.cs +++ b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentation.cs @@ -14,6 +14,8 @@ // limitations under the License. // +using Hangfire; + namespace OpenTelemetry.Instrumentation.Hangfire.Implementation; using System; @@ -41,4 +43,10 @@ internal static class HangfireInstrumentation /// The activity source. /// internal static readonly ActivitySource ActivitySource = new(ActivitySourceName, Version.ToString()); + + /// + /// The default display name delegate. + /// + internal static readonly Func DefaultDisplayNameFunc = + backgroundJob => $"JOB {backgroundJob.Job.Type.Name}.{backgroundJob.Job.Method.Name}"; } diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationJobFilterAttribute.cs b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationJobFilterAttribute.cs index 97e871309b..e74f1aa848 100644 --- a/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationJobFilterAttribute.cs +++ b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationJobFilterAttribute.cs @@ -14,6 +14,9 @@ // limitations under the License. // +using System; +using Hangfire; + namespace OpenTelemetry.Instrumentation.Hangfire.Implementation; using System.Collections.Generic; @@ -56,7 +59,10 @@ public void OnPerforming(PerformingContext performingContext) if (activity != null) { - activity.DisplayName = $"JOB {performingContext.BackgroundJob.Job.Type.Name}.{performingContext.BackgroundJob.Job.Method.Name}"; + Func displayNameFunc = + this.options.DisplayNameFunc ?? HangfireInstrumentation.DefaultDisplayNameFunc; + + activity.DisplayName = displayNameFunc(performingContext.BackgroundJob); if (activity.IsAllDataRequested) { diff --git a/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireInstrumentationJobFilterAttributeTests.cs b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireInstrumentationJobFilterAttributeTests.cs index 3c8920c64c..c1d6ff13b8 100644 --- a/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireInstrumentationJobFilterAttributeTests.cs +++ b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireInstrumentationJobFilterAttributeTests.cs @@ -128,6 +128,27 @@ public async Task Should_Create_Activity_Without_Exception_Event_When_Job_Failed Assert.Empty(activity.Events); } + [Fact] + public async Task Should_Create_Activity_With_Custom_DisplayName() + { + // Arrange + var exportedItems = new List(); + using var tel = Sdk.CreateTracerProviderBuilder() + .AddHangfireInstrumentation(options => options.DisplayNameFunc = backgroundJob => $"JOB {backgroundJob.Id}") + .AddInMemoryExporter(exportedItems) + .Build(); + + // Act + var jobId = BackgroundJob.Enqueue(x => x.Execute()); + await this.WaitJobProcessedAsync(jobId, 5); + + // Assert + Assert.Single(exportedItems, i => i.GetTagItem("job.id") as string == jobId); + var activity = exportedItems.Single(i => i.GetTagItem("job.id") as string == jobId); + Assert.Contains($"JOB {jobId}", activity.DisplayName); + Assert.Equal(ActivityKind.Internal, activity.Kind); + } + private async Task WaitJobProcessedAsync(string jobId, int timeToWaitInSeconds) { var timeout = DateTime.Now.AddSeconds(timeToWaitInSeconds);