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

Add HttpContextCurrentExecutionSegmentsContainer #992

Conversation

russcam
Copy link
Contributor

@russcam russcam commented Oct 27, 2020

This commit adds an implementation of ICurrentExecutionSegmentsContainer that gets/sets the current transaction and span in HttpContext.Items, in addition to AsyncLocal<T>, making them available within the ExecutionContext of IIS.

AsyncLocal<T> are not propagated across the ASP.NET ExecutionContext running in IIS, resulting in the current transaction set in Application_BeginRequest returning as null from Agent.Tracer.CurrentTransaction in later subsequent IIS events, when such events execute asynchronously. ASP.NET does however propagate the current HttpContext through HttpContext.Current, allowing values to be stored in HttpContext.Items hashtable and shared across IIS events. The HttpContextCurrentExecutionSegmentsContainer uses both AsyncLocal<T> and HttpContext.Items to get/set the current transaction and span, allowing them to be available in both IIS events and async contexts. AsyncLocal<T> is still needed for places where HttpContext.Current is null, for example, DiagnosticSourceListeners running on a separate thread in an async flow; in such cases HttpContext.Current, which is set/get on CallContext.HostContext, is not propagated over async
flows.

It seems it may be possible for the current transaction and current span instances stored in AsyncLocal<T> and HttpContext.Items to be different in such scenarios where one is available but not the other on beginning
the transaction/span, and where availability is reversed on end. Unsure how likely this is in practice however, and using both AsyncLocal<T> and HttpContext.Items is the common approach in resolving this issue in < .NET 4.7.1.

For .NET 4.7.1, a new OnExecuteRequestStep method has been added to HttpApplication, to allow the execution context to be restored/saved:

https://devblogs.microsoft.com/dotnet/net-framework-4-7-1-asp-net-and-configuration-features/#asp-net-execution-step-feature

Closes #934
Closes #972

@apmmachine
Copy link
Collaborator

apmmachine commented Oct 27, 2020

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview

Expand to view the summary

Build stats

  • Build Cause: [russcam commented: jenkins run the tests please]

  • Start Time: 2020-10-29T05:46:23.411+0000

  • Duration: 58 min 14 sec

Test stats 🧪

Test Results
Failed 0
Passed 14212
Skipped 0
Total 14212

Steps errors 1

Expand to view the steps failures

  • Name: Build
    • Description: .ci/windows/dotnet.bat

    • Duration: 0 min 24 sec

    • Start Time: 2020-10-29T05:57:12.055+0000

    • log

This commit adds an implementation of ICurrentExecutionSegmentsContainer
that gets/sets the current transaction and span in HttpContext.Items,
in addition to AsyncLocal<T>, making them available within the
ExecutionContext of IIS.

AsyncLocal<T> are not propagated across the ASP.NET ExecutionContext
running in IIS, resulting in the current transaction set in Application_BeginRequest
returning as null from Agent.Tracer.CurrentTransaction in later subsequent
IIS events, when such events execute asynchronously. ASP.NET does
however propagate the current HttpContext through HttpContext.Current,
allowing values to be stored in HttpContext.Items hashtable and shared
across IIS events. The HttpContextCurrentExecutionSegmentsContainer
uses both AsyncLocal<T> and HttpContext.Items to get/set the current
transaction and span, allowing them to be available in both IIS
events and async contexts. AsyncLocal<T> is still needed for places
where HttpContext.Current is null, for example, DiagnosticSourceListeners
running on a separate thread.

It seems it may be possible for the current transaction and current
span instances stored in AsyncLocal<T> and HttpContext.Items to be different
in such scenarios where one is available but not the other on beginning
the transaction/span, and where availability is reversed on end. Unsure
how likely this is in practice however, and using both AsyncLocal<T> and
HttpContext.Items is the common approach in resolving this issue in < .NET 4.7.1.

For .NET 4.7.1, a new OnExecuteRequestStep method has been added to
HttpApplication, to allow the execution context to be restored/saved:

https://devblogs.microsoft.com/dotnet/net-framework-4-7-1-asp-net-and-configuration-features/#asp-net-execution-step-feature

Closes elastic#934
Closes elastic#972
@russcam russcam force-pushed the fix/httpcontext-current-execution-segments-container branch from 28278da to 6cc95b5 Compare October 28, 2020 04:51
@codecov-io
Copy link

codecov-io commented Oct 28, 2020

Codecov Report

Merging #992 into master will decrease coverage by 0.68%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #992      +/-   ##
==========================================
- Coverage   80.73%   80.04%   -0.69%     
==========================================
  Files         138      136       -2     
  Lines        6742     6335     -407     
==========================================
- Hits         5443     5071     -372     
+ Misses       1299     1264      -35     
Impacted Files Coverage Δ
src/Elastic.Apm/Config/ConfigSnapshotFromReader.cs 74.28% <0.00%> (-20.46%) ⬇️
...tic.Apm.SqlClient/SqlClientDiagnosticSubscriber.cs 80.00% <0.00%> (-20.00%) ⬇️
...DiagnosticListener/AspNetCoreDiagnosticListener.cs 81.39% <0.00%> (-10.61%) ⬇️
.../Elastic.Apm/Config/AbstractConfigurationReader.cs 85.51% <0.00%> (-5.84%) ⬇️
...nfig/AbstractConfigurationWithEnvFallbackReader.cs 90.00% <0.00%> (-4.74%) ⬇️
...lastic.Apm/BackendComm/BackendCommComponentBase.cs 92.30% <0.00%> (-3.85%) ⬇️
src/Elastic.Apm/Api/Tracer.cs 94.53% <0.00%> (-3.68%) ⬇️
...ic.Apm.Extensions.Hosting/HostBuilderExtensions.cs 82.85% <0.00%> (-3.45%) ⬇️
...c/Elastic.Apm.AspNetCore/ApmMiddlewareExtension.cs 30.55% <0.00%> (-2.78%) ⬇️
...tic.Apm.AspNetCore/WebRequestTransactionCreator.cs 79.02% <0.00%> (-0.49%) ⬇️
... and 12 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 85a2871...93dfd38. Read the comment docs.

Copy link
Contributor

@gregkalapos gregkalapos left a comment

Choose a reason for hiding this comment

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

Nice!

This commit adds an integration test for
HttpContextCurrentExecutionSegmentsContainer
that makes multiple concurrent requests
and asserts that the captured transactions
and span ids align with expectations.
@russcam
Copy link
Contributor Author

russcam commented Oct 29, 2020

jenkins run the tests please

@russcam russcam merged commit 30038c4 into elastic:master Oct 29, 2020
@russcam russcam added v1.7.0 enhancement New feature or request labels Nov 11, 2020
@russcam russcam deleted the fix/httpcontext-current-execution-segments-container branch December 17, 2020 04:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request v1.7.0
Projects
None yet
4 participants