Skip to content

[ConfigRegistry] 4/6 Aliases handling and analyzers to prevent using any string key#7689

Merged
anna-git merged 8 commits intomasterfrom
anna/config-inversion-configuration-analyzers-4
Dec 9, 2025
Merged

[ConfigRegistry] 4/6 Aliases handling and analyzers to prevent using any string key#7689
anna-git merged 8 commits intomasterfrom
anna/config-inversion-configuration-analyzers-4

Conversation

@anna-git
Copy link
Contributor

@anna-git anna-git commented Oct 21, 2025

Context

Part of Configuration Inversion (Step 4) - Stack progress:

  1. #7548 - Add GitLab step and JSON configuration file
  2. #7688 - Cleanup configuration / platform keys + analyzers
  3. #7698 - Source generator for ConfigurationKeys
  4. #7689 - Aliases handling and analyzers (this PR)
  5. #7931 - Replace manual ConfigurationKeys with generated version
  6. #7932- Forbid use of System.Environment methods and adapt everywhere

Summary

Adds source generator for configuration key aliases, integrates alias resolution into ConfigurationBuilder, and adds Roslyn analyzers to enforce proper configuration key usage.

Changes

Alias Source Generator:

  • ConfigKeyAliasesSwitcherGenerator reads aliases from supported-configurations.json
  • Auto-generates switch statements to resolve primary keys from aliases
  • Generated for all target frameworks (net461, netstandard2.0, netcoreapp3.1, net6.0)

ConfigurationBuilder Improvements:

  • Integrated alias resolution directly into ConfigurationBuilder.WithKeys()
  • Removed manual fallback overloads throughout codebase
  • Added GetKeyWithAlias() method to IConfigurationSource interface

IntegrationSettings Special Handling:

  • Updated to use pattern-based key construction (e.g., DD_TRACE_{INTEGRATION}_ENABLED)
  • Simplified configuration reading by leveraging alias system

Roslyn Analyzers:

  • DD0007: PlatformKeysAnalyzer - Enforces use of PlatformKeys for external platform environment variables
  • DD0008: ConfigurationBuilderWithKeysAnalyzer - Enforces use of ConfigurationKeys/PlatformKeys constants in ConfigurationBuilder.WithKeys() calls

Special Cases:

  • Fixed DatadogLoggingFactory to handle deprecated DD_TRACE_LOG_PATH with proper analyzer suppression
  • Updated configuration tests to work with alias resolution

Motivation

Completes configuration inversion by:

  • Auto-generating alias resolution from supported-configurations.json
  • Eliminating manual fallback chains
  • Enforcing compile-time validation of configuration keys
  • Preventing hardcoded strings and typos

Test Coverage

  • Added ConfigKeyAliasesSwitcherGeneratorTests with comprehensive test coverage
  • Added PlatformKeysAnalyzerTests with 146 lines of tests
  • Added ConfigurationBuilderWithKeysAnalyzerTests with 538 lines of tests
  • Updated existing configuration tests for alias support
  • All tests pass with new alias system

Related Work

Builds on #7548 (configuration registry), #7688 (PlatformKeys separation), and #7698 (source generator for ConfigurationKeys).

@anna-git anna-git marked this pull request as ready for review October 21, 2025 16:24
@anna-git anna-git requested review from a team as code owners October 21, 2025 16:24
@anna-git anna-git requested a review from link04 October 21, 2025 16:24
@anna-git anna-git changed the base branch from master to anna/config-inversion-configuration-aliases-switch-3 October 21, 2025 16:25
@anna-git anna-git marked this pull request as draft October 21, 2025 16:25
@anna-git anna-git changed the title anna/config-inversion-configuration-analyzers-4 [Config registry] Analyzers for ConfigurationBuilder, ConfigurationKeys, PlatformKeys Oct 21, 2025
@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch from be32003 to c983088 Compare October 21, 2025 16:41
@anna-git anna-git force-pushed the anna/config-inversion-configuration-analyzers-4 branch from acaf6cf to c1f7943 Compare October 21, 2025 16:42
@pr-commenter
Copy link

pr-commenter bot commented Oct 21, 2025

Benchmarks

Benchmarks Report for benchmark platform 🐌

Benchmarks for #7689 compared to master:

  • 1 benchmarks are faster, with geometric mean 1.150
  • 1 benchmarks are slower, with geometric mean 1.163
  • 1 benchmarks have fewer allocations
  • 4 benchmarks have more allocations

The following thresholds were used for comparing the benchmark speeds:

  • Mann–Whitney U test with statistical test for significance of 5%
  • Only results indicating a difference greater than 10% and 0.3 ns are considered.

Allocation changes below 0.5% are ignored.

Benchmark details

Benchmarks.Trace.ActivityBenchmark - Same speed ✔️ More allocations ⚠️

More allocations ⚠️ in #7689

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.ActivityBenchmark.StartStopWithChild‑net472 5.93 KB 6 KB 67 B 1.13%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartStopWithChild net6.0 10.9μs 60ns 350ns 0 0 0 5.5 KB
master StartStopWithChild netcoreapp3.1 13.6μs 50ns 194ns 0 0 0 5.71 KB
master StartStopWithChild net472 22.7μs 123ns 675ns 1.03 0.413 0.103 5.93 KB
#7689 StartStopWithChild net6.0 10.9μs 60.3ns 357ns 0 0 0 5.5 KB
#7689 StartStopWithChild netcoreapp3.1 13.6μs 70.3ns 330ns 0 0 0 5.71 KB
#7689 StartStopWithChild net472 22μs 119ns 810ns 0.945 0.315 0 6 KB
Benchmarks.Trace.AgentWriterBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 1.28ms 145ns 543ns 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 1.38ms 540ns 2.09μs 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces net472 1.7ms 1.57μs 5.88μs 0 0 0 3.26 KB
#7689 WriteAndFlushEnrichedTraces net6.0 1.27ms 440ns 1.7μs 0 0 0 2.7 KB
#7689 WriteAndFlushEnrichedTraces netcoreapp3.1 1.37ms 175ns 677ns 0 0 0 2.7 KB
#7689 WriteAndFlushEnrichedTraces net472 1.71ms 257ns 962ns 0 0 0 3.26 KB
Benchmarks.Trace.Asm.AppSecBodyBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master AllCycleSimpleBody net6.0 1.14μs 5.88ns 27.6ns 0 0 0 1.22 KB
master AllCycleSimpleBody netcoreapp3.1 1.38μs 7.63ns 47.6ns 0 0 0 1.2 KB
master AllCycleSimpleBody net472 999ns 0.161ns 0.623ns 0.195 0 0 1.23 KB
master AllCycleMoreComplexBody net6.0 7.28μs 34.2ns 137ns 0 0 0 4.72 KB
master AllCycleMoreComplexBody netcoreapp3.1 9.01μs 44.1ns 177ns 0 0 0 4.62 KB
master AllCycleMoreComplexBody net472 7.67μs 3.82ns 14.3ns 0.73 0 0 4.74 KB
master ObjectExtractorSimpleBody net6.0 326ns 1.6ns 8.34ns 0 0 0 280 B
master ObjectExtractorSimpleBody netcoreapp3.1 396ns 2.18ns 12.5ns 0 0 0 272 B
master ObjectExtractorSimpleBody net472 297ns 0.0328ns 0.123ns 0.0434 0 0 281 B
master ObjectExtractorMoreComplexBody net6.0 6.23μs 31.7ns 142ns 0 0 0 3.79 KB
master ObjectExtractorMoreComplexBody netcoreapp3.1 7.95μs 37.9ns 152ns 0 0 0 3.69 KB
master ObjectExtractorMoreComplexBody net472 6.69μs 4.07ns 15.8ns 0.6 0 0 3.8 KB
#7689 AllCycleSimpleBody net6.0 1.08μs 5.89ns 34.3ns 0 0 0 1.22 KB
#7689 AllCycleSimpleBody netcoreapp3.1 1.39μs 7.96ns 54ns 0 0 0 1.2 KB
#7689 AllCycleSimpleBody net472 1.03μs 2.34ns 9.07ns 0.193 0 0 1.23 KB
#7689 AllCycleMoreComplexBody net6.0 7.24μs 35.6ns 147ns 0 0 0 4.72 KB
#7689 AllCycleMoreComplexBody netcoreapp3.1 8.91μs 46ns 201ns 0 0 0 4.62 KB
#7689 AllCycleMoreComplexBody net472 7.57μs 2.73ns 10.6ns 0.719 0 0 4.74 KB
#7689 ObjectExtractorSimpleBody net6.0 334ns 0.151ns 0.544ns 0 0 0 280 B
#7689 ObjectExtractorSimpleBody netcoreapp3.1 395ns 2.14ns 11.5ns 0 0 0 272 B
#7689 ObjectExtractorSimpleBody net472 305ns 0.0218ns 0.0816ns 0.0445 0 0 281 B
#7689 ObjectExtractorMoreComplexBody net6.0 6.52μs 8.06ns 31.2ns 0 0 0 3.78 KB
#7689 ObjectExtractorMoreComplexBody netcoreapp3.1 7.89μs 40.4ns 181ns 0 0 0 3.69 KB
#7689 ObjectExtractorMoreComplexBody net472 6.7μs 3.88ns 14.5ns 0.603 0 0 3.8 KB
Benchmarks.Trace.Asm.AppSecEncoderBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EncodeArgs net6.0 77.8μs 244ns 947ns 0 0 0 32.4 KB
master EncodeArgs netcoreapp3.1 96.6μs 293ns 1.1μs 0 0 0 32.4 KB
master EncodeArgs net472 109μs 17.9ns 69.2ns 4.89 0 0 32.5 KB
master EncodeLegacyArgs net6.0 146μs 29.6ns 111ns 0 0 0 2.14 KB
master EncodeLegacyArgs netcoreapp3.1 201μs 65.1ns 244ns 0 0 0 2.14 KB
master EncodeLegacyArgs net472 264μs 50.8ns 197ns 0 0 0 2.14 KB
#7689 EncodeArgs net6.0 75.6μs 271ns 1.05μs 0 0 0 32.4 KB
#7689 EncodeArgs netcoreapp3.1 98.1μs 396ns 1.54μs 0 0 0 32.4 KB
#7689 EncodeArgs net472 109μs 16.9ns 65.3ns 4.89 0 0 32.5 KB
#7689 EncodeLegacyArgs net6.0 145μs 41.2ns 160ns 0 0 0 2.14 KB
#7689 EncodeLegacyArgs netcoreapp3.1 200μs 138ns 534ns 0 0 0 2.14 KB
#7689 EncodeLegacyArgs net472 268μs 43.8ns 169ns 0 0 0 2.15 KB
Benchmarks.Trace.Asm.AppSecWafBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master RunWafRealisticBenchmark net6.0 421μs 704ns 2.54μs 0 0 0 4.55 KB
master RunWafRealisticBenchmark netcoreapp3.1 459μs 2.67μs 24.3μs 0 0 0 4.48 KB
master RunWafRealisticBenchmark net472 487μs 964ns 3.73μs 0 0 0 0 b
master RunWafRealisticBenchmarkWithAttack net6.0 306μs 1.14μs 4.12μs 0 0 0 2.24 KB
master RunWafRealisticBenchmarkWithAttack netcoreapp3.1 339μs 2.82μs 26.9μs 0 0 0 2.22 KB
master RunWafRealisticBenchmarkWithAttack net472 360μs 175ns 629ns 0 0 0 0 b
#7689 RunWafRealisticBenchmark net6.0 417μs 846ns 3.05μs 0 0 0 4.55 KB
#7689 RunWafRealisticBenchmark netcoreapp3.1 454μs 3.06μs 29.1μs 0 0 0 4.48 KB
#7689 RunWafRealisticBenchmark net472 486μs 249ns 898ns 0 0 0 0 b
#7689 RunWafRealisticBenchmarkWithAttack net6.0 322μs 1.52μs 5.9μs 0 0 0 2.24 KB
#7689 RunWafRealisticBenchmarkWithAttack netcoreapp3.1 359μs 3.35μs 31.6μs 0 0 0 2.22 KB
#7689 RunWafRealisticBenchmarkWithAttack net472 364μs 250ns 900ns 0 0 0 0 b
Benchmarks.Trace.AspNetCoreBenchmark - Same speed ✔️ More allocations ⚠️

More allocations ⚠️ in #7689

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.AspNetCoreBenchmark.SendRequest‑net6.0 18.97 KB 19.09 KB 119 B 0.63%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendRequest net6.0 82.8μs 174ns 628ns 0 0 0 18.97 KB
master SendRequest netcoreapp3.1 97.2μs 406ns 2.57μs 0 0 0 21.18 KB
master SendRequest net472 0ns 0ns 0ns 0 0 0 0 b
#7689 SendRequest net6.0 86μs 68.2ns 255ns 0 0 0 19.09 KB
#7689 SendRequest netcoreapp3.1 97.6μs 453ns 2.56μs 0 0 0 21.18 KB
#7689 SendRequest net472 0ns 0ns 0ns 0 0 0 0 b
Benchmarks.Trace.CharSliceBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master OriginalCharSlice net6.0 1.95ms 960ns 3.72μs 0 0 0 640 KB
master OriginalCharSlice netcoreapp3.1 3.93ms 1.47μs 5.29μs 0 0 0 640.05 KB
master OriginalCharSlice net472 2.61ms 312ns 1.08μs 0 0 0 638.98 KB
master OptimizedCharSlice net6.0 1.41ms 1.74μs 6.52μs 0 0 0 0 b
master OptimizedCharSlice netcoreapp3.1 2.79ms 2.35μs 9.11μs 0 0 0 0 b
master OptimizedCharSlice net472 1.93ms 2.23μs 8.63μs 0 0 0 0 b
master OptimizedCharSliceWithPool net6.0 999μs 916ns 3.43μs 0 0 0 0 b
master OptimizedCharSliceWithPool netcoreapp3.1 1.88ms 1.13μs 4.37μs 0 0 0 0 b
master OptimizedCharSliceWithPool net472 1.13ms 686ns 2.66μs 0 0 0 0 b
#7689 OriginalCharSlice net6.0 2ms 1.6μs 6.18μs 0 0 0 640 KB
#7689 OriginalCharSlice netcoreapp3.1 3.88ms 710ns 2.46μs 0 0 0 640.05 KB
#7689 OriginalCharSlice net472 2.61ms 973ns 3.77μs 0 0 0 638.98 KB
#7689 OptimizedCharSlice net6.0 1.47ms 664ns 2.39μs 0 0 0 0 b
#7689 OptimizedCharSlice netcoreapp3.1 2.77ms 1.07μs 4.16μs 0 0 0 0 b
#7689 OptimizedCharSlice net472 2ms 887ns 3.44μs 0 0 0 0 b
#7689 OptimizedCharSliceWithPool net6.0 1.02ms 1.48μs 5.73μs 0 0 0 0 b
#7689 OptimizedCharSliceWithPool netcoreapp3.1 1.92ms 2.69μs 10.4μs 0 0 0 0 b
#7689 OptimizedCharSliceWithPool net472 1.14ms 513ns 1.92μs 0 0 0 0 b
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark - Slower ⚠️ Same allocations ✔️

Slower ⚠️ in #7689

Benchmark diff/base Base Median (ns) Diff Median (ns) Modality
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces‑netcoreapp3.1 1.163 647,635.42 752,899.31

Faster 🎉 in #7689

Benchmark base/diff Base Median (ns) Diff Median (ns) Modality
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces‑net472 1.150 956,104.46 831,729.02

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 680μs 1.36μs 5.25μs 0 0 0 41.63 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 648μs 1.26μs 4.88μs 0 0 0 41.93 KB
master WriteAndFlushEnrichedTraces net472 956μs 3.53μs 13.7μs 4.46 0 0 56.03 KB
#7689 WriteAndFlushEnrichedTraces net6.0 657μs 580ns 2.32μs 0 0 0 41.7 KB
#7689 WriteAndFlushEnrichedTraces netcoreapp3.1 765μs 4.28μs 29.7μs 0 0 0 41.81 KB
#7689 WriteAndFlushEnrichedTraces net472 831μs 2μs 7.2μs 4.46 0 0 55.95 KB
Benchmarks.Trace.DbCommandBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master ExecuteNonQuery net6.0 1.97μs 6.87ns 26.6ns 0 0 0 968 B
master ExecuteNonQuery netcoreapp3.1 2.6μs 10.6ns 40.9ns 0 0 0 960 B
master ExecuteNonQuery net472 2.64μs 0.669ns 2.59ns 0.146 0 0 931 B
#7689 ExecuteNonQuery net6.0 1.95μs 7.77ns 30.1ns 0 0 0 968 B
#7689 ExecuteNonQuery netcoreapp3.1 2.49μs 8.13ns 29.3ns 0 0 0 960 B
#7689 ExecuteNonQuery net472 2.7μs 1.28ns 4.95ns 0.147 0 0 931 B
Benchmarks.Trace.ElasticsearchBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master CallElasticsearch net6.0 1.7μs 6.62ns 25.7ns 0 0 0 952 B
master CallElasticsearch netcoreapp3.1 2.34μs 8.27ns 32ns 0 0 0 968 B
master CallElasticsearch net472 3.35μs 2.58ns 9.98ns 0.151 0 0 955 B
master CallElasticsearchAsync net6.0 1.72μs 8.26ns 32ns 0 0 0 928 B
master CallElasticsearchAsync netcoreapp3.1 2.44μs 5.62ns 21.8ns 0 0 0 1.02 KB
master CallElasticsearchAsync net472 3.44μs 4.03ns 15.1ns 0.156 0 0 1.01 KB
#7689 CallElasticsearch net6.0 1.73μs 6.38ns 24.7ns 0 0 0 952 B
#7689 CallElasticsearch netcoreapp3.1 2.29μs 9.65ns 37.4ns 0 0 0 968 B
#7689 CallElasticsearch net472 3.39μs 3.8ns 14.7ns 0.152 0 0 955 B
#7689 CallElasticsearchAsync net6.0 1.71μs 4.17ns 16.1ns 0 0 0 928 B
#7689 CallElasticsearchAsync netcoreapp3.1 2.3μs 11.2ns 46.2ns 0 0 0 1.02 KB
#7689 CallElasticsearchAsync net472 3.44μs 2.86ns 11.1ns 0.157 0 0 1.01 KB
Benchmarks.Trace.GraphQLBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master ExecuteAsync net6.0 1.87μs 6.49ns 25.1ns 0 0 0 896 B
master ExecuteAsync netcoreapp3.1 2.33μs 4.72ns 18.3ns 0 0 0 896 B
master ExecuteAsync net472 2.59μs 2.34ns 9.07ns 0.13 0 0 858 B
#7689 ExecuteAsync net6.0 1.91μs 7.62ns 29.5ns 0 0 0 896 B
#7689 ExecuteAsync netcoreapp3.1 2.37μs 3.44ns 12.9ns 0 0 0 896 B
#7689 ExecuteAsync net472 2.53μs 2.07ns 8.03ns 0.126 0 0 858 B
Benchmarks.Trace.HttpClientBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendAsync net6.0 7.15μs 17.2ns 64.3ns 0 0 0 2.29 KB
master SendAsync netcoreapp3.1 8.65μs 28.1ns 109ns 0 0 0 2.83 KB
master SendAsync net472 12μs 11.3ns 43.8ns 0.479 0 0 3.08 KB
#7689 SendAsync net6.0 6.64μs 29.4ns 110ns 0 0 0 2.29 KB
#7689 SendAsync netcoreapp3.1 8.59μs 21.8ns 84.2ns 0 0 0 2.83 KB
#7689 SendAsync net472 11.8μs 9.46ns 36.6ns 0.466 0 0 3.08 KB
Benchmarks.Trace.Iast.StringAspectsBenchmark - Same speed ✔️ More allocations ⚠️

More allocations ⚠️ in #7689

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑netcoreapp3.1 275.15 KB 318.13 KB 42.98 KB 15.62%
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net472 269.28 KB 270.7 KB 1.42 KB 0.53%

Fewer allocations 🎉 in #7689

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net6.0 272.25 KB 259.08 KB -13.17 KB -4.84%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StringConcatBenchmark net6.0 45μs 218ns 927ns 0 0 0 42.51 KB
master StringConcatBenchmark netcoreapp3.1 49.5μs 279ns 1.72μs 0 0 0 42.54 KB
master StringConcatBenchmark net472 57.6μs 143ns 517ns 0 0 0 49.15 KB
master StringConcatAspectBenchmark net6.0 471μs 2.15μs 8.62μs 0 0 0 272.25 KB
master StringConcatAspectBenchmark netcoreapp3.1 540μs 2.46μs 13μs 0 0 0 275.15 KB
master StringConcatAspectBenchmark net472 406μs 2.36μs 19.9μs 0 0 0 269.28 KB
#7689 StringConcatBenchmark net6.0 46.5μs 307ns 2.83μs 0 0 0 42.51 KB
#7689 StringConcatBenchmark netcoreapp3.1 48.7μs 279ns 2.07μs 0 0 0 42.54 KB
#7689 StringConcatBenchmark net472 56.9μs 283ns 1.2μs 0 0 0 49.15 KB
#7689 StringConcatAspectBenchmark net6.0 476μs 1.85μs 7.85μs 0 0 0 259.08 KB
#7689 StringConcatAspectBenchmark netcoreapp3.1 474μs 5.94μs 58.8μs 0 0 0 318.13 KB
#7689 StringConcatAspectBenchmark net472 405μs 2.22μs 16.9μs 0 0 0 270.7 KB
Benchmarks.Trace.ILoggerBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 2.66μs 0.992ns 3.84ns 0 0 0 1.69 KB
master EnrichedLog netcoreapp3.1 3.51μs 14.4ns 53.8ns 0 0 0 1.7 KB
master EnrichedLog net472 4.04μs 4.4ns 17ns 0.242 0 0 1.6 KB
#7689 EnrichedLog net6.0 2.76μs 13.7ns 61ns 0 0 0 1.69 KB
#7689 EnrichedLog netcoreapp3.1 3.59μs 3.62ns 13.6ns 0 0 0 1.7 KB
#7689 EnrichedLog net472 3.82μs 3.29ns 12.8ns 0.246 0 0 1.6 KB
Benchmarks.Trace.Log4netBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 121μs 82.3ns 285ns 0 0 0 4.31 KB
master EnrichedLog netcoreapp3.1 127μs 407ns 1.52μs 0 0 0 4.31 KB
master EnrichedLog net472 165μs 44.7ns 173ns 0 0 0 4.51 KB
#7689 EnrichedLog net6.0 124μs 92.7ns 334ns 0 0 0 4.31 KB
#7689 EnrichedLog netcoreapp3.1 128μs 150ns 582ns 0 0 0 4.31 KB
#7689 EnrichedLog net472 168μs 202ns 784ns 0 0 0 4.51 KB
Benchmarks.Trace.NLogBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 5.06μs 3.04ns 11.8ns 0 0 0 2.24 KB
master EnrichedLog netcoreapp3.1 6.88μs 14.1ns 48.8ns 0 0 0 2.26 KB
master EnrichedLog net472 7.55μs 6.05ns 23.4ns 0.303 0 0 2.05 KB
#7689 EnrichedLog net6.0 4.94μs 21.2ns 82.2ns 0 0 0 2.24 KB
#7689 EnrichedLog netcoreapp3.1 6.98μs 24.3ns 94.3ns 0 0 0 2.26 KB
#7689 EnrichedLog net472 7.65μs 8.71ns 33.7ns 0.307 0 0 2.05 KB
Benchmarks.Trace.RedisBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendReceive net6.0 1.88μs 9.8ns 46ns 0 0 0 1.12 KB
master SendReceive netcoreapp3.1 2.41μs 12.4ns 58.3ns 0 0 0 1.14 KB
master SendReceive net472 2.95μs 1.88ns 7.27ns 0.176 0 0 1.12 KB
#7689 SendReceive net6.0 2.01μs 1.49ns 5.78ns 0 0 0 1.12 KB
#7689 SendReceive netcoreapp3.1 2.56μs 11.2ns 43.5ns 0 0 0 1.14 KB
#7689 SendReceive net472 2.93μs 1.94ns 7.01ns 0.176 0 0 1.12 KB
Benchmarks.Trace.SerilogBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 4.47μs 2.85ns 10.3ns 0 0 0 1.58 KB
master EnrichedLog netcoreapp3.1 5.74μs 25.9ns 100ns 0 0 0 1.63 KB
master EnrichedLog net472 6.6μs 7.36ns 27.5ns 0.295 0 0 2.03 KB
#7689 EnrichedLog net6.0 4.44μs 11.4ns 44.3ns 0 0 0 1.58 KB
#7689 EnrichedLog netcoreapp3.1 5.79μs 13ns 48.5ns 0 0 0 1.63 KB
#7689 EnrichedLog net472 6.79μs 9.88ns 38.3ns 0.304 0 0 2.03 KB
Benchmarks.Trace.SpanBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartFinishSpan net6.0 759ns 0.792ns 3.07ns 0 0 0 520 B
master StartFinishSpan netcoreapp3.1 971ns 4.82ns 21ns 0 0 0 520 B
master StartFinishSpan net472 894ns 3.57ns 13.8ns 0.08 0 0 522 B
master StartFinishScope net6.0 895ns 1.22ns 4.72ns 0 0 0 640 B
master StartFinishScope netcoreapp3.1 1.13μs 5.7ns 24.9ns 0 0 0 640 B
master StartFinishScope net472 1.08μs 1.04ns 4.03ns 0.092 0 0 602 B
master StartFinishTwoScopes net6.0 1.79μs 1.66ns 6.22ns 0 0 0 1.19 KB
master StartFinishTwoScopes netcoreapp3.1 2.22μs 10.4ns 40.3ns 0 0 0 1.19 KB
master StartFinishTwoScopes net472 2.1μs 0.216ns 0.837ns 0.168 0 0 1.08 KB
#7689 StartFinishSpan net6.0 744ns 3.93ns 19.2ns 0 0 0 520 B
#7689 StartFinishSpan netcoreapp3.1 969ns 4.62ns 17.9ns 0 0 0 520 B
#7689 StartFinishSpan net472 912ns 0.204ns 0.762ns 0.0823 0 0 522 B
#7689 StartFinishScope net6.0 890ns 4.53ns 21.2ns 0 0 0 640 B
#7689 StartFinishScope netcoreapp3.1 1.13μs 5.67ns 25.4ns 0 0 0 640 B
#7689 StartFinishScope net472 1.07μs 0.143ns 0.536ns 0.0913 0 0 602 B
#7689 StartFinishTwoScopes net6.0 1.82μs 0.799ns 3.09ns 0 0 0 1.19 KB
#7689 StartFinishTwoScopes netcoreapp3.1 2.17μs 10.9ns 49ns 0 0 0 1.19 KB
#7689 StartFinishTwoScopes net472 2.12μs 0.387ns 1.45ns 0.169 0 0 1.08 KB
Benchmarks.Trace.TraceAnnotationsBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master RunOnMethodBegin net6.0 1.05μs 5.24ns 23.5ns 0 0 0 640 B
master RunOnMethodBegin netcoreapp3.1 1.41μs 6.52ns 26.1ns 0 0 0 640 B
master RunOnMethodBegin net472 1.43μs 0.431ns 1.67ns 0.0929 0 0 602 B
#7689 RunOnMethodBegin net6.0 1.07μs 5.11ns 21.1ns 0 0 0 640 B
#7689 RunOnMethodBegin netcoreapp3.1 1.35μs 6.17ns 23.1ns 0 0 0 640 B
#7689 RunOnMethodBegin net472 1.4μs 0.897ns 3.47ns 0.0914 0 0 602 B

@dd-trace-dotnet-ci-bot
Copy link

dd-trace-dotnet-ci-bot bot commented Oct 21, 2025

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (7689) and master.

✅ No regressions detected - check the details below

Full Metrics Comparison

FakeDbCommand

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration77.02 ± (77.07 - 77.98) ms73.91 ± (74.15 - 74.88) ms-4.0%
.NET Framework 4.8 - Bailout
duration81.89 ± (81.83 - 82.84) ms79.95 ± (80.07 - 81.04) ms-2.4%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1078.74 ± (1080.20 - 1090.29) ms1078.42 ± (1080.06 - 1090.18) ms-0.0%
.NET Core 3.1 - Baseline
process.internal_duration_ms23.19 ± (23.12 - 23.25) ms23.10 ± (23.01 - 23.18) ms-0.4%
process.time_to_main_ms90.09 ± (89.61 - 90.56) ms88.94 ± (88.50 - 89.39) ms-1.3%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.90 ± (10.90 - 10.90) MB10.92 ± (10.91 - 10.92) MB+0.2%✅⬆️
runtime.dotnet.threads.count12 ± (12 - 12)12 ± (12 - 12)+0.0%
.NET Core 3.1 - Bailout
process.internal_duration_ms23.14 ± (23.06 - 23.21) ms22.99 ± (22.91 - 23.08) ms-0.6%
process.time_to_main_ms91.17 ± (90.74 - 91.59) ms89.98 ± (89.58 - 90.38) ms-1.3%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.95 ± (10.95 - 10.95) MB10.97 ± (10.97 - 10.97) MB+0.2%✅⬆️
runtime.dotnet.threads.count13 ± (13 - 13)13 ± (13 - 13)+0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms224.37 ± (223.08 - 225.66) ms224.88 ± (223.55 - 226.22) ms+0.2%✅⬆️
process.time_to_main_ms508.62 ± (507.24 - 509.99) ms514.55 ± (513.05 - 516.05) ms+1.2%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed47.92 ± (47.90 - 47.94) MB47.92 ± (47.90 - 47.94) MB+0.0%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)-0.0%
.NET 6 - Baseline
process.internal_duration_ms21.98 ± (21.91 - 22.06) ms22.04 ± (21.97 - 22.11) ms+0.3%✅⬆️
process.time_to_main_ms78.11 ± (77.66 - 78.55) ms77.69 ± (77.29 - 78.09) ms-0.5%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.60 ± (10.60 - 10.60) MB10.62 ± (10.62 - 10.63) MB+0.2%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 6 - Bailout
process.internal_duration_ms21.95 ± (21.86 - 22.03) ms21.75 ± (21.68 - 21.83) ms-0.9%
process.time_to_main_ms79.31 ± (78.90 - 79.73) ms78.23 ± (77.76 - 78.70) ms-1.4%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.66 ± (10.65 - 10.66) MB10.66 ± (10.66 - 10.67) MB+0.1%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms212.48 ± (211.40 - 213.56) ms214.44 ± (213.15 - 215.72) ms+0.9%✅⬆️
process.time_to_main_ms473.82 ± (472.66 - 474.98) ms476.87 ± (475.55 - 478.19) ms+0.6%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed48.14 ± (48.11 - 48.17) MB48.27 ± (48.25 - 48.29) MB+0.3%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.0%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms20.11 ± (20.03 - 20.19) ms20.05 ± (19.97 - 20.13) ms-0.3%
process.time_to_main_ms76.36 ± (75.95 - 76.78) ms76.36 ± (75.96 - 76.76) ms-0.0%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.66 ± (7.65 - 7.67) MB7.67 ± (7.66 - 7.67) MB+0.1%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 8 - Bailout
process.internal_duration_ms19.92 ± (19.84 - 20.00) ms19.81 ± (19.74 - 19.88) ms-0.6%
process.time_to_main_ms77.40 ± (77.03 - 77.77) ms76.58 ± (76.21 - 76.94) ms-1.1%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.70 ± (7.69 - 7.70) MB7.72 ± (7.71 - 7.73) MB+0.3%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms194.46 ± (193.35 - 195.58) ms194.65 ± (193.52 - 195.78) ms+0.1%✅⬆️
process.time_to_main_ms463.68 ± (462.39 - 464.98) ms463.79 ± (462.25 - 465.32) ms+0.0%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed36.44 ± (36.40 - 36.47) MB36.49 ± (36.45 - 36.53) MB+0.2%✅⬆️
runtime.dotnet.threads.count27 ± (27 - 27)27 ± (27 - 27)-0.0%

HttpMessageHandler

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration195.77 ± (195.56 - 196.38) ms196.29 ± (196.47 - 197.38) ms+0.3%✅⬆️
.NET Framework 4.8 - Bailout
duration198.64 ± (198.44 - 199.32) ms202.80 ± (202.74 - 203.88) ms+2.1%✅⬆️
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1122.57 ± (1125.36 - 1133.96) ms1130.18 ± (1135.16 - 1144.55) ms+0.7%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms192.55 ± (192.11 - 192.99) ms193.48 ± (192.99 - 193.97) ms+0.5%✅⬆️
process.time_to_main_ms82.12 ± (81.88 - 82.36) ms82.44 ± (82.23 - 82.65) ms+0.4%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.05 ± (16.03 - 16.07) MB16.12 ± (16.10 - 16.14) MB+0.4%✅⬆️
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)+0.1%✅⬆️
.NET Core 3.1 - Bailout
process.internal_duration_ms190.58 ± (190.18 - 190.99) ms193.20 ± (192.71 - 193.69) ms+1.4%✅⬆️
process.time_to_main_ms83.00 ± (82.77 - 83.22) ms83.91 ± (83.70 - 84.11) ms+1.1%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.10 ± (16.08 - 16.13) MB16.17 ± (16.15 - 16.19) MB+0.4%✅⬆️
runtime.dotnet.threads.count21 ± (21 - 21)21 ± (21 - 21)-0.3%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms398.70 ± (396.49 - 400.92) ms406.23 ± (403.36 - 409.11) ms+1.9%✅⬆️
process.time_to_main_ms478.01 ± (477.22 - 478.80) ms487.75 ± (486.86 - 488.65) ms+2.0%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed58.85 ± (58.74 - 58.97) MB58.86 ± (58.75 - 58.98) MB+0.0%✅⬆️
runtime.dotnet.threads.count29 ± (29 - 30)29 ± (29 - 30)-0.1%
.NET 6 - Baseline
process.internal_duration_ms195.35 ± (194.92 - 195.78) ms196.59 ± (196.07 - 197.11) ms+0.6%✅⬆️
process.time_to_main_ms70.54 ± (70.33 - 70.74) ms71.02 ± (70.76 - 71.27) ms+0.7%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.34 ± (16.32 - 16.37) MB16.29 ± (16.23 - 16.35) MB-0.3%
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)-1.8%
.NET 6 - Bailout
process.internal_duration_ms196.34 ± (195.90 - 196.79) ms195.16 ± (194.70 - 195.63) ms-0.6%
process.time_to_main_ms72.02 ± (71.84 - 72.20) ms71.86 ± (71.70 - 72.03) ms-0.2%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.40 ± (16.38 - 16.43) MB16.38 ± (16.35 - 16.40) MB-0.2%
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)+0.4%✅⬆️
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms411.70 ± (409.78 - 413.62) ms413.22 ± (411.08 - 415.37) ms+0.4%✅⬆️
process.time_to_main_ms446.97 ± (446.26 - 447.69) ms452.66 ± (451.95 - 453.37) ms+1.3%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed59.20 ± (59.08 - 59.32) MB59.42 ± (59.31 - 59.53) MB+0.4%✅⬆️
runtime.dotnet.threads.count30 ± (30 - 30)30 ± (29 - 30)-0.3%
.NET 8 - Baseline
process.internal_duration_ms193.75 ± (193.28 - 194.22) ms195.79 ± (195.36 - 196.22) ms+1.1%✅⬆️
process.time_to_main_ms69.88 ± (69.68 - 70.08) ms70.77 ± (70.53 - 71.00) ms+1.3%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.67 ± (11.65 - 11.69) MB11.72 ± (11.70 - 11.74) MB+0.4%✅⬆️
runtime.dotnet.threads.count18 ± (18 - 18)18 ± (18 - 18)+0.2%✅⬆️
.NET 8 - Bailout
process.internal_duration_ms192.52 ± (192.08 - 192.97) ms196.27 ± (195.66 - 196.87) ms+1.9%✅⬆️
process.time_to_main_ms71.25 ± (71.06 - 71.43) ms72.04 ± (71.83 - 72.25) ms+1.1%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.78 ± (11.76 - 11.81) MB11.75 ± (11.73 - 11.77) MB-0.3%
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)+0.6%✅⬆️
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms371.75 ± (370.31 - 373.19) ms374.28 ± (372.78 - 375.77) ms+0.7%✅⬆️
process.time_to_main_ms435.11 ± (434.50 - 435.72) ms437.92 ± (437.17 - 438.67) ms+0.6%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed47.99 ± (47.96 - 48.02) MB48.04 ± (48.01 - 48.07) MB+0.1%✅⬆️
runtime.dotnet.threads.count29 ± (29 - 29)29 ± (29 - 29)-0.1%
Comparison explanation

Execution-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:

  • Welch test with statistical test for significance of 5%
  • Only results indicating a difference greater than 5% and 5 ms are considered.

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 charts
FakeDbCommand (.NET Framework 4.8)
gantt
    title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7689) - mean (75ms)  : 69, 80
    master - mean (78ms)  : 71, 84

    section Bailout
    This PR (7689) - mean (81ms)  : 73, 88
    master - mean (82ms)  : 75, 90

    section CallTarget+Inlining+NGEN
    This PR (7689) - mean (1,085ms)  : 1012, 1159
    master - mean (1,085ms)  : 1016, 1155

Loading
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 (7689) - mean (120ms)  : 112, 128
    master - mean (121ms)  : 113, 129

    section Bailout
    This PR (7689) - mean (121ms)  : 114, 128
    master - mean (122ms)  : 113, 131

    section CallTarget+Inlining+NGEN
    This PR (7689) - mean (780ms)  : 745, 815
    master - mean (774ms)  : 737, 810

Loading
FakeDbCommand (.NET 6)
gantt
    title Execution time (ms) FakeDbCommand (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7689) - mean (107ms)  : 98, 116
    master - mean (108ms)  : 98, 117

    section Bailout
    This PR (7689) - mean (107ms)  : 98, 116
    master - mean (109ms)  : 101, 117

    section CallTarget+Inlining+NGEN
    This PR (7689) - mean (721ms)  : 679, 763
    master - mean (715ms)  : 686, 745

Loading
FakeDbCommand (.NET 8)
gantt
    title Execution time (ms) FakeDbCommand (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7689) - mean (105ms)  : 98, 112
    master - mean (105ms)  : 96, 115

    section Bailout
    This PR (7689) - mean (105ms)  : 97, 113
    master - mean (106ms)  : 99, 112

    section CallTarget+Inlining+NGEN
    This PR (7689) - mean (697ms)  : 650, 745
    master - mean (697ms)  : 659, 735

Loading
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 (7689) - mean (197ms)  : 191, 203
    master - mean (196ms)  : 191, 201

    section Bailout
    This PR (7689) - mean (203ms)  : 195, 212
    master - mean (199ms)  : 195, 203

    section CallTarget+Inlining+NGEN
    This PR (7689) - mean (1,140ms)  : 1067, 1212
    master - mean (1,130ms)  : 1067, 1193

Loading
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 (7689) - mean (284ms)  : 274, 295
    master - mean (283ms)  : 274, 292

    section Bailout
    This PR (7689) - mean (286ms)  : 277, 294
    master - mean (282ms)  : 275, 288

    section CallTarget+Inlining+NGEN
    This PR (7689) - mean (935ms)  : 885, 985
    master - mean (914ms)  : 874, 955

Loading
HttpMessageHandler (.NET 6)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7689) - mean (276ms)  : 270, 283
    master - mean (274ms)  : 268, 280

    section Bailout
    This PR (7689) - mean (275ms)  : 268, 283
    master - mean (277ms)  : 270, 284

    section CallTarget+Inlining+NGEN
    This PR (7689) - mean (900ms)  : 862, 939
    master - mean (893ms)  : 856, 930

Loading
HttpMessageHandler (.NET 8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7689) - mean (276ms)  : 267, 285
    master - mean (274ms)  : 266, 282

    section Bailout
    This PR (7689) - mean (278ms)  : 269, 287
    master - mean (274ms)  : 268, 279

    section CallTarget+Inlining+NGEN
    This PR (7689) - mean (845ms)  : 820, 870
    master - mean (837ms)  : 806, 869

Loading

@anna-git anna-git changed the title [Config registry] Analyzers for ConfigurationBuilder, ConfigurationKeys, PlatformKeys [ConfigRegistry] Analyzers for platform and ConfigurationBuilder Oct 22, 2025
@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch from c983088 to 9e2a61b Compare October 22, 2025 17:26
@anna-git anna-git force-pushed the anna/config-inversion-configuration-analyzers-4 branch from c1f7943 to 56bd199 Compare October 22, 2025 17:26
@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch 2 times, most recently from f242046 to 153e7b3 Compare October 22, 2025 18:14
@anna-git anna-git force-pushed the anna/config-inversion-configuration-analyzers-4 branch from 56bd199 to e52fd10 Compare October 22, 2025 18:14
@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch from 153e7b3 to bd34118 Compare October 22, 2025 18:27
@anna-git anna-git force-pushed the anna/config-inversion-configuration-analyzers-4 branch from acdece9 to 86d6dbd Compare October 27, 2025 19:21
@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch from 5018466 to 783a308 Compare October 27, 2025 20:56
@anna-git anna-git force-pushed the anna/config-inversion-configuration-analyzers-4 branch from 86d6dbd to fc26b53 Compare October 27, 2025 20:56
@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch from 783a308 to aa52b7f Compare October 28, 2025 14:33
@anna-git anna-git force-pushed the anna/config-inversion-configuration-analyzers-4 branch from fc26b53 to cc850d6 Compare October 28, 2025 14:33
@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch from aa52b7f to 0c28972 Compare October 28, 2025 14:55
@anna-git anna-git force-pushed the anna/config-inversion-configuration-analyzers-4 branch from cc850d6 to 2a09875 Compare October 28, 2025 14:55
anna-git added a commit that referenced this pull request Oct 28, 2025
… yaml for doc (#7548)

## Context

Part of **Configuration Inversion (Step 1)** - Stack progress:
1. **→ [#7548](#7548) -
Add GitLab step and JSON configuration file (this PR)**
2. [#7688](#7688) -
Reorganize keys, split config keys and platform keys
3. [#7698](#7698) -
Generate ConfigurationKeys with source generator
4. [#7689](#7689) -
Aliases handling and analyzers
5. [#7697](#7697) -
Replace manual ConfigurationKeys by generated ones in the whole solution



## Summary

Adds centralized configuration registry (`supported-configurations.json`
+
[supported-configurations-docs.yaml](cci:7://file:///Users/anna.yafi/go/src/github.com/DataDog/dd-trace-dotnet3/tracer/src/Datadog.Trace/Configuration/supported-configurations-docs.yaml:0:0-0:0))
containing ~280 configuration keys with automated GitLab CI validation.

## Changes

**Configuration Files:**
- `supported-configurations.json` - Machine-readable registry of all
configuration keys with versions, aliases, and deprecations
-
[supported-configurations-docs.yaml](cci:7://file:///Users/anna.yafi/go/src/github.com/DataDog/dd-trace-dotnet3/tracer/src/Datadog.Trace/Configuration/supported-configurations-docs.yaml:0:0-0:0)
- Human-readable documentation for each configuration key

**CI/CD:**
- Added `validate_supported_configurations_local_file` step to
`.gitlab-ci.yml`
- Updated `.gitlab/one-pipeline.locked.yaml` to reference validation
template

**File Structure:**
```json
{
  "supportedConfigurations": { "DD_TRACE_ENABLED": { "version": ["A"] }, ... },
  "aliases": { "DD_AGENT_HOST": ["DD_TRACE_AGENT_HOSTNAME", ...], ... },
  "deprecations": { "DD_TRACE_ANALYTICS_ENABLED": "Deprecated - ...", ... }
}
```

## Motivation

Provides single source of truth for configuration keys to enable:
- Automated documentation validation
- Cross-tracer compatibility checks
- Configuration migration tooling
- Automated doc generation

See: [Configuration Registry Design
Doc](https://docs.google.com/document/d/1VIvOyQPfuQIWBIgNY68A9hzLir0-3eJijTwmpWASO8s/edit?tab=t.0#heading=h.jy2ajbk2b8ba)

## Validation

GitLab CI validates JSON structure, naming conventions, and schema
compliance on every build.

## Commit Details

**`2639cf0` - Initial Configuration Registry**
- Added `supported-configurations.json` with ~280 configuration keys
organized by version (A/B/C)
- Includes `aliases` section mapping primary keys to
deprecated/alternative names
- Includes `deprecations` section with deprecation messages
- Added GitLab CI validation step to ensure file integrity
- Updated one-pipeline lock file to reference validation template

**`70e632e` - Configuration Documentation**
- Added
[supported-configurations-docs.yaml](cci:7://file:///Users/anna.yafi/go/src/github.com/DataDog/dd-trace-dotnet3/tracer/src/Datadog.Trace/Configuration/supported-configurations-docs.yaml:0:0-0:0)
with detailed XML documentation for each configuration key
- Provides human-readable descriptions, default values, and usage
examples
- Includes `<seealso>` references to relevant code classes
- Complements the machine-readable JSON with developer-friendly
documentation
- Enables automated generation of configuration documentation from a
single source
Copy link
Member

@andrewlock andrewlock left a comment

Choose a reason for hiding this comment

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

Nice work 👍

var aliasSection = additionalText.Collect()
.Select(static (files, ct) =>
{
if (files.Length == 0)
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure this will ever fire 🤔 Given we filter out non-matching texts, I don't think it will. So we can probably just remove the Collect, remove the diagnostic, and make this Select operate on a single file

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point! changed in 888141d

#pragma warning disable 618 // ProfilerLogPath is deprecated but still supported
var nativeLogFile = config.WithKeys(ConfigurationKeys.ProfilerLogPath).AsString();
#pragma warning restore 618
// ProfilerLogPath is deprecated but still supported. For now, we bypass the WithKeys analyzer, but later we want to pull deprecations differently as part of centralized file
Copy link
Member

Choose a reason for hiding this comment

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

Later, as in later in this config stack, or as in after that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

later as later in config registry v2 😅

Comment on lines +22 to +39
public HasKeys WithIntegrationKey(string integrationName) => new(
_source,
_telemetry,
string.Format(IntegrationSettings.IntegrationEnabledKey, integrationName.ToUpperInvariant()),
[
string.Format(IntegrationSettings.IntegrationEnabledKey, integrationName),
$"DD_{integrationName}_ENABLED"
]);

public HasKeys WithIntegrationAnalyticsKey(string integrationName) => new(
_source,
_telemetry,
#pragma warning disable 618 // App analytics is deprecated, but still used
string.Format(IntegrationSettings.AnalyticsEnabledKey, integrationName.ToUpperInvariant()),
[
string.Format(IntegrationSettings.AnalyticsEnabledKey, integrationName),
#pragma warning restore 618
$"DD_{integrationName}_ANALYTICS_ENABLED"
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure this makes sense to me - AFAICT what you have today is correct 🤔

public HasKeys WithKeys(string key, string fallbackKey1, string fallbackKey2, string fallbackKey3) => new(_source, _telemetry, key, fallbackKey1, fallbackKey2, fallbackKey3);

internal readonly struct HasKeys
public HasKeys WithIntegrationKey(string integrationName) => new(
Copy link
Member

Choose a reason for hiding this comment

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

Such a pain 😅 Part of me wonders if instead of doing string.Format() here, we should have a source-generated mapping from integrationName => keys, but that's totally separate, and something we can investigate later to see if it improves perf

Copy link
Contributor Author

@anna-git anna-git Nov 25, 2025

Choose a reason for hiding this comment

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

good idea, and maybe have all these in the Config registry in the feature parity database... I'll put it in the config registry backlog but it would be neat as it would avoid formatting stuff at runtime

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I'm inclined to do this sooner rather than later (not in this PR or anything obvs!) because all this formatting actually shows up in profiles too....


// Filter out tags with empty keys or empty values, and trim whitespaces
var headerTags = InitializeHeaderTags(config, ConfigurationKeys.HeaderTags, headerTagsNormalizationFixEnabled) ?? ReadOnlyDictionary.Empty;
var headerTags = InitializeHeaderTags(config.WithKeys(ConfigurationKeys.HeaderTags), headerTagsNormalizationFixEnabled) ?? ReadOnlyDictionary.Empty;
Copy link
Member

Choose a reason for hiding this comment

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

Example of at callsite:

Suggested change
var headerTags = InitializeHeaderTags(config.WithKeys(ConfigurationKeys.HeaderTags), headerTagsNormalizationFixEnabled) ?? ReadOnlyDictionary.Empty;
var headerTagsConfig = config.WithKeys(ConfigurationKeys.HeaderTags);
var headerTags = InitializeHeaderTags(in headerTagsConfig, headerTagsNormalizationFixEnabled) ?? ReadOnlyDictionary.Empty;

Copy link
Contributor Author

@anna-git anna-git Nov 25, 2025

Choose a reason for hiding this comment

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

yes! changed in 888141d

.AsBool(defaultValue: false);

var httpServerErrorStatusCodesString = config
#pragma warning disable 618 // This config key has been replaced but may still be used
Copy link
Member

Choose a reason for hiding this comment

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

ooh, that's a nice benefit where only the aliases are deprecated

Comment on lines +1376 to +1384
internal bool IsErrorStatusCode(int statusCode, bool serverStatusCode)
=> MutableSettings.IsErrorStatusCode(statusCode, serverStatusCode);

internal bool IsIntegrationEnabled(IntegrationId integration, bool defaultValue = true)
=> MutableSettings.IsIntegrationEnabled(integration, defaultValue);

[Obsolete(DeprecationMessages.AppAnalytics)]
internal double? GetIntegrationAnalyticsSampleRate(IntegrationId integration, bool enabledWithGlobalSetting)
=> MutableSettings.GetIntegrationAnalyticsSampleRate(integration, enabledWithGlobalSetting);
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to add these here? 🤔

Copy link
Contributor Author

@anna-git anna-git Nov 25, 2025

Choose a reason for hiding this comment

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

removed in 888141d

Comment on lines +29 to +33
return new string[]
{
"DATADOG_TRACE_AGENT_HOSTNAME",
"DD_TRACE_AGENT_HOSTNAME"
};
Copy link
Member

Choose a reason for hiding this comment

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

IMO we should update the source generator to use a switch expression and to use collection expressions so that it looks like this:

public static string[] GetAliases(string mainKey)
    => mainKey switch
    {
        "DD_AGENT_HOST" => [ "DATADOG_TRACE_AGENT_HOSTNAME", "DD_TRACE_AGENT_HOSTNAME" ],
        // the rest
        _ => [],
    };

Copy link
Contributor Author

@anna-git anna-git Nov 25, 2025

Choose a reason for hiding this comment

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

yes thanks, changed in 888141d

@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch from 0c28972 to bea714d Compare October 29, 2025 17:15
@anna-git anna-git force-pushed the anna/config-inversion-configuration-analyzers-4 branch from 2a09875 to 279b292 Compare October 29, 2025 17:15
@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch from bea714d to a6668f3 Compare October 29, 2025 17:48
@anna-git anna-git force-pushed the anna/config-inversion-configuration-analyzers-4 branch from 279b292 to 9860a88 Compare October 29, 2025 17:49
anna-git added a commit that referenced this pull request Oct 30, 2025
… keys (#7688)

## Context

Part of **Configuration Inversion (Step 2)** - Stack progress:
1. [#7548](#7548) - Add
GitLab step and JSON configuration file
2. **→ [#7688](#7688) -
[Config registry] Reorganize keys, split config keys and platform
keys(this PR)**
3. [#7698](#7698) -
Generate ConfigurationKeys with source generator
4. [#7689](#7689) -
Aliases handling and analyzers
5. [#7697](#7697) -
Replace manual ConfigurationKeys by generated ones in the whole solution
## Summary

Separates platform-specific environment variables into `PlatformKeys`
class and adds Roslyn analyzers to enforce proper usage of configuration
keys throughout the codebase.

## Changes

**Platform Keys Separation:**
- Created `PlatformKeys` class for external platform environment
variables (AWS, Azure, GCP, Kubernetes, CLR Profiler), those that don't
start with DD_ and come from other platforms.
- Updated all references throughout codebase to use `PlatformKeys` for
platform-specific variables
- Keeps `ConfigurationKeys` focused only on Datadog configuration

**Roslyn Analyzers:**
- **DD0007**: Platform key analyzer - Enforces use of `PlatformKeys` for
external platform environment variables
- **DD0008**: ConfigurationBuilder analyzer - Enforces use of
`ConfigurationKeys` or `PlatformKeys` constants in
`ConfigurationBuilder.WithKeys()` calls
- Prevents hardcoded strings and ensures type safety

**Configuration Mapping:**
- Added `configuration_keys_mapping.json` to map environment variable
names to their `ConfigurationKeys` constant names, so that we avoid
renaming hundreds of variables according to automatically source
generated deducted ones.
- Enables preservation of original constant names during refactoring
- Supports source generator integration

**Code Updates:**
- Updated `TracerSettings`, test files, and profiler code to use
`PlatformKeys`
- Replaced manual `ConfigurationKeys` with generated version from
`supported-configurations.json`
- Added missing `DD_TRACE_LOG_PATH` to configuration registry

## Motivation

Ensures clean separation between Datadog and platform configuration by:
- Preventing accidental mixing of platform and Datadog keys
- Enforcing compile-time validation of configuration key usage
- Making it clear which keys are owned by Datadog vs external platforms
- Catching configuration errors at build time instead of runtime

## Validation

- Roslyn analyzers run on every build
- All existing tests pass with updated key references
- Analyzers report clear diagnostic messages for violations

## Related Work

This PR builds on the configuration registry foundation established in
#7548:
- **Commit `2639cf0`** added `supported-configurations.json` with ~280
keys, aliases, deprecations, and GitLab CI validation
- **Commit `70e632e`** added
[supported-configurations-docs.yaml](cci:7://file:///Users/anna.yafi/go/src/github.com/DataDog/dd-trace-dotnet3/tracer/src/Datadog.Trace/Configuration/supported-configurations-docs.yaml:0:0-0:0)
with XML documentation for automated doc generation
@anna-git anna-git force-pushed the anna/config-inversion-configuration-aliases-switch-3 branch from a6668f3 to d90d571 Compare October 30, 2025 18:03
Copy link
Contributor

@daniel-romano-DD daniel-romano-DD left a comment

Choose a reason for hiding this comment

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

TY!

Copy link
Member

@andrewlock andrewlock left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

<type fullname="System.Func`4" />
<type fullname="System.Func`5" />
<type fullname="System.Func`6" />
<type fullname="System.Func`7" />
Copy link
Member

Choose a reason for hiding this comment

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

weird 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it's because I removed some selectors of the ConfigurationBuilder following simplification

public HasKeys WithKeys(string key, string fallbackKey1, string fallbackKey2, string fallbackKey3) => new(_source, _telemetry, key, fallbackKey1, fallbackKey2, fallbackKey3);

internal readonly struct HasKeys
public HasKeys WithIntegrationKey(string integrationName) => new(
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I'm inclined to do this sooner rather than later (not in this PR or anything obvs!) because all this formatting actually shows up in profiles too....

/// </summary>
/// <param name="mainKey">The configuration key.</param>
/// <returns>An array of aliases for the key, or empty array if no aliases exist.</returns>
public static string[] GetAliases(string mainKey) => mainKey switch
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we can/should make this return ReadOnlySpan<string>, at least for .NET Core 🤔 That way we could avoid the allocation, as we're only going to iterate over the results 🤔 I don't think it should block this necessarily, but as all of these are going to be called by default for most apps, I'm concerned about all the extra tiny arrays 🤔

Copy link
Contributor Author

@anna-git anna-git Dec 9, 2025

Choose a reason for hiding this comment

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

good point, added in d18480f

// todo, handle in phase 2 with deprecations
// ProfilerLogPath is deprecated but still supported. For now, we bypass the WithKeys analyzer, but later (config registry v2) we want to pull deprecations differently as part of centralized file
#pragma warning disable DD0008, 618
var nativeLogFile = configurationBuilder.WithKeys(ConfigurationKeys.TraceLogPath).AsString();
Copy link
Member

Choose a reason for hiding this comment

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

Did you rename ProfilerLogPath to TraceLogPath here? 🤔 If so, we should rename the comment too (otherwise, we should fix the variable! 😄)

Copy link
Contributor Author

@anna-git anna-git Dec 9, 2025

Choose a reason for hiding this comment

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

thanks, fixed in d18480f

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants