Adding azure frontdoor support#8861
Conversation
| try | ||
| { | ||
|
|
||
| var startTimeHeaderValue = InferredProxyHeaders.StartTime ? |
There was a problem hiding this comment.
You're getting a compiler error here because InferredProxyHeaders.StartTime is not a bool, which you need to use the ?: operator.
|
|
||
| if (string.Equals(proxyName, AzureFrontDoorHeaderValue, StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| _azureCoordinator ??= new InferredProxyCoordinator(new AzureFrontDoorExtractor(), new Az()); |
There was a problem hiding this comment.
You're getting a compiler error with new Az().
There was a problem hiding this comment.
Yeah -- I realize I started to write the template but hadn't created the span factory.... a reason why this was in draft. I fixed this.
BenchmarksBenchmark execution time: 2026-07-03 01:46:42 Comparing candidate commit 9696d6a in PR branch Found 2 performance improvements and 1 performance regressions! Performance is the same for 69 metrics, 0 unstable metrics, 60 known flaky benchmarks, 66 flaky benchmarks without significant changes.
|
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (8861) and master. ✅ No regressions detected - check the details below Full Metrics ComparisonFakeDbCommand
HttpMessageHandler
Comparison explanationExecution-time benchmarks measure the whole time it takes to execute a program, and are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are highlighted in **red**. The following thresholds were used for comparing the execution times:
Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard. Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph). Duration chartsFakeDbCommand (.NET Framework 4.8)gantt
title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8861) - mean (70ms) : 68, 73
master - mean (71ms) : 67, 74
section Bailout
This PR (8861) - mean (77ms) : 73, 81
master - mean (74ms) : 73, 75
section CallTarget+Inlining+NGEN
This PR (8861) - mean (1,084ms) : 1034, 1134
master - mean (1,087ms) : 1042, 1132
FakeDbCommand (.NET Core 3.1)gantt
title Execution time (ms) FakeDbCommand (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8861) - mean (112ms) : 105, 118
master - mean (109ms) : 105, 113
section Bailout
This PR (8861) - mean (113ms) : 109, 118
master - mean (110ms) : 108, 112
section CallTarget+Inlining+NGEN
This PR (8861) - mean (772ms) : 749, 796
master - mean (777ms) : 754, 800
FakeDbCommand (.NET 6)gantt
title Execution time (ms) FakeDbCommand (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8861) - mean (100ms) : 95, 105
master - mean (98ms) : 94, 102
section Bailout
This PR (8861) - mean (98ms) : 95, 102
master - mean (98ms) : 96, 99
section CallTarget+Inlining+NGEN
This PR (8861) - mean (937ms) : 901, 972
master - mean (945ms) : 902, 987
FakeDbCommand (.NET 8)gantt
title Execution time (ms) FakeDbCommand (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8861) - mean (94ms) : 91, 96
master - mean (96ms) : 91, 101
section Bailout
This PR (8861) - mean (99ms) : 94, 104
master - mean (99ms) : 94, 103
section CallTarget+Inlining+NGEN
This PR (8861) - mean (815ms) : 778, 853
master - mean (816ms) : 779, 853
HttpMessageHandler (.NET Framework 4.8)gantt
title Execution time (ms) HttpMessageHandler (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8861) - mean (204ms) : 198, 210
master - mean (203ms) : 197, 209
section Bailout
This PR (8861) - mean (209ms) : 205, 212
master - mean (207ms) : 202, 211
section CallTarget+Inlining+NGEN
This PR (8861) - mean (1,217ms) : 1172, 1262
master - mean (1,213ms) : 1164, 1261
HttpMessageHandler (.NET Core 3.1)gantt
title Execution time (ms) HttpMessageHandler (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8861) - mean (293ms) : 286, 301
master - mean (289ms) : 281, 297
section Bailout
This PR (8861) - mean (295ms) : 290, 301
master - mean (291ms) : 284, 298
section CallTarget+Inlining+NGEN
This PR (8861) - mean (977ms) : 958, 996
master - mean (984ms) : 960, 1008
HttpMessageHandler (.NET 6)gantt
title Execution time (ms) HttpMessageHandler (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8861) - mean (287ms) : 279, 295
master - mean (286ms) : 280, 291
section Bailout
This PR (8861) - mean (288ms) : 280, 295
master - mean (287ms) : 282, 293
section CallTarget+Inlining+NGEN
This PR (8861) - mean (1,180ms) : 1136, 1223
master - mean (1,176ms) : 1134, 1219
HttpMessageHandler (.NET 8)gantt
title Execution time (ms) HttpMessageHandler (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8861) - mean (285ms) : 279, 291
master - mean (286ms) : 277, 294
section Bailout
This PR (8861) - mean (286ms) : 281, 292
master - mean (286ms) : 279, 292
section CallTarget+Inlining+NGEN
This PR (8861) - mean (1,049ms) : 1006, 1092
master - mean (1,051ms) : 1004, 1097
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Summary of changes
This PR implements Azure FrontDoor. This is an upstream proxy service that Azure offers.
Azure Front Door
Azure Front Door is a edge computing CDN proxy that provides load balancing and regional routing to azure web apps and containers. Customers use this ensure their application has a single entry point across multiple regions.
One special case is that azure front door lacks the ability to insert timestamps in the headers. This may change in the future but due to this I modified the process to add a timespan at header detection which means that the accuracy of the timeline decreases but we still get a usable span and the proxy is represented. If this does change and the ability to insert timestamps does get implemented on Azure's side the code is thoughtful enough to not overwrite an existing timestamp header and making it less of an urgent change to remove the code I am introducing.
Reason for change
This is a proxy service from Azure. It would be great to provide observability coverage for customers to see in their traces.
Implementation details
I added Azure Front Door support to the inferred proxy span pipeline, following the same pattern already established for Azure API Management and AWS API Gateway.
The core of the work is two new classes: AzureFrontDoorExtractor and AzureFrontDoorSpanFactory. The extractor reads the standard inferred proxy headers (start time, domain, HTTP method, path, region) from the incoming request and returns an InferredProxyData struct. Unlike APIM and API Gateway, Azure Front Door does not inject a timestamp header, so if one isn't present the extractor synthesizes a start time from the current time — but if a start time header is present it will be used instead. The span factory takes that data and creates a web-type span with operation name azure.frontdoor, setting resource name, HTTP tags, region, and using the domain name as the service name.
I wired these into InferredProxySpanHelper so that when the x-dd-proxy header value is azure-fd, the coordinator is initialized with the Front Door extractor and factory and produces the inferred proxy scope.
I also updated AzureFunctionsCommon to recognize azure.frontdoor as a proxy operation name — same as it already does for azure.apim — so that Azure Functions doesn't overwrite the inferred proxy span as the root.
Finally, I added the constant AzureFrontDoorName = "azure.frontdoor" to AzureFunctionsConstants, and wrote unit tests for both the extractor and the span factory covering the happy path, missing optional headers, and invalid/missing start time.
Test coverage
AzureFrontDoorExtractorTests has 7 tests total (4 via [Theory], 3 [Fact]):
I verify that when all headers are present and valid, TryExtract returns true and correctly populates ProxyName, StartTime, HttpMethod, Path, Stage, and Region.
I verify that when only the required start time header is present (optional headers removed), extraction still succeeds and the optional fields come back null.
I cover 4 invalid start time cases (null, empty string, non-numeric, and an overflowing value) via a theory — all should return false with a default InferredProxyData.
I verify that a completely missing start time header also returns false.
AzureFrontDoorSpanFactoryTests has 1 test:
I verify that CreateSpan produces a span with the correct operation name (azure.frontdoor), resource name (GET /api/v1/users), span type (web), start time, and all expected tags (http.method, component, http.url, http.route).
Other details