From ccc0f42afeeacbbcefe1d48d34b461c61418fda2 Mon Sep 17 00:00:00 2001 From: fred2u Date: Tue, 12 Apr 2022 16:26:01 +0200 Subject: [PATCH] Add Hangfire instrumentation (#271) --- .github/component_owners.yml | 4 + opentelemetry-dotnet-contrib.sln | 14 +++ .../Implementation/HangfireInstrumentation.cs | 45 +++++++++ .../HangfireInstrumentationConstants.cs | 27 ++++++ ...ngfireInstrumentationJobFilterAttribute.cs | 69 ++++++++++++++ ...nTelemetry.Instrumentation.Hangfire.csproj | 13 +++ .../README.md | 62 ++++++++++++ .../TracerProviderBuilderExtensions.cs | 44 +++++++++ .../HangfireFixture.cs | 43 +++++++++ ...eInstrumentationJobFilterAttributeTests.cs | 94 +++++++++++++++++++ ...etry.Instrumentation.Hangfire.Tests.csproj | 24 +++++ .../TestJob.cs | 33 +++++++ 12 files changed, 472 insertions(+) create mode 100644 src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentation.cs create mode 100644 src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationConstants.cs create mode 100644 src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationJobFilterAttribute.cs create mode 100644 src/OpenTelemetry.Instrumentation.Hangfire/OpenTelemetry.Instrumentation.Hangfire.csproj create mode 100644 src/OpenTelemetry.Instrumentation.Hangfire/README.md create mode 100644 src/OpenTelemetry.Instrumentation.Hangfire/TracerProviderBuilderExtensions.cs create mode 100644 test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireFixture.cs create mode 100644 test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireInstrumentationJobFilterAttributeTests.cs create mode 100644 test/OpenTelemetry.Instrumentation.Hangfire.Tests/OpenTelemetry.Instrumentation.Hangfire.Tests.csproj create mode 100644 test/OpenTelemetry.Instrumentation.Hangfire.Tests/TestJob.cs diff --git a/.github/component_owners.yml b/.github/component_owners.yml index cce1ca18ffa..0686afaf8bb 100644 --- a/.github/component_owners.yml +++ b/.github/component_owners.yml @@ -15,6 +15,8 @@ components: - ejsmith src/OpenTelemetry.Instrumentation.GrpcCore/: - pcwiese + src/OpenTelemetry.Instrumentation.Hangfire/: + - fred2u src/OpenTelemetry.Instrumentation.MassTransit/: - alexvaluyskiy src/OpenTelemetry.Instrumentation.MySqlData/: @@ -39,6 +41,8 @@ components: - ejsmith test/OpenTelemetry.Instrumentation.GrpcCore.Tests/: - pcwiese + test/OpenTelemetry.Instrumentation.Hangfire.Tests/: + - fred2u test/OpenTelemetry.Instrumentation.MassTransit.Tests/: - alexvaluyskiy test/OpenTelemetry.Instrumentation.MySqlData.Tests/: diff --git a/opentelemetry-dotnet-contrib.sln b/opentelemetry-dotnet-contrib.sln index 7edfd46ffb6..440e9f1c952 100644 --- a/opentelemetry-dotnet-contrib.sln +++ b/opentelemetry-dotnet-contrib.sln @@ -169,6 +169,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Tests", "test\OpenTelemetry.Extensions.Tests\OpenTelemetry.Extensions.Tests.csproj", "{2117F4E3-6612-4E4D-A757-27271EEB7783}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentation.Hangfire", "src\OpenTelemetry.Instrumentation.Hangfire\OpenTelemetry.Instrumentation.Hangfire.csproj", "{BE5FFBBB-D73F-4071-92F4-F1694881604F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentation.Hangfire.Tests", "test\OpenTelemetry.Instrumentation.Hangfire.Tests\OpenTelemetry.Instrumentation.Hangfire.Tests.csproj", "{ED774FC3-C1C0-44CD-BA41-686C04BEB3E5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -335,6 +339,14 @@ Global {2117F4E3-6612-4E4D-A757-27271EEB7783}.Debug|Any CPU.Build.0 = Debug|Any CPU {2117F4E3-6612-4E4D-A757-27271EEB7783}.Release|Any CPU.ActiveCfg = Release|Any CPU {2117F4E3-6612-4E4D-A757-27271EEB7783}.Release|Any CPU.Build.0 = Release|Any CPU + {BE5FFBBB-D73F-4071-92F4-F1694881604F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE5FFBBB-D73F-4071-92F4-F1694881604F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE5FFBBB-D73F-4071-92F4-F1694881604F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE5FFBBB-D73F-4071-92F4-F1694881604F}.Release|Any CPU.Build.0 = Release|Any CPU + {ED774FC3-C1C0-44CD-BA41-686C04BEB3E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED774FC3-C1C0-44CD-BA41-686C04BEB3E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED774FC3-C1C0-44CD-BA41-686C04BEB3E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED774FC3-C1C0-44CD-BA41-686C04BEB3E5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -386,6 +398,8 @@ Global {6AE92AAD-CF08-4E60-98EF-A7F762DAAB4D} = {2097345F-4DD3-477D-BC54-A922F9B2B402} {42B3FB71-BB42-46E3-9CEC-56620CB76BD9} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63} {2117F4E3-6612-4E4D-A757-27271EEB7783} = {2097345F-4DD3-477D-BC54-A922F9B2B402} + {BE5FFBBB-D73F-4071-92F4-F1694881604F} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63} + {ED774FC3-C1C0-44CD-BA41-686C04BEB3E5} = {2097345F-4DD3-477D-BC54-A922F9B2B402} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B0816796-CDB3-47D7-8C3C-946434DE3B66} diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentation.cs b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentation.cs new file mode 100644 index 00000000000..2adc37cd774 --- /dev/null +++ b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentation.cs @@ -0,0 +1,45 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Instrumentation.Hangfire.Implementation +{ + using System; + using System.Diagnostics; + using System.Reflection; + + internal static class HangfireInstrumentation + { + /// + /// The assembly name. + /// + internal static readonly AssemblyName AssemblyName = typeof(HangfireInstrumentation).Assembly.GetName(); + + /// + /// The activity source name. + /// + internal static readonly string ActivitySourceName = AssemblyName.Name; + + /// + /// The version. + /// + internal static readonly Version Version = AssemblyName.Version; + + /// + /// The activity source. + /// + internal static readonly ActivitySource ActivitySource = new(ActivitySourceName, Version.ToString()); + } +} diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationConstants.cs b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationConstants.cs new file mode 100644 index 00000000000..956a0ca3d01 --- /dev/null +++ b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationConstants.cs @@ -0,0 +1,27 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Instrumentation.Hangfire.Implementation +{ + internal static class HangfireInstrumentationConstants + { + public const string JobIdTag = "job.id"; + public const string JobCreatedAtTag = "job.createdat"; + + public const string ActivityName = "JOB"; + public const string ActivityKey = "opentelemetry_activity_key"; + } +} diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationJobFilterAttribute.cs b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationJobFilterAttribute.cs new file mode 100644 index 00000000000..d00b78fd4ed --- /dev/null +++ b/src/OpenTelemetry.Instrumentation.Hangfire/Implementation/HangfireInstrumentationJobFilterAttribute.cs @@ -0,0 +1,69 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Instrumentation.Hangfire.Implementation +{ + using System.Diagnostics; + using global::Hangfire.Common; + using global::Hangfire.Server; + + internal class HangfireInstrumentationJobFilterAttribute : JobFilterAttribute, IServerFilter + { + public void OnPerforming(PerformingContext performingContext) + { + // Short-circuit if nobody is listening + if (!HangfireInstrumentation.ActivitySource.HasListeners()) + { + return; + } + + var activity = HangfireInstrumentation.ActivitySource + .StartActivity(HangfireInstrumentationConstants.ActivityName, ActivityKind.Internal, parentContext: default); + + if (activity != null) + { + activity.DisplayName = $"JOB {performingContext.BackgroundJob.Job.Type.Name}.{performingContext.BackgroundJob.Job.Method.Name}"; + + if (activity.IsAllDataRequested) + { + activity.SetTag(HangfireInstrumentationConstants.JobIdTag, performingContext.BackgroundJob.Id); + activity.SetTag(HangfireInstrumentationConstants.JobCreatedAtTag, performingContext.BackgroundJob.CreatedAt.ToString("O")); + } + + performingContext.Items.Add(HangfireInstrumentationConstants.ActivityKey, activity); + } + } + + public void OnPerformed(PerformedContext performedContext) + { + // Short-circuit if nobody is listening + if (!HangfireInstrumentation.ActivitySource.HasListeners() || !performedContext.Items.ContainsKey(HangfireInstrumentationConstants.ActivityKey)) + { + return; + } + + if (performedContext.Items[HangfireInstrumentationConstants.ActivityKey] is Activity activity) + { + if (performedContext.Exception != null) + { + activity.SetStatus(ActivityStatusCode.Error, performedContext.Exception.Message); + } + + activity.Dispose(); + } + } + } +} diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/OpenTelemetry.Instrumentation.Hangfire.csproj b/src/OpenTelemetry.Instrumentation.Hangfire/OpenTelemetry.Instrumentation.Hangfire.csproj new file mode 100644 index 00000000000..85b5c8efadd --- /dev/null +++ b/src/OpenTelemetry.Instrumentation.Hangfire/OpenTelemetry.Instrumentation.Hangfire.csproj @@ -0,0 +1,13 @@ + + + netstandard2.0 + OpenTelemetry Hangfire Instrumentation + $(PackageTags);Hangfire + Instrumentation.Hangfire- + false + + + + + + diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/README.md b/src/OpenTelemetry.Instrumentation.Hangfire/README.md new file mode 100644 index 00000000000..951a14054bd --- /dev/null +++ b/src/OpenTelemetry.Instrumentation.Hangfire/README.md @@ -0,0 +1,62 @@ +# Hangfire Instrumentation for OpenTelemetry .NET + +[![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Instrumentation.Hangfire.svg)](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Hangfire) +[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Instrumentation.Hangfire.svg)](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Hangfire) + +This is an +[Instrumentation Library](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library), +which instruments +[Hangfire](https://www.nuget.org/packages/Hangfire/) +and collects telemetry about BackgroundJob. + +## Steps to enable OpenTelemetry.Instrumentation.Hangfire + +### Step 1: Install and configure Hangfire + +[Getting Started](https://docs.hangfire.io/en/latest/getting-started/index.html) + +### Step 2: Install Hangfire instrumentation Package + +Add a reference to the +[`OpenTelemetry.Instrumentation.Hangfire`](https://www.nuget.org/packages/OpenTelemetry.Instrumentation.Hangfire) +package. Also, add any other instrumentations & exporters you will need. + +```shell +dotnet add package OpenTelemetry.Instrumentation.Hangfire --prerelease +``` + +### Step 3: Enable Hangfire Instrumentation at application startup + +Hangfire instrumentation must be enabled at application startup. + +The following example demonstrates adding Hangfire instrumentation to a +console application. This example also sets up the OpenTelemetry Console +exporter, which requires adding the package +[`OpenTelemetry.Exporter.Console`](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Exporter.Console/README.md) +to the application. + +```csharp +using OpenTelemetry.Trace; + +public class Program +{ + public static void Main(string[] args) + { + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddHangfireInstrumentation() + .AddConsoleExporter() + .Build(); + } +} +``` + +For an ASP.NET Core application, adding instrumentation is typically done in +the `ConfigureServices` of your `Startup` class. Refer to [example](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/examples/AspNetCore/Program.cs). + +For an ASP.NET application, adding instrumentation is typically done in the +`Global.asax.cs`. Refer to [example](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/examples/AspNet/Global.asax.cs). + +## References + +* [OpenTelemetry Project](https://opentelemetry.io/) +* [Hangfire Project](https://www.hangfire.io/) diff --git a/src/OpenTelemetry.Instrumentation.Hangfire/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Instrumentation.Hangfire/TracerProviderBuilderExtensions.cs new file mode 100644 index 00000000000..1565151c2af --- /dev/null +++ b/src/OpenTelemetry.Instrumentation.Hangfire/TracerProviderBuilderExtensions.cs @@ -0,0 +1,44 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace OpenTelemetry.Trace +{ + using System; + using OpenTelemetry.Instrumentation.Hangfire.Implementation; + + /// + /// Extension methods to simplify registering of Hangfire job instrumentation. + /// + public static class TracerProviderBuilderExtensions + { + /// + /// Adds Hangfire instrumentation to the tracer provider. + /// + /// being configured. + /// The instance of to chain the calls. + public static TracerProviderBuilder AddHangfireInstrumentation(this TracerProviderBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + Hangfire.GlobalJobFilters.Filters.Add(new HangfireInstrumentationJobFilterAttribute()); + + return builder.AddSource(HangfireInstrumentation.ActivitySourceName); + } + } +} diff --git a/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireFixture.cs b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireFixture.cs new file mode 100644 index 00000000000..acb9ac64e34 --- /dev/null +++ b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireFixture.cs @@ -0,0 +1,43 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using Hangfire; +using Hangfire.MemoryStorage; +using Hangfire.Storage; + +namespace OpenTelemetry.Instrumentation.Hangfire.Tests +{ + public class HangfireFixture : IDisposable + { + public HangfireFixture() + { + GlobalConfiguration.Configuration + .UseMemoryStorage(); + this.Server = new BackgroundJobServer(); + this.MonitoringApi = JobStorage.Current.GetMonitoringApi(); + } + + public BackgroundJobServer Server { get; } + + public IMonitoringApi MonitoringApi { get; } + + public void Dispose() + { + this.Server.Dispose(); + } + } +} diff --git a/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireInstrumentationJobFilterAttributeTests.cs b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireInstrumentationJobFilterAttributeTests.cs new file mode 100644 index 00000000000..1f2d4347e71 --- /dev/null +++ b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/HangfireInstrumentationJobFilterAttributeTests.cs @@ -0,0 +1,94 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Hangfire; +using Hangfire.Storage.Monitoring; +using OpenTelemetry.Trace; +using Xunit; + +namespace OpenTelemetry.Instrumentation.Hangfire.Tests +{ + public class HangfireInstrumentationJobFilterAttributeTests : IClassFixture + { + private HangfireFixture hangfireFixture; + + public HangfireInstrumentationJobFilterAttributeTests(HangfireFixture hangfireFixture) + { + this.hangfireFixture = hangfireFixture; + } + + [Fact] + public async Task Should_Create_Activity() + { + // Arrange + var exportedItems = new List(); + using var tel = Sdk.CreateTracerProviderBuilder() + .AddHangfireInstrumentation() + .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 TestJob.Execute", activity.DisplayName); + Assert.Equal(ActivityKind.Internal, activity.Kind); + } + + [Fact] + public async Task Should_Create_Activity_With_Status_Error_When_Job_Failed() + { + // Arrange + var exportedItems = new List(); + using var tel = Sdk.CreateTracerProviderBuilder() + .AddHangfireInstrumentation() + .AddInMemoryExporter(exportedItems) + .Build(); + + // Act + var jobId = BackgroundJob.Enqueue(x => x.ThrowException()); + 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 TestJob.ThrowException", activity.DisplayName); + Assert.Equal(ActivityKind.Internal, activity.Kind); + Assert.Equal(ActivityStatusCode.Error, activity.Status); + Assert.NotNull(activity.StatusDescription); + } + + private async Task WaitJobProcessedAsync(string jobId, int timeToWaitInSeconds) + { + var timeout = DateTime.Now.AddSeconds(timeToWaitInSeconds); + string[] states = new[] { "Enqueued", "Processing" }; + JobDetailsDto jobDetails; + while (((jobDetails = this.hangfireFixture.MonitoringApi.JobDetails(jobId)) == null || jobDetails.History.All(h => states.Contains(h.StateName))) + && DateTime.Now < timeout) + { + await Task.Delay(500); + } + } + } +} diff --git a/test/OpenTelemetry.Instrumentation.Hangfire.Tests/OpenTelemetry.Instrumentation.Hangfire.Tests.csproj b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/OpenTelemetry.Instrumentation.Hangfire.Tests.csproj new file mode 100644 index 00000000000..552d1cd1d31 --- /dev/null +++ b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/OpenTelemetry.Instrumentation.Hangfire.Tests.csproj @@ -0,0 +1,24 @@ + + + Unit test project for OpenTelemetry Hangfire instrumentation + net472;netcoreapp3.1 + false + false + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + diff --git a/test/OpenTelemetry.Instrumentation.Hangfire.Tests/TestJob.cs b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/TestJob.cs new file mode 100644 index 00000000000..df112c67547 --- /dev/null +++ b/test/OpenTelemetry.Instrumentation.Hangfire.Tests/TestJob.cs @@ -0,0 +1,33 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; + +namespace OpenTelemetry.Instrumentation.Hangfire.Tests +{ + public class TestJob + { + public void Execute() + { + return; + } + + public void ThrowException() + { + throw new Exception(); + } + } +}