Skip to content

Commit fc81dab

Browse files
chojomokbouwkastzacharycmontoya
authored
[tracing] hangfire autoinstrumentation (#6904)
## Summary of changes This PR introduces automatic instrumentation for Hangfire in the Datadog .NET Tracer. The following new files and code components were added to enable distributed tracing and error reporting for Hangfire background jobs: - Core instrumentation logic (`HangfireCommon.cs`, `HangfireConstants.cs`) - Duck typing interfaces for Hangfire contexts and jobs to access runtime data (`IBackgroundJobProxy.cs`, `IPerformContextProxy.cs`, `ICreatingContextProxy.cs`, etc.) - Datadog job filters for server and client sides (`DatadogHangfireServerFilter.cs`, `DatadogHangfireClientFilter.cs`) - Integration hooks to inject filters into Hangfire (`JobFilterCollectionctorIntegration.cs`) - Tagging support for Hangfire spans (`HangfireTags.cs`) - Integration tests for Hangfire tracing (`HangfireTests.cs`) - Sample application updates to demonstrate Hangfire usage (`Samples.Hangfire/Program.cs`, `TestJob.cs`) - Addition of `Hangfire` to the `IntegrationId` enum. ## Reason for change - Remove reliance on OTEL instrumentation ## Implementation details - Job filters are injected into Hangfire at runtime using calltarget instrumentation on `JobFilterCollection` construction. - Context propagation is handled via Datadog’s span context mechanisms, ensuring distributed traces are continued between job enqueueing and execution. - Server-side filter creates a Datadog span for each job executed; errors are captured and reported on the span. - Client-side filter propagates trace context when jobs are enqueued. - Duck typing is used to interact with Hangfire types at runtime, making the instrumentation robust to API changes. - Tags are added to spans for job ID, creation time, and resource names for easier identification in Datadog. - All new code adheres to Datadog’s licensing and coding standards. ## Test coverage - Integration tests (`HangfireTests.cs`) verify that traces are submitted for Hangfire jobs, distributed trace context is propagated, and errors are properly recorded in the spans. - The sample application demonstrates covering typical Hangfire usage scenarios, including successful and failed jobs. - Tests confirm service name tagging, error status, and correct trace propagation ## Other details <!-- Fixes #{issue} --> <!-- ⚠️ Note: where possible, please obtain 2 approvals prior to merging. Unless CODEOWNERS specifies otherwise, for external teams it is typically best to have one review from a team member, and one review from apm-dotnet. Trivial changes do not require 2 reviews. --> --------- Co-authored-by: Steven Bouwkamp <steven.bouwkamp@datadoghq.com> Co-authored-by: Zach Montoya <zach.montoya@datadoghq.com>
1 parent 5b42318 commit fc81dab

File tree

68 files changed

+4251
-6845
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+4251
-6845
lines changed

Datadog.Trace.Samples.g.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.AWS.S3", "tracer\te
441441
EndProject
442442
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.GoogleProtobuf", "tracer\test\test-applications\integrations\Samples.GoogleProtobuf\Samples.GoogleProtobuf.csproj", "{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}"
443443
EndProject
444+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.Hangfire", "tracer\test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj", "{59A9EDCD-6892-4817-8957-54DE84BDCAFB}"
445+
EndProject
444446
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.Quartz", "tracer\test\test-applications\integrations\Samples.Quartz\Samples.Quartz.csproj", "{CF69BC17-1527-425A-9B02-8E223BC31DB8}"
445447
EndProject
446448
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.AzureFunctions.V4Isolated.HostLogsDisabled", "tracer\test\test-applications\azure-functions\Samples.AzureFunctions.V4Isolated.HostLogsDisabled\Samples.AzureFunctions.V4Isolated.HostLogsDisabled.csproj", "{C770F9F8-0430-587D-EB7A-8BEC2FE9B61C}"
@@ -1059,6 +1061,10 @@ Global
10591061
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
10601062
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
10611063
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9}.Release|Any CPU.Build.0 = Release|Any CPU
1064+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1065+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
1066+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
1067+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB}.Release|Any CPU.Build.0 = Release|Any CPU
10621068
{CF69BC17-1527-425A-9B02-8E223BC31DB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
10631069
{CF69BC17-1527-425A-9B02-8E223BC31DB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
10641070
{CF69BC17-1527-425A-9B02-8E223BC31DB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -1243,6 +1249,7 @@ Global
12431249
{E2EDDD17-B5E6-4240-9EF8-34F2D274AA19} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
12441250
{0C0578CB-3B67-4F95-8547-206CD2A560CD} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
12451251
{EF8C4CCE-E79C-4D78-BF31-222A11E198B9} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
1252+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
12461253
{CF69BC17-1527-425A-9B02-8E223BC31DB8} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
12471254
{C770F9F8-0430-587D-EB7A-8BEC2FE9B61C} = {C4C1E313-C7C1-4490-AECE-0DD0062380A4}
12481255
EndGlobalSection

Datadog.Trace.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks.OpenTelemetry.In
619619
EndProject
620620
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Datadog.AzureFunctions", "tracer\src\Datadog.AzureFunctions\Datadog.AzureFunctions.csproj", "{BB073E40-F46D-E52B-662E-395EED834111}"
621621
EndProject
622+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.Hangfire", "tracer\test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj", "{59A9EDCD-6892-4817-8957-54DE84BDCAFB}"
623+
EndProject
622624
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.Quartz", "tracer\test\test-applications\integrations\Samples.Quartz\Samples.Quartz.csproj", "{CF69BC17-1527-425A-9B02-8E223BC31DB8}"
623625
EndProject
624626
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.AzureFunctions.V4Isolated.HostLogsDisabled", "tracer\test\test-applications\azure-functions\Samples.AzureFunctions.V4Isolated.HostLogsDisabled\Samples.AzureFunctions.V4Isolated.HostLogsDisabled.csproj", "{C770F9F8-0430-587D-EB7A-8BEC2FE9B61C}"
@@ -1493,6 +1495,10 @@ Global
14931495
{BB073E40-F46D-E52B-662E-395EED834111}.Debug|Any CPU.Build.0 = Debug|Any CPU
14941496
{BB073E40-F46D-E52B-662E-395EED834111}.Release|Any CPU.ActiveCfg = Release|Any CPU
14951497
{BB073E40-F46D-E52B-662E-395EED834111}.Release|Any CPU.Build.0 = Release|Any CPU
1498+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1499+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
1500+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
1501+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB}.Release|Any CPU.Build.0 = Release|Any CPU
14961502
{CF69BC17-1527-425A-9B02-8E223BC31DB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14971503
{CF69BC17-1527-425A-9B02-8E223BC31DB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
14981504
{CF69BC17-1527-425A-9B02-8E223BC31DB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -1748,6 +1754,7 @@ Global
17481754
{501AD343-1951-FF43-0C7F-3FE3FDF5A660} = {E5439139-6F94-44FA-9590-C32FCC1C7A93}
17491755
{BD7ADF79-C948-5CC7-6BE8-A7FF8DF882C3} = {E5439139-6F94-44FA-9590-C32FCC1C7A93}
17501756
{BB073E40-F46D-E52B-662E-395EED834111} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}
1757+
{59A9EDCD-6892-4817-8957-54DE84BDCAFB} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
17511758
{CF69BC17-1527-425A-9B02-8E223BC31DB8} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
17521759
{C770F9F8-0430-587D-EB7A-8BEC2FE9B61C} = {C4C1E313-C7C1-4490-AECE-0DD0062380A4}
17531760
{32521F0A-D52D-4DB1-86C4-3D72DEDA6E55} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}

tracer/build/PackageVersionsGeneratorDefinitions.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
[
2+
{
3+
"IntegrationName": "Hangfire",
4+
"SampleProjectName": "Samples.Hangfire",
5+
"NugetPackageSearchName": "Hangfire.Core",
6+
"MinVersion": "1.7.0",
7+
"MaxVersionExclusive": "2.0.0",
8+
"SpecificVersions": [
9+
"1.7.*",
10+
"1.8.*"
11+
]
12+
},
213
{
314
"IntegrationName": "Quartz",
415
"SampleProjectName": "Samples.Quartz",

tracer/build/PackageVersionsLatestMajors.g.props

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,66 @@ NOTE: This code was generated by the GeneratePackageVersions tool. To safely
1212
-->
1313
<Project>
1414
<ItemGroup>
15+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
16+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
17+
<TargetFramework>net48</TargetFramework>
18+
<RequiresDockerDependency>None</RequiresDockerDependency>
19+
<SampleName>Samples.Hangfire</SampleName>
20+
</PackageVersionSample>
21+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
22+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
23+
<TargetFramework>netcoreapp2.1</TargetFramework>
24+
<RequiresDockerDependency>None</RequiresDockerDependency>
25+
<SampleName>Samples.Hangfire</SampleName>
26+
</PackageVersionSample>
27+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
28+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
29+
<TargetFramework>netcoreapp3.0</TargetFramework>
30+
<RequiresDockerDependency>None</RequiresDockerDependency>
31+
<SampleName>Samples.Hangfire</SampleName>
32+
</PackageVersionSample>
33+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
34+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
35+
<TargetFramework>netcoreapp3.1</TargetFramework>
36+
<RequiresDockerDependency>None</RequiresDockerDependency>
37+
<SampleName>Samples.Hangfire</SampleName>
38+
</PackageVersionSample>
39+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
40+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
41+
<TargetFramework>net5.0</TargetFramework>
42+
<RequiresDockerDependency>None</RequiresDockerDependency>
43+
<SampleName>Samples.Hangfire</SampleName>
44+
</PackageVersionSample>
45+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
46+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
47+
<TargetFramework>net6.0</TargetFramework>
48+
<RequiresDockerDependency>None</RequiresDockerDependency>
49+
<SampleName>Samples.Hangfire</SampleName>
50+
</PackageVersionSample>
51+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
52+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
53+
<TargetFramework>net7.0</TargetFramework>
54+
<RequiresDockerDependency>None</RequiresDockerDependency>
55+
<SampleName>Samples.Hangfire</SampleName>
56+
</PackageVersionSample>
57+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
58+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
59+
<TargetFramework>net8.0</TargetFramework>
60+
<RequiresDockerDependency>None</RequiresDockerDependency>
61+
<SampleName>Samples.Hangfire</SampleName>
62+
</PackageVersionSample>
63+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
64+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
65+
<TargetFramework>net9.0</TargetFramework>
66+
<RequiresDockerDependency>None</RequiresDockerDependency>
67+
<SampleName>Samples.Hangfire</SampleName>
68+
</PackageVersionSample>
69+
<PackageVersionSample Include="test\test-applications\integrations\Samples.Hangfire\Samples.Hangfire.csproj">
70+
<Properties>ApiVersion=1.8.21;RestoreRecursive=false;BuildProjectReferences=false</Properties>
71+
<TargetFramework>net10.0</TargetFramework>
72+
<RequiresDockerDependency>None</RequiresDockerDependency>
73+
<SampleName>Samples.Hangfire</SampleName>
74+
</PackageVersionSample>
1575
<PackageVersionSample Include="test\test-applications\integrations\Samples.Quartz\Samples.Quartz.csproj">
1676
<Properties>ApiVersion=3.15.1;RestoreRecursive=false;BuildProjectReferences=false</Properties>
1777
<TargetFramework>net48</TargetFramework>

0 commit comments

Comments
 (0)