Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/OpenTelemetry.Instrumentation.Hangfire/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Fix 'FailedToInjectActivityContext' when no ActivityContext exists.
([#2990](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2990))

## 1.12.0-beta.1

Released 2025-Jun-23
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,13 @@ public void OnCreating(CreatingContext creatingContext)
return;
}

ActivityContext contextToInject = default;
if (Activity.Current != null)
if (Activity.Current == null)
Comment thread
gao-artur marked this conversation as resolved.
Outdated
{
contextToInject = Activity.Current.Context;
return;
}

var activityContextData = new Dictionary<string, string>();
Propagators.DefaultTextMapPropagator.Inject(new PropagationContext(contextToInject, Baggage.Current), activityContextData, InjectActivityProperties);
Propagators.DefaultTextMapPropagator.Inject(new PropagationContext(Activity.Current.Context, Baggage.Current), activityContextData, InjectActivityProperties);
Comment thread
gao-artur marked this conversation as resolved.
Outdated
creatingContext.SetJobParameter(HangfireInstrumentationConstants.ActivityContextKey, activityContextData);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public async Task Should_Create_Activity()
using var tel = Sdk.CreateTracerProviderBuilder()
.AddHangfireInstrumentation()
.AddInMemoryExporter(exportedItems)
.SetSampler<AlwaysOnSampler>()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason, this test started to fail intermittently when I added a new test. I guess it's related to the static configuration in the HangfireFixture. Adding AlwaysOnSampler seems to fix/workaround it.

.Build();

// Act
Expand Down Expand Up @@ -170,6 +171,27 @@ public async Task Should_Respect_Filter_Option(string filter, bool shouldRecord)
Assert.Equal(shouldRecord, activity.ActivityTraceFlags.HasFlag(ActivityTraceFlags.Recorded));
}

[Fact]
public async Task Should_Not_Inject_Invalid_Context()
{
// Arrange
var exportedItems = new List<Activity>();
using var tel = Sdk.CreateTracerProviderBuilder()
.AddHangfireInstrumentation()
.AddInMemoryExporter(exportedItems)
.SetSampler<AlwaysOffSampler>()
.Build();

using var listener = new OpenTelemetryEventListener();

// Act
var jobId = BackgroundJob.Enqueue<TestJob>(x => x.Execute());
await this.WaitJobProcessedAsync(jobId, 5);

// Assert
Assert.All(listener.Messages, args => Assert.NotEqual("FailedToInjectActivityContext", args.EventName));
}

private async Task WaitJobProcessedAsync(string jobId, int timeToWaitInSeconds)
{
var timeout = TimeSpan.FromSeconds(timeToWaitInSeconds);
Expand Down
Comment thread
gao-artur marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.Diagnostics.Tracing;

namespace OpenTelemetry.Instrumentation.Hangfire.Tests;

internal class OpenTelemetryEventListener : EventListener
{
private const string EventSourceName = "OpenTelemetry-Api";

private readonly Queue<EventWrittenEventArgs> events = new();
private readonly AutoResetEvent eventWritten = new(false);
private EventSource? apiEventSource;

public IEnumerable<EventWrittenEventArgs> Messages
{
get
{
if (this.events.Count == 0)
{
this.eventWritten.WaitOne(TimeSpan.FromSeconds(3));
}

while (this.events.Count != 0)
{
yield return this.events.Dequeue();
}
}
}

public override void Dispose()
{
if (this.apiEventSource != null)
{
this.DisableEvents(this.apiEventSource);
}

base.Dispose();
}

protected override void OnEventSourceCreated(EventSource eventSource)
{
if (eventSource.Name == EventSourceName)
{
this.apiEventSource = eventSource;
this.EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.All);
}

base.OnEventSourceCreated(eventSource);
}

protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
if (eventData.EventSource.Name == EventSourceName)
{
this.events.Enqueue(eventData);
this.eventWritten.Set();
}
}
}
Loading