OpenTelemetry.Instrumentation.Hangfire
1.14.0-beta.2
Prefix Reserved
dotnet add package OpenTelemetry.Instrumentation.Hangfire --version 1.14.0-beta.2
NuGet\Install-Package OpenTelemetry.Instrumentation.Hangfire -Version 1.14.0-beta.2
<PackageReference Include="OpenTelemetry.Instrumentation.Hangfire" Version="1.14.0-beta.2" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Hangfire" Version="1.14.0-beta.2" />
<PackageReference Include="OpenTelemetry.Instrumentation.Hangfire" />
paket add OpenTelemetry.Instrumentation.Hangfire --version 1.14.0-beta.2
#r "nuget: OpenTelemetry.Instrumentation.Hangfire, 1.14.0-beta.2"
#:package OpenTelemetry.Instrumentation.Hangfire@1.14.0-beta.2
#addin nuget:?package=OpenTelemetry.Instrumentation.Hangfire&version=1.14.0-beta.2&prerelease
#tool nuget:?package=OpenTelemetry.Instrumentation.Hangfire&version=1.14.0-beta.2&prerelease
Hangfire Instrumentation for OpenTelemetry .NET
| Status | |
|---|---|
| Stability | Beta |
| Code Owners | @fred2u |
This is an Instrumentation Library, which instruments Hangfire and collects traces and metrics about BackgroundJob executions.
Please note that installing the OpenTelemetry Hangfire instrumentation will retrieve from NuGet and install Hangfire.Core, which is provided by its licensor under a choice of LGPL-3.0 or a commercial license.
Steps to enable OpenTelemetry.Instrumentation.Hangfire
The following steps show how to enable tracing. For metrics, see the Metrics section below.
Step 1: Install and configure Hangfire
Step 2: Install Hangfire instrumentation Package
Add a reference to the
OpenTelemetry.Instrumentation.Hangfire
package. Also, add any other instrumentations & exporters you will need.
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
to the application.
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.
For an ASP.NET application, adding instrumentation is typically done in the
Global.asax.cs. Refer to example.
Advanced configuration
This instrumentation can be configured to change the default behavior by using
HangfireInstrumentationOptions.
using var tracerProvider = Sdk
.CreateTracerProviderBuilder()
.AddHangfireInstrumentation(options =>
{
options.DisplayNameFunc = job => $"JOB {job.Id}";
options.Filter = job => job.Id == "Filter this job";
options.RecordException = true;
})
.AddConsoleExporter()
.Build();
When used with
OpenTelemetry.Extensions.Hosting,
all configurations to HangfireInstrumentationOptions
can be done in the ConfigureServices method of your applications Startup
class as shown below.
// Configure
services.Configure<HangfireInstrumentationOptions>(options =>
{
options.DisplayNameFunc = job => $"JOB {job.Id}";
options.Filter = job => job.Id == "Filter this job";
options.RecordException = true;
});
services.AddOpenTelemetry()
.WithTracing(builder => builder
.AddHangfireInstrumentation()
.AddConsoleExporter());
RecordException
Configures a value indicating whether the exception will be recorded as ActivityEvent or not. See Semantic Conventions for Exceptions on Spans
using var tracerProvider = Sdk
.CreateTracerProviderBuilder()
.AddHangfireInstrumentation(options =>
{
options.RecordException = true;
})
.AddConsoleExporter()
.Build();
DisplayNameFunc
This option allows changing activity display name.
using var tracerProvider = Sdk
.CreateTracerProviderBuilder()
.AddHangfireInstrumentation(options =>
{
options.DisplayNameFunc = job => $"JOB {job.Id}";
})
.AddConsoleExporter()
.Build();
If not configured the default is
$"JOB {BackgroundJob.Job.Type.Name}.{BackgroundJob.Job.Method.Name}"
Filter
This option can be used to filter out activities based on the BackgroundJob
being executed. The Filter function should return true if the telemetry is
to be collected, and false if it should not.
The following code snippet shows how to use Filter to filter out traces for
job with a specified job id.
using var tracerProvider = Sdk
.CreateTracerProviderBuilder()
.AddHangfireInstrumentation(options =>
{
options.Filter = job => job.Id == "Filter this job";
})
.AddConsoleExporter()
.Build();
Metrics
This instrumentation library collects metrics following a POC/draft definition of workflow metrics defined as part of semantic-conventions/#1688. As those definitions evolve, changes including breaking ones will flow back to this implementation.
In Hangfire, the workflow semantic conventions are applied as follows:
- Each background job execution is modeled as a workflow task execution
- Workflow-level metrics track the complete lifecycle (including scheduled jobs)
- Execution-level metrics track the execution pipeline (enqueued jobs and later)
This approach provides comprehensive visibility into both job creation/scheduling and actual execution performance.
Enabling Metrics
Metrics are enabled by adding Hangfire instrumentation to the MeterProviderBuilder:
using OpenTelemetry.Metrics;
var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddHangfireInstrumentation()
.AddConsoleExporter()
.Build();
The above example also sets up the OpenTelemetry Console exporter, which requires
adding the package
OpenTelemetry.Exporter.Console
to the application.
Enabling both Traces and Metrics
To collect both traces and metrics from Hangfire:
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddHangfireInstrumentation()
.AddOtlpExporter())
.WithMetrics(metrics => metrics
.AddHangfireInstrumentation()
.AddOtlpExporter());
Metrics Configuration
Metrics behavior is configured through the
HangfireMetricsInstrumentationOptions class in the
OpenTelemetry.Metrics namespace.
RecordQueueLatency
By default, the instrumentation records only the execution phase duration
(time spent actually running the job). To also track the pending phase
duration (time spent waiting in the queue before execution), enable the
RecordQueueLatency option:
var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddHangfireInstrumentation(options =>
{
options.RecordQueueLatency = true;
})
.AddConsoleExporter()
.Build();
When enabled, workflow.execution.duration is recorded with
workflow.execution.state="pending" representing queue wait time, in addition
to workflow.execution.state="executing" for actual execution time.
Enabling RecordQueueLatency requires an additional database query per job
execution to retrieve the enqueue timestamp. In high-throughput scenarios,
this may impact performance.
Add using OpenTelemetry.Metrics; to access
HangfireMetricsInstrumentationOptions.
Available Metrics
The following metrics are emitted by this instrumentation:
Execution-level metrics track jobs that have entered the execution pipeline:
workflow.execution.outcome- Counter for completed executionsworkflow.execution.duration- Histogram for execution duration (pending and executing phases)workflow.execution.status- UpDownCounter for current execution stateworkflow.execution.errors- Counter for execution errors
Workflow-level metrics track the complete job lifecycle:
workflow.outcome- Counter for completed workflowsworkflow.status- UpDownCounter for current workflow state (including scheduled jobs)
workflow.execution.outcome
The number of task executions which have been initiated.
| Units | Instrument Type | Value Type |
|---|---|---|
{executions} |
Counter | Int64 |
This metric does NOT include the workflow.execution.state attribute, as
state differentiation is not needed for counting completed executions.
Attributes:
| Attribute | Type | Description | Requirement Level | Values |
|---|---|---|---|---|
workflow.task.name |
string | Name of the task (Hangfire job method) | Required | e.g., MyJob.Execute |
workflow.execution.result |
string | The result of executing the task | Required | success, failure |
workflow.platform.name |
string | The workflow platform being used | Recommended | hangfire |
error.type |
string | The type of error that occurred | Conditionally Required[1] | Exception type name |
[1]: Required if and only if the task execution failed.
workflow.execution.duration
Duration of an execution grouped by task, state, and result. Records duration for different execution phases:
- state=pending: Time spent waiting in queue (only when
RecordQueueLatencyis enabled) - state=executing: Time spent in actual execution
| Units | Instrument Type | Value Type |
|---|---|---|
s |
Histogram | Double |
The workflow.execution.state attribute is an extension to the current
semantic conventions to support measuring different execution phases
(pending vs executing). This attribute is being proposed for inclusion in
the official semantic conventions.
Attributes:
| Attribute | Type | Description | Requirement Level | Values |
|---|---|---|---|---|
workflow.task.name |
string | Name of the task (Hangfire job method) | Required | e.g., MyJob.Execute |
workflow.execution.result |
string | The result of executing the task | Required | success, failure |
workflow.execution.state |
string | The execution phase being measured | Required | pending, executing |
workflow.platform.name |
string | The workflow platform being used | Recommended | hangfire |
error.type |
string | The type of error that occurred | Conditionally Required[1] | Exception type name |
[1]: Required if and only if the task execution failed.
workflow.execution.status
The number of actively running tasks grouped by task and the current state.
| Units | Instrument Type | Value Type |
|---|---|---|
{executions} |
UpDownCounter | Int64 |
This metric tracks the current state of job executions. When a job transitions to a new state, the previous state is decremented and the new state is incremented.
Attributes:
| Attribute | Type | Description | Requirement Level | Values |
|---|---|---|---|---|
workflow.task.name |
string | Name of the task (Hangfire job method) | Required | e.g., MyJob.Execute |
workflow.execution.state |
string | Current state of the execution | Required | pending, executing, completed |
workflow.platform.name |
string | The workflow platform being used | Recommended | hangfire |
error.type |
string | The type of error that occurred | Conditionally Required[1] | Exception type name |
[1]: Required if and only if the task execution failed.
Hangfire State Mapping:
Hangfire job states are mapped to workflow semantic convention states as follows:
| Hangfire State | Workflow State |
|---|---|
| Scheduled, Enqueued, Awaiting | pending |
| Processing | executing |
| Succeeded, Failed, Deleted | completed |
workflow.execution.errors
The number of errors encountered in task executions.
| Units | Instrument Type | Value Type |
|---|---|---|
{error} |
Counter | Int64 |
Attributes:
| Attribute | Type | Description | Requirement Level | Values |
|---|---|---|---|---|
error.type |
string | The type of error that occurred | Required | Exception type name |
workflow.task.name |
string | Name of the task (Hangfire job method) | Required | e.g., MyJob.Execute |
workflow.platform.name |
string | The workflow platform being used | Recommended | hangfire |
workflow.outcome
The number of workflow instances which have been initiated. In Hangfire, this tracks individual job completions.
| Units | Instrument Type | Value Type |
|---|---|---|
{workflows} |
Counter | Int64 |
Attributes:
| Attribute | Type | Description | Requirement Level | Values |
|---|---|---|---|---|
workflow.definition.name |
string | Name of the workflow (Hangfire job method) | Required | e.g., MyJob.Execute |
workflow.result |
string | The result of the workflow | Required | success, failure |
workflow.trigger.type |
string | Type of trigger that initiated the workflow | Required | api, cron, schedule |
workflow.platform.name |
string | The workflow platform being used | Recommended | hangfire |
error.type |
string | The type of error that occurred | Conditionally Required[1] | Exception type name |
[1]: Required if and only if the workflow execution failed.
workflow.status
The number of actively running workflows grouped by definition and the current state.
| Units | Instrument Type | Value Type |
|---|---|---|
{workflows} |
UpDownCounter | Int64 |
This metric tracks the workflow lifecycle including jobs that haven't entered the execution pipeline yet (e.g., scheduled jobs waiting for their trigger time). When a workflow transitions to a new state, the previous state is decremented and the new state is incremented.
Attributes:
| Attribute | Type | Description | Requirement Level | Values |
|---|---|---|---|---|
workflow.definition.name |
string | Name of the workflow (Hangfire job method) | Required | e.g., MyJob.Execute |
workflow.state |
string | Current state of the workflow | Required | pending, executing, completed |
workflow.trigger.type |
string | Type of trigger that initiated the workflow | Required | api, cron, schedule |
workflow.platform.name |
string | The workflow platform being used | Recommended | hangfire |
error.type |
string | The type of error that occurred | Conditionally Required[1] | Exception type name |
[1]: Required if and only if the workflow execution failed.
Hangfire State Mapping:
Hangfire job states are mapped to workflow semantic convention states as follows:
| Hangfire State | Workflow State | Workflow Trigger Type |
|---|---|---|
| Scheduled | pending |
schedule |
| Enqueued, Awaiting (from cron) | pending |
cron |
| Enqueued, Awaiting (fire-and-forget) | pending |
api |
| Processing | executing |
(inherited from previous state) |
| Succeeded, Failed, Deleted | completed |
(inherited from previous state) |
Difference between workflow.status and workflow.execution.status:
workflow.status: Tracks the complete workflow lifecycle, including jobs that haven't started execution yet (e.g., scheduled jobs waiting for their trigger time). This provides visibility into jobs across all states.workflow.execution.status: Tracks only jobs that have entered the execution pipeline (enqueued or later). Scheduled jobs do NOT appear here until they become enqueued.
For example, a scheduled job appears in
workflow.status{state=pending, trigger.type=schedule} but NOT in
workflow.execution.status until it becomes enqueued. Once enqueued, it
appears in both metrics.
Semantic Conventions
This instrumentation follows the OpenTelemetry semantic conventions for workflows:
Attribute Usage
- workflow.platform.name: Always set to
"hangfire" - workflow.task.name / workflow.definition.name: Derived from the
Hangfire job method (e.g.,
ClassName.MethodName)workflow.task.nameis used for execution-level metrics (workflow.execution.*)workflow.definition.nameis used for workflow-level metrics (workflow.outcome,workflow.status)
- workflow.trigger.type: Identifies how the job was initiated
"cron"for recurring jobs"schedule"for delayed jobs (scheduled for future execution)"api"for fire-and-forget and continuation jobs- Only included on workflow-level metrics (
workflow.outcome,workflow.status), not on execution-level metrics (workflow.execution.*)
- workflow.execution.result / workflow.result: Set to
"success"when jobs complete without errors,"failure"when an exception is thrown - workflow.execution.state / workflow.state: Maps Hangfire states to
semantic convention states
workflow.execution.statetracks execution pipeline states (used inworkflow.execution.status,workflow.execution.duration)workflow.statetracks complete workflow lifecycle (used inworkflow.status)- See state mapping tables above for details
- error.type: Set to the full type name of the exception when a job fails
Workflow vs Execution Metrics
The instrumentation distinguishes between workflow-level and execution-level metrics:
Workflow-level metrics (workflow.outcome, workflow.status):
- Track the complete lifecycle of jobs, including pre-execution states (e.g., scheduled)
- Use
workflow.definition.name,workflow.state, andworkflow.trigger.type - Provide visibility into all jobs regardless of execution status
Execution-level metrics (workflow.execution.*):
- Track only jobs that have entered the execution pipeline (enqueued or later)
- Use
workflow.task.nameandworkflow.execution.state - Do NOT include
workflow.trigger.type(trigger is a workflow-level concept) - Provide detailed execution performance metrics
References
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Hangfire.Core (>= 1.7.0)
- Microsoft.Extensions.Options (>= 10.0.0)
- Newtonsoft.Json (>= 13.0.1)
- OpenTelemetry.Api.ProviderBuilderExtensions (>= 1.14.0 && < 2.0.0)
NuGet packages (11)
Showing the top 5 NuGet packages that depend on OpenTelemetry.Instrumentation.Hangfire:
| Package | Downloads |
|---|---|
|
Grafana.OpenTelemetry
Full Grafana distribution of OpenTelemetry .NET |
|
|
Keed_Digital.SharedKernel.Infrastructure
Package Description |
|
|
CyberEye.Observability.Lib
Package cung cấp các cấu hình về Observability, Monitoring, Telemetry như Metrics, Traces |
|
|
Dosaic.Plugins.Jobs.Hangfire
A plugin-first dotnet framework for rapidly building anything hosted in the web. |
|
|
Adliance.AspNetCore.Buddy.OpenTelemetry
Easy OpenTelemetry instrumentation for ASP.NET Core services. |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on OpenTelemetry.Instrumentation.Hangfire:
| Repository | Stars |
|---|---|
|
bitfoundation/bitplatform
Build all of your apps using what you already know and love ❤️
|
| Version | Downloads | Last Updated |
|---|---|---|
| 1.14.0-beta.2 | 7 | 1/14/2026 |
| 1.14.0-beta.1 | 48,699 | 11/13/2025 |
| 1.13.0-beta.1 | 31,718 | 10/23/2025 |
| 1.12.0-beta.1 | 516,570 | 6/23/2025 |
| 1.9.0-beta.1 | 1,396,940 | 10/2/2024 |
| 1.6.0-beta.1 | 2,365,651 | 12/20/2023 |
| 1.5.0-beta.1 | 919,227 | 6/23/2023 |
| 1.0.0-beta.4 | 947,459 | 12/16/2022 |
| 1.0.0-beta.3 | 113,915 | 10/26/2022 |
| 1.0.0-beta.2 | 295,730 | 7/13/2022 |
| 1.0.0-beta.1 | 23,453 | 6/3/2022 |