Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lost Baggage: Fix TelemetryHttpModule losing Baggage when switching from native to managed threads #2314

Merged

Conversation

CodeBlanch
Copy link
Member

@CodeBlanch CodeBlanch commented Sep 4, 2021

Changes

TelemetryHttpModule will now restore Baggage in addition to Activity when it detects that it has been lost.

Public API Changes

    // New interface
    public interface IRuntimeContextSlotValueAccessor
    {
        object Value { get; set; }
    }

Added IRuntimeContextSlotValueAccessor so I could expose a non-dynamic method for accessing the value stored in a RuntimeContextSlot<T> as an object. I went with the interface because I think adding abstract object Value { get; set ;} on RuntimeContextSlot<T> would be breaking.

AsyncLocalRuntimeContextSlot<T>, RemotingRuntimeContextSlot<T>, & ThreadLocalRuntimeContextSlot<T> now implement IRuntimeContextSlotValueAccessor.

TODOs

  • CHANGELOG.md updated for non-trivial changes
  • Changes in public API reviewed

@CodeBlanch CodeBlanch requested a review from a team September 4, 2021 18:40
@@ -291,9 +291,8 @@ private static void HookOrProcessResult(HttpWebRequest request)

private static void ProcessResult(IAsyncResult asyncResult, AsyncCallback asyncCallback, Activity activity, object result, bool forceResponseCopy)
{
// We could be executing on a different thread now so set the activity.
Debug.Assert(Activity.Current == null || Activity.Current == activity, "There was an unexpected active Activity on the result thread.");
Copy link
Member Author

Choose a reason for hiding this comment

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

When Activity is lost (more precisely, ExecutionContext is lost) in the HttpModule we restore the root (HttpIn) Activity. That makes this assert invalid. I tried to fix the HttpModule so that it restores the Activity that was last running, but it is impossible to retrieve do to the way ExecutionContext works. It isn't an issue to remove the assert, but it is unnerving. Any instrumentation running in IIS reliant on Activity.Current could run into trouble.

@codecov
Copy link

codecov bot commented Sep 4, 2021

Codecov Report

Merging #2314 (a0f4268) into main (3cc0f7e) will increase coverage by 0.02%.
The diff coverage is 51.85%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2314      +/-   ##
==========================================
+ Coverage   81.03%   81.06%   +0.02%     
==========================================
  Files         228      228              
  Lines        7289     7305      +16     
==========================================
+ Hits         5907     5922      +15     
- Misses       1382     1383       +1     
Impacted Files Coverage Δ
...elemetry.Api/Context/RemotingRuntimeContextSlot.cs 0.00% <0.00%> (ø)
...metry.Api/Context/ThreadLocalRuntimeContextSlot.cs 0.00% <0.00%> (ø)
....AspNet.TelemetryHttpModule/TelemetryHttpModule.cs 5.26% <14.28%> (+0.61%) ⬆️
src/OpenTelemetry.Api/Context/RuntimeContext.cs 76.31% <60.00%> (-2.86%) ⬇️
...emetry.Api/Context/AsyncLocalRuntimeContextSlot.cs 100.00% <100.00%> (ø)
...ation.AspNet.TelemetryHttpModule/ActivityHelper.cs 84.21% <100.00%> (+0.87%) ⬆️
...ter.ZPages/Implementation/ZPagesActivityTracker.cs 97.14% <0.00%> (-2.86%) ⬇️
...Telemetry/Internal/SelfDiagnosticsEventListener.cs 97.63% <0.00%> (+0.78%) ⬆️

@reyang
Copy link
Member

reyang commented Sep 10, 2021

Added IRuntimeContextSlotValueAccessor so I could expose a non-dynamic method for accessing the value stored in a RuntimeContextSlot<T> as an object. I went with the interface because I think adding abstract object Value { get; set ;} on RuntimeContextSlot<T> would be breaking.

Would a non-abstract version work? e.g. the default object Value { get; set; } on RuntimeContextSlot<T> would throw something like InvalidOperationException (or NotImplementedException, probably doesn't quite fit though).

@CodeBlanch
Copy link
Member Author

@reyang

Would a non-abstract version work?

It would yes. Something like this on the base...

public virtual object Value 
{
   get => throw new NotSupportedException();
   set => throw new NotSupportedException();
}

But it isn't as nice, IMO. Because then callers have to know about the throw behavior and put in a catch. For non-overridden implementations that evaluation will always be a throw, which is very expensive. I think the interface test (if (slot is IRuntimeContextSlotValueAccessor runtimeContextSlotValueAccessor)) is much nicer and faster.

I got the idea from ISupportExternalScope which I think was added after the logging API was introduced as a way to opt-into externally managed scopes in a non-breaking way.

Copy link
Member

@reyang reyang left a comment

Choose a reason for hiding this comment

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

LGTM.

@CodeBlanch CodeBlanch merged commit 2df1a62 into open-telemetry:main Sep 15, 2021
@CodeBlanch CodeBlanch deleted the TelemetryHttpModule-lost-baggage branch September 15, 2021 18:04
{
Task.Yield();

Assert.Null(Activity.Current);
Copy link
Member Author

Choose a reason for hiding this comment

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

@stephentoub Activity.Current uses an AsyncLocal. Occasionally this test fails only on net461. Can you Miyagi me on this and point me in the right direction? There is a similar test right above which I haven't seen fail.

What I'm trying to do is get some code running on a thread where ExecutionContext has no local values so I can verify my code properly restores things when we run into that situation. We see this in the wild when running on IIS and it decides to jump threads.

Copy link
Member Author

Choose a reason for hiding this comment

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

@GrabYourPitchforks Hey anything jump out at you on this test? Sorry to bug, I'm scratching my head on this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants