Skip to content

[AspNetCore] Optimize HttpInListener#4090

Open
martincostello wants to merge 2 commits intoopen-telemetry:mainfrom
martincostello:optimize-HttpInListener
Open

[AspNetCore] Optimize HttpInListener#4090
martincostello wants to merge 2 commits intoopen-telemetry:mainfrom
martincostello:optimize-HttpInListener

Conversation

@martincostello
Copy link
Copy Markdown
Member

@martincostello martincostello commented Apr 10, 2026

Changes

While looking at some profiles for an OTel instrumented application of mine, I noticed that HttpInListener.OnStopActivity() came up in the top 5 OTel-related samples.

Add optimizations, recommended by Copilot, to reduce allocations in HttpInListener.OnStopActivity():

  • Cache activity display names.
  • Uses slices instead of Regex.
  • Avoid enum reflection.
  • Use custom property to track source of instrumentation.
  • Avoid duplicating or redundant work.

See #4090 (comment) for benchmark results.

Merge requirement checklist

  • CONTRIBUTING guidelines followed (license requirements, nullable enabled, static analysis, etc.)
  • Unit tests added/updated
  • Appropriate CHANGELOG.md files updated for non-trivial changes
  • Changes in public API reviewed (if applicable)

@github-actions github-actions Bot added the comp:instrumentation.aspnetcore Things related to OpenTelemetry.Instrumentation.AspNetCore label Apr 10, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 10, 2026

Codecov Report

❌ Patch coverage is 87.36842% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.69%. Comparing base (886d9a7) to head (2381014).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...tation.AspNetCore/Implementation/HttpInListener.cs 83.56% 12 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4090      +/-   ##
==========================================
+ Coverage   75.62%   75.69%   +0.06%     
==========================================
  Files         455      455              
  Lines       18238    18278      +40     
==========================================
+ Hits        13793    13836      +43     
+ Misses       4445     4442       -3     
Flag Coverage Δ
unittests-Contrib.Shared.Tests 89.92% <100.00%> (+0.40%) ⬆️
unittests-Exporter.Geneva 54.82% <ø> (-0.16%) ⬇️
unittests-Exporter.InfluxDB 95.81% <ø> (ø)
unittests-Exporter.OneCollector 94.63% <ø> (ø)
unittests-Extensions 90.78% <ø> (ø)
unittests-Extensions.Enrichment 100.00% <ø> (ø)
unittests-Extensions.Enrichment.AspNetCore 86.27% <ø> (ø)
unittests-Extensions.Enrichment.Http 94.33% <ø> (ø)
unittests-Instrumentation.AWS 85.22% <ø> (ø)
unittests-Instrumentation.AspNet 78.04% <ø> (ø)
unittests-Instrumentation.AspNetCore 78.64% <83.56%> (+6.53%) ⬆️
unittests-Instrumentation.Cassandra 92.85% <ø> (ø)
unittests-Instrumentation.ConfluentKafka 78.52% <ø> (ø)
unittests-Instrumentation.ElasticsearchClient 80.60% <ø> (ø)
unittests-Instrumentation.EntityFrameworkCore 81.39% <ø> (ø)
unittests-Instrumentation.EventCounters 77.67% <ø> (ø)
unittests-Instrumentation.GrpcCore 91.34% <ø> (ø)
unittests-Instrumentation.GrpcNetClient 79.09% <ø> (ø)
unittests-Instrumentation.Hangfire 88.91% <ø> (ø)
unittests-Instrumentation.Http 74.62% <ø> (ø)
unittests-Instrumentation.Owin 88.62% <ø> (ø)
unittests-Instrumentation.Process 100.00% <ø> (ø)
unittests-Instrumentation.Quartz 78.76% <ø> (ø)
unittests-Instrumentation.Remoting 66.06% <ø> (ø)
unittests-Instrumentation.Runtime 100.00% <ø> (ø)
unittests-Instrumentation.ServiceFabricRemoting 40.83% <ø> (ø)
unittests-Instrumentation.SqlClient 84.36% <ø> (ø)
unittests-Instrumentation.StackExchangeRedis 93.78% <ø> (ø)
unittests-Instrumentation.Wcf 81.94% <ø> (ø)
unittests-OpAmp.Client 83.84% <ø> (-0.42%) ⬇️
unittests-PersistentStorage 67.83% <ø> (-1.47%) ⬇️
unittests-Resources.AWS 74.49% <ø> (ø)
unittests-Resources.Azure 88.31% <ø> (ø)
unittests-Resources.Container 67.34% <ø> (ø)
unittests-Resources.Gcp 71.42% <ø> (ø)
unittests-Resources.Host 72.26% <ø> (ø)
unittests-Resources.OperatingSystem 76.98% <ø> (ø)
unittests-Resources.Process 90.47% <ø> (ø)
unittests-Resources.ProcessRuntime 79.59% <ø> (ø)
unittests-Sampler.AWS 96.39% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/Shared/GrpcTagHelper.cs 98.07% <100.00%> (+0.03%) ⬆️
src/Shared/RequestDataHelper.cs 83.33% <100.00%> (+8.33%) ⬆️
...tation.AspNetCore/Implementation/HttpInListener.cs 87.97% <83.56%> (+13.30%) ⬆️

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added infra Infra work - CI/CD, code coverage, linters dependencies Pull requests that update a dependency file perf Performance related labels Apr 11, 2026
@martincostello martincostello force-pushed the optimize-HttpInListener branch from 4cd813b to 204d65f Compare April 14, 2026 14:40
@github-actions github-actions Bot removed infra Infra work - CI/CD, code coverage, linters dependencies Pull requests that update a dependency file labels Apr 14, 2026
@martincostello martincostello added the keep-open Prevents issues and pull requests being closed as stale label Apr 20, 2026
@martincostello

This comment was marked as outdated.

@martincostello martincostello marked this pull request as ready for review April 22, 2026 16:40
@martincostello martincostello requested a review from a team as a code owner April 22, 2026 16:40
Copilot AI review requested due to automatic review settings April 22, 2026 16:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Optimizes ASP.NET Core inbound instrumentation hot paths (notably HttpInListener.OnStopActivity) to reduce allocations and redundant work, including improved gRPC handling and display-name caching.

Changes:

  • Adds caching for HTTP route-based activity display names and consolidates HTTP method display-name/tag setting.
  • Reworks gRPC method parsing and gRPC attribute enrichment to avoid regex/enum reflection and reduce tag lookups.
  • Adds/updates tests covering display name caching and gRPC attribute behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs Allocation-reducing refactor for request path handling, enrichment guards, gRPC tag extraction, and gRPC-derived attribute caching.
src/Shared/RequestDataHelper.cs Adds route display-name caching and a helper to set both display name and HTTP method tags together.
src/Shared/GrpcTagHelper.cs Replaces regex parsing with span-based parsing and avoids enum reflection for status validation.
src/Shared/GrpcStatusCanonicalCode.cs Introduces a max-value sentinel for status validation.
test/OpenTelemetry.Instrumentation.AspNetCore.Tests/GrpcTests.cs New tests validating gRPC attribute enrichment behavior in HttpInListener.OnStopActivity.
test/OpenTelemetry.Contrib.Shared.Tests/RequestDataHelperTests.cs Adds tests for display name generation, HTTP method tagging, and caching behavior.
test/OpenTelemetry.Contrib.Shared.Tests/GrpcTagHelperTests.cs Expands coverage to include invalid negative gRPC status codes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/OpenTelemetry.Instrumentation.AspNetCore.Tests/GrpcTests.cs
Comment thread src/Shared/RequestDataHelper.cs Outdated
Comment thread src/Shared/GrpcStatusCanonicalCode.cs
Add optimizations, recommended by Copilot, to reduce allocations in `HttpInListener.OnStopActivity()`:

- Cache activity display names.
- Uses slices instead of `Regex`.
- Avoid enum reflection.
- Null check delegates to avoid try-catch blocks.
- Use SetCustomProperty to check for who made the instrumentation.
- Avoid running gRPC-related code for HTTP 1.1.
- Avoid additional check for the normalized HTTP method.
- Use pattern matching on nullable.
@martincostello martincostello force-pushed the optimize-HttpInListener branch from 213c8a4 to 2629aa6 Compare May 7, 2026 09:32
@martincostello martincostello marked this pull request as ready for review May 7, 2026 10:36
@martincostello
Copy link
Copy Markdown
Member Author

Will do a final round of benchmark comparisons shortly.

@martincostello
Copy link
Copy Markdown
Member Author

Benchmark Results

Copilot Summary

optimize-HttpInListener is a modest net win versus main: across all 8 benchmark cases, mean duration is 0.9786x the baseline (2.14% faster) and allocations are
0.9831x the baseline (1.69% lower).

Benchmark Duration ratio (opt/main) Duration impact Memory ratio (opt/main) Memory impact
HttpGet, None 0.9190x 8.10% faster 1.0000x no change
GrpcGet, None 0.9544x 4.56% faster 1.0000x no change
HttpGet, Traces 1.0056x 0.56% slower 0.9964x 0.36% lower
GrpcGet, Traces 0.9855x 1.45% faster 0.9531x 4.69% lower
HttpGet, Metrics 0.9695x 3.05% faster 1.0000x no change
GrpcGet, Metrics 1.0037x 0.37% slower 1.0000x no change
HttpGet, Traces + Metrics 0.9745x 2.55% faster 0.9967x 0.33% lower
GrpcGet, Traces + Metrics 0.9757x 2.43% faster 0.9535x 4.65% lower
Scope Duration ratio (opt/main) Duration impact Memory ratio (opt/main) Memory impact
HttpGet average 0.9728x 2.72% faster 0.9981x 0.19% lower
GrpcGet average 0.9804x 1.96% faster 0.9750x 2.50% lower
Overall average 0.9786x 2.14% faster 0.9831x 1.69% lower

By workload:

  • HttpGet: duration 0.9728x (2.72% faster), memory 0.9981x (0.19% lower)
  • GrpcGet: duration 0.9804x (1.96% faster), memory 0.9750x (2.50% lower)

The biggest gain is plain HttpGet with no instrumentation enabled, and the clearest allocation improvement is on the gRPC trace-enabled cases. The only regressions
are small duration increases in HttpGet, Traces and GrpcGet, Metrics.

BenchmarkDotNet Results

Click to expand

main

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8246/25H2/2025Update/HudsonValley2)
13th Gen Intel Core i7-13700H 2.90GHz, 1 CPU, 20 logical and 14 physical cores
.NET SDK 10.0.203
  [Host]    : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v3
  .NET 10.0 : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v3

Job=.NET 10.0  Runtime=.NET 10.0  Toolchain=net10.0  
Method EnableInstrumentation Mean Error StdDev Gen0 Allocated
HttpGet None 5.260 μs 0.0941 μs 0.0786 μs 0.5493 7.3 KB
GrpcGet None 25.836 μs 0.4473 μs 0.4393 μs 1.0986 13.86 KB
HttpGet Traces 8.757 μs 0.1934 μs 0.5642 μs 0.6104 8.26 KB
GrpcGet Traces 29.576 μs 0.4614 μs 0.4316 μs 1.2207 15.99 KB
HttpGet Metrics 7.444 μs 0.1748 μs 0.5128 μs 0.6104 7.43 KB
GrpcGet Metrics 28.368 μs 0.4241 μs 0.3967 μs 0.9766 13.99 KB
HttpGet Traces, Metrics 12.019 μs 0.2781 μs 0.8112 μs 0.7324 9.11 KB
GrpcGet Traces, Metrics 30.748 μs 0.4955 μs 0.4635 μs 1.2207 16.13 KB

This PR

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.8246/25H2/2025Update/HudsonValley2)
13th Gen Intel Core i7-13700H 2.90GHz, 1 CPU, 20 logical and 14 physical cores
.NET SDK 10.0.203
  [Host]    : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v3
  .NET 10.0 : .NET 10.0.7 (10.0.7, 10.0.726.21808), X64 RyuJIT x86-64-v3

Job=.NET 10.0  Runtime=.NET 10.0  Toolchain=net10.0  
Method EnableInstrumentation Mean Error StdDev Gen0 Allocated
HttpGet None 4.834 μs 0.0956 μs 0.1402 μs 0.5493 7.3 KB
GrpcGet None 24.658 μs 0.4746 μs 0.6653 μs 1.0986 13.86 KB
HttpGet Traces 8.806 μs 0.1913 μs 0.5365 μs 0.6104 8.23 KB
GrpcGet Traces 29.146 μs 0.3107 μs 0.2754 μs 1.2207 15.24 KB
HttpGet Metrics 7.217 μs 0.1587 μs 0.4628 μs 0.6104 7.43 KB
GrpcGet Metrics 28.473 μs 0.5627 μs 0.7888 μs 0.9766 13.99 KB
HttpGet Traces, Metrics 11.712 μs 0.3177 μs 0.9366 μs 0.7324 9.08 KB
GrpcGet Traces, Metrics 30.002 μs 0.3535 μs 0.3307 μs 1.2207 15.38 KB

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:instrumentation.aspnetcore Things related to OpenTelemetry.Instrumentation.AspNetCore keep-open Prevents issues and pull requests being closed as stale perf Performance related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants