Skip to content

Conversation

@andrewlock
Copy link
Member

@andrewlock andrewlock commented Oct 22, 2025

Summary of changes

  • Introduces SettingsManager responsible for managing MutableSettings and ExporterSettings

Reason for change

We need to be notified about runtime changes to settings (i.e. config in code or remote config) but don't want to tear down the world and rebuild every time. SettingsManager is responsible for handling this. Consumers subscribe to changes and can be notified about updates.

This is a first step which just introduces the type, but doesn't force users to consume changes or remove the current places settings are exposed. Instead, it just encapsulates the changes.

Implementation details

  • Introduce SettingsManager
  • Move code duplicated in DynamicConfigurationManager and ConfigureIntegration into SettingsManager
  • Create a new instance of SettingsManager (and maintain it throughout the app lifetime)
  • Subscribe to changes one time in TracerManager to do the "full rebuild"
    • This is a stop gap before we use it "properly" and stop exposing the settings on TracerSettings

Test coverage

  • Mostly a refactor so covered by integration tests
  • Unit tests for SettingsManager functionality

Other details

https://datadoghq.atlassian.net/browse/LANGPLAT-819

Part of a config stack

@andrewlock andrewlock added area:tracer The core tracer library (Datadog.Trace, does not include OpenTracing, native code, or integrations) type:refactor area:dynamic-configuration labels Oct 22, 2025
andrewlock added a commit that referenced this pull request Oct 22, 2025
…tIntegrationAnalyticsSampleRate()` (#7544)

## Summary of changes

Fix usages of `IsIntegrationEnabled()`, `IsErrorStatusCode()`, and
`GetIntegrationAnalyticsSampleRate()` to use `MutableSettings` instead
of `TracerSettings`

## Reason for change

These functions are dependent on `MutableSettings`, and are exposed
there, so making sure we call the methods there, and remove the
delegation from `TracerSettings` entirely.

## Implementation details

- Find and replace usages
- Remove the old delegating methods

## Test coverage

Just a refactor, so covered by existing tests

## Other details

https://datadoghq.atlassian.net/browse/LANGPLAT-819

Part of a config stack

- #7522
- #7525
- #7530
- #7532
- #7543
- #7544 👈
- #7695
Base automatically changed from andrew/settings/4b-fix-integration-enabled to master October 22, 2025 12:16
@dd-trace-dotnet-ci-bot
Copy link

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

Execution-Time Benchmarks Report ⏱️

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

⚠️ Potential regressions detected

FakeDbCommand

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1117.66 ± (1119.26 - 1129.74) ms1185.48 ± (1186.19 - 1213.63) ms+6.1%❌⬆️
Full Metrics Comparison

FakeDbCommand

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration74.35 ± (74.28 - 75.12) ms74.68 ± (74.66 - 75.29) ms+0.4%✅⬆️
.NET Framework 4.8 - Bailout
duration80.22 ± (79.93 - 80.66) ms79.41 ± (78.91 - 79.64) ms-1.0%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1117.66 ± (1119.26 - 1129.74) ms1185.48 ± (1186.19 - 1213.63) ms+6.1%❌⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms22.89 ± (22.82 - 22.97) ms23.55 ± (23.43 - 23.67) ms+2.8%✅⬆️
process.time_to_main_ms86.97 ± (86.66 - 87.28) ms88.90 ± (88.49 - 89.30) ms+2.2%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.91 ± (10.91 - 10.91) MB10.91 ± (10.91 - 10.92) MB+0.0%✅⬆️
runtime.dotnet.threads.count12 ± (12 - 12)12 ± (12 - 12)+0.0%
.NET Core 3.1 - Bailout
process.internal_duration_ms22.61 ± (22.56 - 22.67) ms23.14 ± (23.04 - 23.24) ms+2.3%✅⬆️
process.time_to_main_ms87.33 ± (87.02 - 87.64) ms89.25 ± (88.84 - 89.66) ms+2.2%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.95 ± (10.95 - 10.95) MB10.96 ± (10.96 - 10.97) MB+0.1%✅⬆️
runtime.dotnet.threads.count13 ± (13 - 13)13 ± (13 - 13)+0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms218.42 ± (216.98 - 219.87) ms219.20 ± (217.69 - 220.71) ms+0.4%✅⬆️
process.time_to_main_ms548.34 ± (547.21 - 549.46) ms544.02 ± (542.84 - 545.20) ms-0.8%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed52.48 ± (52.46 - 52.50) MB52.47 ± (52.45 - 52.49) MB-0.0%
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.0%✅⬆️
.NET 6 - Baseline
process.internal_duration_ms21.65 ± (21.59 - 21.72) ms21.93 ± (21.83 - 22.03) ms+1.3%✅⬆️
process.time_to_main_ms75.20 ± (74.86 - 75.53) ms77.34 ± (76.77 - 77.90) ms+2.8%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.60 ± (10.60 - 10.60) MB10.63 ± (10.62 - 10.63) MB+0.3%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 6 - Bailout
process.internal_duration_ms21.70 ± (21.62 - 21.77) ms21.78 ± (21.71 - 21.85) ms+0.4%✅⬆️
process.time_to_main_ms77.97 ± (77.53 - 78.40) ms76.85 ± (76.51 - 77.19) ms-1.4%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.68 ± (10.67 - 10.68) 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_ms208.08 ± (206.52 - 209.65) ms204.39 ± (203.05 - 205.73) ms-1.8%
process.time_to_main_ms517.01 ± (515.90 - 518.11) ms507.27 ± (506.18 - 508.36) ms-1.9%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed51.60 ± (51.57 - 51.63) MB51.69 ± (51.67 - 51.72) MB+0.2%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.0%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms19.66 ± (19.60 - 19.72) ms20.02 ± (19.95 - 20.08) ms+1.8%✅⬆️
process.time_to_main_ms74.09 ± (73.76 - 74.42) ms75.20 ± (74.92 - 75.48) ms+1.5%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.65 ± (7.65 - 7.66) MB7.65 ± (7.65 - 7.66) MB+0.0%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 8 - Bailout
process.internal_duration_ms19.74 ± (19.68 - 19.80) ms19.64 ± (19.58 - 19.71) ms-0.5%
process.time_to_main_ms76.38 ± (76.06 - 76.69) ms75.59 ± (75.30 - 75.87) ms-1.0%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.71 ± (7.71 - 7.72) MB7.70 ± (7.69 - 7.70) MB-0.2%
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms190.34 ± (189.38 - 191.29) ms191.56 ± (190.68 - 192.44) ms+0.6%✅⬆️
process.time_to_main_ms489.56 ± (488.57 - 490.54) ms485.54 ± (484.57 - 486.51) ms-0.8%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed38.85 ± (38.81 - 38.88) MB38.89 ± (38.85 - 38.92) MB+0.1%✅⬆️
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
duration192.93 ± (193.00 - 193.85) ms192.40 ± (192.34 - 193.23) ms-0.3%
.NET Framework 4.8 - Bailout
duration195.89 ± (195.70 - 196.15) ms195.51 ± (195.32 - 195.77) ms-0.2%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1167.84 ± (1170.49 - 1180.26) ms1167.55 ± (1170.06 - 1179.42) ms-0.0%
.NET Core 3.1 - Baseline
process.internal_duration_ms187.65 ± (187.23 - 188.07) ms187.70 ± (187.43 - 187.98) ms+0.0%✅⬆️
process.time_to_main_ms80.39 ± (80.20 - 80.59) ms80.43 ± (80.22 - 80.63) ms+0.0%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.07 ± (16.04 - 16.10) MB16.07 ± (16.04 - 16.09) MB-0.0%
runtime.dotnet.threads.count20 ± (20 - 20)19 ± (19 - 20)-0.8%
.NET Core 3.1 - Bailout
process.internal_duration_ms187.30 ± (186.99 - 187.61) ms187.73 ± (187.32 - 188.14) ms+0.2%✅⬆️
process.time_to_main_ms81.56 ± (81.44 - 81.68) ms81.98 ± (81.82 - 82.14) ms+0.5%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.15 ± (16.12 - 16.17) MB16.13 ± (16.10 - 16.16) MB-0.1%
runtime.dotnet.threads.count21 ± (20 - 21)21 ± (20 - 21)+0.1%✅⬆️
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms391.93 ± (389.73 - 394.14) ms397.17 ± (394.71 - 399.63) ms+1.3%✅⬆️
process.time_to_main_ms514.76 ± (514.10 - 515.42) ms515.49 ± (514.83 - 516.15) ms+0.1%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed62.85 ± (62.70 - 63.01) MB62.88 ± (62.73 - 63.03) MB+0.0%✅⬆️
runtime.dotnet.threads.count29 ± (29 - 29)29 ± (29 - 30)+0.1%✅⬆️
.NET 6 - Baseline
process.internal_duration_ms191.69 ± (191.29 - 192.08) ms192.41 ± (191.99 - 192.82) ms+0.4%✅⬆️
process.time_to_main_ms69.58 ± (69.41 - 69.75) ms69.69 ± (69.47 - 69.90) ms+0.2%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.08 ± (15.94 - 16.22) MB15.86 ± (15.71 - 16.02) MB-1.3%
runtime.dotnet.threads.count18 ± (18 - 18)18 ± (18 - 18)-0.4%
.NET 6 - Bailout
process.internal_duration_ms190.48 ± (190.15 - 190.81) ms191.17 ± (190.83 - 191.52) ms+0.4%✅⬆️
process.time_to_main_ms70.42 ± (70.31 - 70.53) ms70.60 ± (70.47 - 70.73) ms+0.3%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed15.98 ± (15.82 - 16.13) MB15.88 ± (15.71 - 16.04) MB-0.6%
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)+0.1%✅⬆️
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms413.82 ± (410.59 - 417.04) ms405.24 ± (402.86 - 407.61) ms-2.1%
process.time_to_main_ms485.74 ± (485.15 - 486.32) ms482.44 ± (481.72 - 483.15) ms-0.7%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed62.09 ± (61.95 - 62.23) MB62.04 ± (61.89 - 62.19) MB-0.1%
runtime.dotnet.threads.count29 ± (29 - 29)30 ± (29 - 30)+0.3%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms189.57 ± (189.19 - 189.95) ms189.40 ± (189.06 - 189.74) ms-0.1%
process.time_to_main_ms69.10 ± (68.89 - 69.31) ms68.98 ± (68.83 - 69.13) ms-0.2%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.77 ± (11.73 - 11.82) MB11.73 ± (11.71 - 11.76) MB-0.3%
runtime.dotnet.threads.count18 ± (18 - 18)18 ± (18 - 18)+0.0%✅⬆️
.NET 8 - Bailout
process.internal_duration_ms189.00 ± (188.71 - 189.29) ms189.37 ± (189.02 - 189.72) ms+0.2%✅⬆️
process.time_to_main_ms69.85 ± (69.75 - 69.95) ms70.10 ± (69.97 - 70.24) ms+0.4%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.85 ± (11.81 - 11.88) MB11.75 ± (11.69 - 11.82) MB-0.8%
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)-0.6%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms361.34 ± (359.79 - 362.89) ms362.84 ± (361.51 - 364.17) ms+0.4%✅⬆️
process.time_to_main_ms463.68 ± (463.03 - 464.32) ms458.11 ± (457.51 - 458.70) ms-1.2%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed50.34 ± (50.30 - 50.38) MB50.40 ± (50.36 - 50.43) 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 (7695) - mean (75ms)  : 70, 80
    master - mean (75ms)  : 69, 80

    section Bailout
    This PR (7695) - mean (79ms)  : 74, 85
    master - mean (80ms)  : 75, 86

    section CallTarget+Inlining+NGEN
    This PR (7695) - mean (1,200ms)  : crit, 985, 1414
    master - mean (1,125ms)  : 1046, 1203

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 (7695) - mean (121ms)  : 113, 128
    master - mean (117ms)  : 112, 123

    section Bailout
    This PR (7695) - mean (120ms)  : 113, 127
    master - mean (117ms)  : 111, 124

    section CallTarget+Inlining+NGEN
    This PR (7695) - mean (801ms)  : 748, 855
    master - mean (799ms)  : 749, 848

Loading
FakeDbCommand (.NET 6)
gantt
    title Execution time (ms) FakeDbCommand (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7695) - mean (106ms)  : 97, 115
    master - mean (104ms)  : 97, 111

    section Bailout
    This PR (7695) - mean (106ms)  : 98, 114
    master - mean (106ms)  : 98, 115

    section CallTarget+Inlining+NGEN
    This PR (7695) - mean (745ms)  : 702, 788
    master - mean (757ms)  : 715, 800

Loading
FakeDbCommand (.NET 8)
gantt
    title Execution time (ms) FakeDbCommand (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7695) - mean (104ms)  : 99, 109
    master - mean (102ms)  : 95, 110

    section Bailout
    This PR (7695) - mean (104ms)  : 98, 109
    master - mean (105ms)  : 98, 112

    section CallTarget+Inlining+NGEN
    This PR (7695) - mean (709ms)  : 679, 740
    master - mean (709ms)  : 681, 737

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 (7695) - mean (193ms)  : 189, 197
    master - mean (193ms)  : 188, 199

    section Bailout
    This PR (7695) - mean (196ms)  : 193, 198
    master - mean (196ms)  : 194, 198

    section CallTarget+Inlining+NGEN
    This PR (7695) - mean (1,175ms)  : 1104, 1246
    master - mean (1,175ms)  : 1101, 1250

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 (7695) - mean (277ms)  : 273, 280
    master - mean (277ms)  : 272, 282

    section Bailout
    This PR (7695) - mean (278ms)  : 273, 282
    master - mean (277ms)  : 273, 281

    section CallTarget+Inlining+NGEN
    This PR (7695) - mean (943ms)  : 904, 982
    master - mean (939ms)  : 900, 978

Loading
HttpMessageHandler (.NET 6)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7695) - mean (270ms)  : 265, 275
    master - mean (270ms)  : 264, 275

    section Bailout
    This PR (7695) - mean (270ms)  : 265, 275
    master - mean (269ms)  : 265, 273

    section CallTarget+Inlining+NGEN
    This PR (7695) - mean (918ms)  : 878, 958
    master - mean (929ms)  : 873, 986

Loading
HttpMessageHandler (.NET 8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7695) - mean (268ms)  : 263, 273
    master - mean (269ms)  : 262, 276

    section Bailout
    This PR (7695) - mean (269ms)  : 263, 275
    master - mean (268ms)  : 264, 272

    section CallTarget+Inlining+NGEN
    This PR (7695) - mean (853ms)  : 833, 873
    master - mean (858ms)  : 837, 879

Loading

@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch from c29eb56 to 9c790a3 Compare October 22, 2025 14:05
@pr-commenter
Copy link

pr-commenter bot commented Oct 22, 2025

Benchmarks

Benchmarks Report for benchmark platform 🐌

Benchmarks for #7695 compared to master:

  • 1 benchmarks are slower, with geometric mean 1.140
  • 4 benchmarks have fewer allocations
  • 3 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 #7695

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.ActivityBenchmark.StartStopWithChild‑net472 6.01 KB 6.09 KB 79 B 1.31%
Benchmarks.Trace.ActivityBenchmark.StartStopWithChild‑netcoreapp3.1 5.63 KB 5.69 KB 54 B 0.96%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartStopWithChild net6.0 10.6μs 58.4ns 340ns 0 0 0 5.53 KB
master StartStopWithChild netcoreapp3.1 13.8μs 73.1ns 373ns 0 0 0 5.63 KB
master StartStopWithChild net472 23.9μs 131ns 777ns 1.04 0.313 0.104 6.01 KB
#7695 StartStopWithChild net6.0 10.2μs 56.9ns 373ns 0 0 0 5.53 KB
#7695 StartStopWithChild netcoreapp3.1 13.4μs 69.8ns 342ns 0 0 0 5.69 KB
#7695 StartStopWithChild net472 22.5μs 121ns 664ns 0.888 0.222 0 6.09 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 929μs 172ns 644ns 0 0 0 2.71 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 1.04ms 190ns 735ns 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces net472 1.23ms 915ns 3.54μs 0 0 0 3.31 KB
#7695 WriteAndFlushEnrichedTraces net6.0 949μs 82.6ns 320ns 0 0 0 2.7 KB
#7695 WriteAndFlushEnrichedTraces netcoreapp3.1 1.02ms 143ns 534ns 0 0 0 2.7 KB
#7695 WriteAndFlushEnrichedTraces net472 1.2ms 42.5ns 147ns 0 0 0 3.31 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.04μs 6.32ns 63.2ns 0 0 0 1.22 KB
master AllCycleSimpleBody netcoreapp3.1 1.39μs 7.58ns 42.2ns 0 0 0 1.2 KB
master AllCycleSimpleBody net472 1.08μs 0.104ns 0.39ns 0.194 0 0 1.23 KB
master AllCycleMoreComplexBody net6.0 7.19μs 9.86ns 38.2ns 0 0 0 4.72 KB
master AllCycleMoreComplexBody netcoreapp3.1 8.87μs 42.5ns 170ns 0 0 0 4.62 KB
master AllCycleMoreComplexBody net472 7.67μs 3.37ns 13.1ns 0.728 0 0 4.74 KB
master ObjectExtractorSimpleBody net6.0 318ns 0.0601ns 0.225ns 0 0 0 280 B
master ObjectExtractorSimpleBody netcoreapp3.1 407ns 2.09ns 9.78ns 0 0 0 272 B
master ObjectExtractorSimpleBody net472 300ns 0.0354ns 0.133ns 0.0446 0 0 281 B
master ObjectExtractorMoreComplexBody net6.0 6.21μs 32ns 153ns 0 0 0 3.78 KB
master ObjectExtractorMoreComplexBody netcoreapp3.1 7.92μs 7.77ns 30.1ns 0 0 0 3.69 KB
master ObjectExtractorMoreComplexBody net472 6.69μs 3.6ns 13.9ns 0.6 0 0 3.8 KB
#7695 AllCycleSimpleBody net6.0 1.04μs 6.23ns 62.3ns 0 0 0 1.22 KB
#7695 AllCycleSimpleBody netcoreapp3.1 1.4μs 7.67ns 46ns 0 0 0 1.2 KB
#7695 AllCycleSimpleBody net472 1.02μs 0.295ns 1.1ns 0.194 0 0 1.23 KB
#7695 AllCycleMoreComplexBody net6.0 7.01μs 38.5ns 225ns 0 0 0 4.72 KB
#7695 AllCycleMoreComplexBody netcoreapp3.1 9.05μs 3.41ns 13.2ns 0 0 0 4.62 KB
#7695 AllCycleMoreComplexBody net472 7.57μs 2.1ns 8.12ns 0.721 0 0 4.74 KB
#7695 ObjectExtractorSimpleBody net6.0 317ns 1.75ns 10.8ns 0 0 0 280 B
#7695 ObjectExtractorSimpleBody netcoreapp3.1 404ns 2.08ns 9.73ns 0 0 0 272 B
#7695 ObjectExtractorSimpleBody net472 300ns 0.0658ns 0.255ns 0.0437 0 0 281 B
#7695 ObjectExtractorMoreComplexBody net6.0 6.31μs 30.9ns 131ns 0 0 0 3.78 KB
#7695 ObjectExtractorMoreComplexBody netcoreapp3.1 7.81μs 5.15ns 19.9ns 0 0 0 3.69 KB
#7695 ObjectExtractorMoreComplexBody net472 6.65μs 2.54ns 9.85ns 0.597 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 76.8μs 337ns 1.22μs 0 0 0 32.4 KB
master EncodeArgs netcoreapp3.1 96.7μs 307ns 1.11μs 0 0 0 32.4 KB
master EncodeArgs net472 115μs 16.7ns 64.8ns 4.6 0 0 32.51 KB
master EncodeLegacyArgs net6.0 143μs 22.5ns 78.1ns 0 0 0 2.15 KB
master EncodeLegacyArgs netcoreapp3.1 202μs 77ns 298ns 0 0 0 2.14 KB
master EncodeLegacyArgs net472 265μs 116ns 450ns 0 0 0 2.16 KB
#7695 EncodeArgs net6.0 76.7μs 298ns 1.12μs 0 0 0 32.4 KB
#7695 EncodeArgs netcoreapp3.1 97μs 291ns 1.13μs 0 0 0 32.4 KB
#7695 EncodeArgs net472 109μs 17.9ns 69.3ns 4.92 0 0 32.51 KB
#7695 EncodeLegacyArgs net6.0 141μs 53.3ns 192ns 0 0 0 2.15 KB
#7695 EncodeLegacyArgs netcoreapp3.1 197μs 103ns 372ns 0 0 0 2.14 KB
#7695 EncodeLegacyArgs net472 266μs 37.5ns 135ns 0 0 0 2.16 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 393μs 92ns 332ns 0 0 0 4.55 KB
master RunWafRealisticBenchmark netcoreapp3.1 415μs 562ns 2.02μs 0 0 0 4.48 KB
master RunWafRealisticBenchmark net472 427μs 70.6ns 274ns 0 0 0 4.66 KB
master RunWafRealisticBenchmarkWithAttack net6.0 282μs 29.3ns 113ns 0 0 0 2.24 KB
master RunWafRealisticBenchmarkWithAttack netcoreapp3.1 696μs 10.6μs 102μs 0 0 0 2.22 KB
master RunWafRealisticBenchmarkWithAttack net472 309μs 40.4ns 156ns 0 0 0 2.29 KB
#7695 RunWafRealisticBenchmark net6.0 393μs 112ns 403ns 0 0 0 4.55 KB
#7695 RunWafRealisticBenchmark netcoreapp3.1 410μs 127ns 457ns 0 0 0 4.48 KB
#7695 RunWafRealisticBenchmark net472 432μs 105ns 406ns 0 0 0 4.68 KB
#7695 RunWafRealisticBenchmarkWithAttack net6.0 286μs 47.3ns 177ns 0 0 0 2.24 KB
#7695 RunWafRealisticBenchmarkWithAttack netcoreapp3.1 722μs 3.41μs 14μs 0 0 0 2.22 KB
#7695 RunWafRealisticBenchmarkWithAttack net472 309μs 29.8ns 111ns 0 0 0 2.29 KB
Benchmarks.Trace.AspNetCoreBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendRequest net6.0 59.6μs 48.3ns 181ns 0 0 0 14.52 KB
master SendRequest netcoreapp3.1 71.6μs 136ns 489ns 0 0 0 17.42 KB
master SendRequest net472 0.00482ns 0.00196ns 0.00758ns 0 0 0 0 b
#7695 SendRequest net6.0 61μs 200ns 749ns 0 0 0 14.52 KB
#7695 SendRequest netcoreapp3.1 71.3μs 378ns 1.93μs 0 0 0 17.42 KB
#7695 SendRequest net472 0.00545ns 0.00161ns 0.00624ns 0 0 0 0 b
Benchmarks.Trace.CharSliceBenchmark - Same speed ✔️ More allocations ⚠️

More allocations ⚠️ in #7695

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool‑netcoreapp3.1 0 b 10 B 10 B

Fewer allocations 🎉 in #7695

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice‑net6.0 7 B 4 B -3 B -42.86%
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice‑net472 73 B 0 b -73 B -100.00%
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool‑net472 47 B 0 b -47 B -100.00%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master OriginalCharSlice net6.0 1.87ms 3.8μs 14.2μs 0 0 0 640.01 KB
master OriginalCharSlice netcoreapp3.1 2.14ms 9.79μs 36.6μs 0 0 0 640 KB
master OriginalCharSlice net472 2.66ms 137ns 493ns 100 0 0 641.95 KB
master OptimizedCharSlice net6.0 1.37ms 435ns 1.68μs 0 0 0 7 B
master OptimizedCharSlice netcoreapp3.1 1.67ms 631ns 2.45μs 0 0 0 1 B
master OptimizedCharSlice net472 1.9ms 484ns 1.87μs 0 0 0 73 B
master OptimizedCharSliceWithPool net6.0 800μs 84.8ns 317ns 0 0 0 2 B
master OptimizedCharSliceWithPool netcoreapp3.1 842μs 101ns 390ns 0 0 0 0 b
master OptimizedCharSliceWithPool net472 1.18ms 88.2ns 342ns 0 0 0 47 B
#7695 OriginalCharSlice net6.0 1.92ms 608ns 2.28μs 0 0 0 640.01 KB
#7695 OriginalCharSlice netcoreapp3.1 2.09ms 9.75μs 37.8μs 0 0 0 640 KB
#7695 OriginalCharSlice net472 2.7ms 102ns 367ns 100 0 0 641.95 KB
#7695 OptimizedCharSlice net6.0 1.39ms 198ns 768ns 0 0 0 4 B
#7695 OptimizedCharSlice netcoreapp3.1 1.66ms 396ns 1.54μs 0 0 0 1 B
#7695 OptimizedCharSlice net472 1.93ms 175ns 677ns 0 0 0 0 b
#7695 OptimizedCharSliceWithPool net6.0 840μs 58.8ns 228ns 0 0 0 2 B
#7695 OptimizedCharSliceWithPool netcoreapp3.1 822μs 235ns 879ns 0 0 0 10 B
#7695 OptimizedCharSliceWithPool net472 1.14ms 91.6ns 355ns 0 0 0 0 b
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark - Slower ⚠️ Same allocations ✔️

Slower ⚠️ in #7695

Benchmark diff/base Base Median (ns) Diff Median (ns) Modality
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces‑net472 1.140 918,164.29 1,046,530.00

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 656μs 2.73μs 9.83μs 0 0 0 41.72 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 756μs 3.85μs 18μs 0 0 0 41.86 KB
master WriteAndFlushEnrichedTraces net472 923μs 3.76μs 14.6μs 4.46 0 0 56.02 KB
#7695 WriteAndFlushEnrichedTraces net6.0 665μs 996ns 3.73μs 0 0 0 41.55 KB
#7695 WriteAndFlushEnrichedTraces netcoreapp3.1 740μs 3.5μs 14.4μs 0 0 0 41.86 KB
#7695 WriteAndFlushEnrichedTraces net472 1.05ms 5.17μs 22μs 8.33 0 0 56.29 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.9μs 9.37ns 39.8ns 0 0 0 1.02 KB
master ExecuteNonQuery netcoreapp3.1 2.5μs 7.47ns 28.9ns 0 0 0 1.02 KB
master ExecuteNonQuery net472 2.8μs 3.11ns 12.1ns 0.152 0.0138 0 987 B
#7695 ExecuteNonQuery net6.0 2μs 3.08ns 11.9ns 0 0 0 1.02 KB
#7695 ExecuteNonQuery netcoreapp3.1 2.62μs 10.7ns 41.5ns 0 0 0 1.02 KB
#7695 ExecuteNonQuery net472 2.86μs 3.54ns 13.7ns 0.144 0.0144 0 987 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.73μs 7.96ns 30.8ns 0 0 0 1.03 KB
master CallElasticsearch netcoreapp3.1 2.24μs 7.2ns 27.9ns 0 0 0 1.03 KB
master CallElasticsearch net472 3.48μs 1.88ns 7.28ns 0.156 0 0 1.04 KB
master CallElasticsearchAsync net6.0 1.84μs 1.42ns 4.93ns 0 0 0 1.01 KB
master CallElasticsearchAsync netcoreapp3.1 2.41μs 10.7ns 41.6ns 0 0 0 1.08 KB
master CallElasticsearchAsync net472 3.64μs 3.03ns 11.7ns 0.164 0 0 1.1 KB
#7695 CallElasticsearch net6.0 1.69μs 8.97ns 44.9ns 0 0 0 1.03 KB
#7695 CallElasticsearch netcoreapp3.1 2.16μs 10.6ns 43.8ns 0 0 0 1.03 KB
#7695 CallElasticsearch net472 3.68μs 4.29ns 16.6ns 0.148 0 0 1.04 KB
#7695 CallElasticsearchAsync net6.0 1.86μs 5.42ns 21ns 0 0 0 1.01 KB
#7695 CallElasticsearchAsync netcoreapp3.1 2.5μs 6.34ns 23.7ns 0 0 0 1.08 KB
#7695 CallElasticsearchAsync net472 3.72μs 5.23ns 20.3ns 0.166 0 0 1.1 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.83μs 6.94ns 26ns 0 0 0 952 B
master ExecuteAsync netcoreapp3.1 2.54μs 2.88ns 11.2ns 0 0 0 952 B
master ExecuteAsync net472 2.66μs 3.5ns 13.5ns 0.133 0 0 915 B
#7695 ExecuteAsync net6.0 2.02μs 4.4ns 15.9ns 0 0 0 952 B
#7695 ExecuteAsync netcoreapp3.1 2.51μs 2.22ns 8.59ns 0 0 0 952 B
#7695 ExecuteAsync net472 2.73μs 1.3ns 5.05ns 0.135 0 0 915 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.02μs 7.86ns 30.4ns 0 0 0 2.36 KB
master SendAsync netcoreapp3.1 8.33μs 8.82ns 34.2ns 0 0 0 2.9 KB
master SendAsync net472 12.3μs 9.24ns 35.8ns 0.487 0 0 3.18 KB
#7695 SendAsync net6.0 7.06μs 8.49ns 31.8ns 0 0 0 2.36 KB
#7695 SendAsync netcoreapp3.1 8.96μs 28.4ns 110ns 0 0 0 2.9 KB
#7695 SendAsync net472 12.2μs 4.83ns 18.1ns 0.488 0 0 3.18 KB
Benchmarks.Trace.Iast.StringAspectsBenchmark - Same speed ✔️ Fewer allocations 🎉

Fewer allocations 🎉 in #7695

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net6.0 256.97 KB 248.58 KB -8.39 KB -3.27%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StringConcatBenchmark net6.0 45.2μs 259ns 2.15μs 0 0 0 43.98 KB
master StringConcatBenchmark netcoreapp3.1 49.9μs 257ns 1.23μs 0 0 0 43.34 KB
master StringConcatBenchmark net472 55.9μs 272ns 1.22μs 0 0 0 65.54 KB
master StringConcatAspectBenchmark net6.0 445μs 2.26μs 11.1μs 0 0 0 256.97 KB
master StringConcatAspectBenchmark netcoreapp3.1 525μs 1.79μs 6.2μs 0 0 0 275.83 KB
master StringConcatAspectBenchmark net472 404μs 2.13μs 10.4μs 0 0 0 274.5 KB
#7695 StringConcatBenchmark net6.0 44.7μs 221ns 1.41μs 0 0 0 43.93 KB
#7695 StringConcatBenchmark netcoreapp3.1 49.6μs 281ns 1.91μs 0 0 0 43.22 KB
#7695 StringConcatBenchmark net472 57.5μs 192ns 718ns 0 0 0 65.54 KB
#7695 StringConcatAspectBenchmark net6.0 454μs 2.2μs 9.61μs 0 0 0 248.58 KB
#7695 StringConcatAspectBenchmark netcoreapp3.1 512μs 2.5μs 11.2μs 0 0 0 275.55 KB
#7695 StringConcatAspectBenchmark net472 406μs 2.31μs 16.4μs 0 0 0 275.77 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.64μs 13.9ns 72.3ns 0 0 0 1.7 KB
master EnrichedLog netcoreapp3.1 3.57μs 8.07ns 31.2ns 0 0 0 1.7 KB
master EnrichedLog net472 3.84μs 4.18ns 16.2ns 0.251 0 0 1.64 KB
#7695 EnrichedLog net6.0 2.69μs 1.21ns 4.52ns 0 0 0 1.7 KB
#7695 EnrichedLog netcoreapp3.1 3.49μs 17.1ns 70.4ns 0 0 0 1.7 KB
#7695 EnrichedLog net472 3.92μs 2.29ns 8.87ns 0.254 0 0 1.64 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 123μs 38ns 137ns 0 0 0 4.31 KB
master EnrichedLog netcoreapp3.1 127μs 111ns 401ns 0 0 0 4.31 KB
master EnrichedLog net472 169μs 53.8ns 208ns 0 0 0 4.52 KB
#7695 EnrichedLog net6.0 123μs 119ns 412ns 0 0 0 4.31 KB
#7695 EnrichedLog netcoreapp3.1 131μs 246ns 955ns 0 0 0 4.31 KB
#7695 EnrichedLog net472 168μs 44.6ns 173ns 0 0 0 4.52 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.27μs 15.9ns 59.6ns 0 0 0 2.26 KB
master EnrichedLog netcoreapp3.1 6.62μs 24.1ns 90.1ns 0 0 0 2.26 KB
master EnrichedLog net472 7.64μs 4.03ns 15.1ns 0.306 0 0 2.08 KB
#7695 EnrichedLog net6.0 5.1μs 3.39ns 12.7ns 0 0 0 2.26 KB
#7695 EnrichedLog netcoreapp3.1 6.86μs 19ns 73.7ns 0 0 0 2.26 KB
#7695 EnrichedLog net472 7.52μs 6.25ns 24.2ns 0.3 0 0 2.08 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 2μs 10.1ns 44ns 0 0 0 1.2 KB
master SendReceive netcoreapp3.1 2.59μs 11.8ns 45.7ns 0 0 0 1.2 KB
master SendReceive net472 3.12μs 2.8ns 10.5ns 0.186 0 0 1.2 KB
#7695 SendReceive net6.0 2.02μs 9.27ns 35.9ns 0 0 0 1.2 KB
#7695 SendReceive netcoreapp3.1 2.58μs 13.1ns 57.3ns 0 0 0 1.2 KB
#7695 SendReceive net472 3.26μs 1.25ns 4.85ns 0.18 0 0 1.2 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.35μs 13.7ns 52.9ns 0 0 0 1.58 KB
master EnrichedLog netcoreapp3.1 5.56μs 10.1ns 39.2ns 0 0 0 1.63 KB
master EnrichedLog net472 6.98μs 6.73ns 25.2ns 0.314 0 0 2.03 KB
#7695 EnrichedLog net6.0 4.21μs 5.36ns 20.1ns 0 0 0 1.58 KB
#7695 EnrichedLog netcoreapp3.1 5.7μs 12.3ns 47.8ns 0 0 0 1.63 KB
#7695 EnrichedLog net472 7.05μs 6.44ns 24.9ns 0.316 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 765ns 4.08ns 23.1ns 0 0 0 576 B
master StartFinishSpan netcoreapp3.1 953ns 4.91ns 24.6ns 0 0 0 576 B
master StartFinishSpan net472 950ns 0.151ns 0.545ns 0.09 0 0 578 B
master StartFinishScope net6.0 926ns 0.157ns 0.566ns 0 0 0 696 B
master StartFinishScope netcoreapp3.1 1.19μs 5.65ns 22.6ns 0 0 0 696 B
master StartFinishScope net472 1.14μs 0.698ns 2.7ns 0.103 0 0 658 B
#7695 StartFinishSpan net6.0 775ns 3.94ns 17.2ns 0 0 0 576 B
#7695 StartFinishSpan netcoreapp3.1 967ns 5.06ns 23.2ns 0 0 0 576 B
#7695 StartFinishSpan net472 1μs 0.351ns 1.36ns 0.0893 0 0 578 B
#7695 StartFinishScope net6.0 923ns 3.1ns 11.6ns 0 0 0 696 B
#7695 StartFinishScope netcoreapp3.1 1.2μs 6.51ns 35.7ns 0 0 0 696 B
#7695 StartFinishScope net472 1.23μs 1.03ns 4ns 0.0988 0 0 658 B
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.08μs 1.08ns 4.19ns 0 0 0 696 B
master RunOnMethodBegin netcoreapp3.1 1.4μs 6.58ns 24.6ns 0 0 0 696 B
master RunOnMethodBegin net472 1.45μs 1.06ns 4.09ns 0.101 0 0 658 B
#7695 RunOnMethodBegin net6.0 1.03μs 5.63ns 31.4ns 0 0 0 696 B
#7695 RunOnMethodBegin netcoreapp3.1 1.43μs 5.36ns 20.8ns 0 0 0 696 B
#7695 RunOnMethodBegin net472 1.47μs 1.48ns 5.74ns 0.104 0 0 658 B

@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch from 9c790a3 to 9f05223 Compare October 22, 2025 16:39
@andrewlock
Copy link
Member Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Chef's kiss.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch from 9f05223 to 6b9a134 Compare October 24, 2025 16:42
@datadog-datadog-prod-us1

This comment has been minimized.

@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch from 6b9a134 to c04decc Compare October 28, 2025 12:46
@andrewlock andrewlock changed the base branch from master to andrew/settings/4b-helper October 28, 2025 13:11
@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch from c04decc to 60c7874 Compare October 28, 2025 13:41
@andrewlock andrewlock force-pushed the andrew/settings/4b-helper branch from a6b40ae to 1ed4e84 Compare October 28, 2025 13:41
@andrewlock andrewlock marked this pull request as ready for review October 28, 2025 13:41
@andrewlock andrewlock requested review from a team as code owners October 28, 2025 13:41
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch from 60c7874 to c691a0e Compare October 28, 2025 15:20
@andrewlock andrewlock force-pushed the andrew/settings/4b-helper branch from 1ed4e84 to 1477479 Compare October 28, 2025 15:20
andrewlock

This comment was marked as resolved.

andrewlock

This comment was marked as resolved.

@andrewlock andrewlock requested review from a team as code owners October 31, 2025 18:04
@andrewlock andrewlock force-pushed the andrew/settings/4b-helper branch from e27c515 to 41ce09f Compare October 31, 2025 18:04
Base automatically changed from andrew/settings/4b-helper to master November 3, 2025 14:40
andrewlock added a commit that referenced this pull request Nov 3, 2025
## Summary of changes

Add a helper for comparing `ReadOnlyDictionary<>` instances

## Reason for change

As part of the config work, we need to detect if tags have changed when
customers do a manual/remote config update. This helper makes it easy

## Implementation details

Added a `SequenceEqual` extension method.

Note that I used `SequenceEqual` because it _already_ exists in
_System.Linq_, but I could see an argument that it's too easy to use the
wrong one, and instead we could use a different name? `IsSameAs(other)`?

Also, I only wrote this for `ReadOnlyDictionary<>` because that's all we
need, it's what we use for all our setting dictionaries, and it will be
(a tiny bit) faster than making it `IDictionary<>`, but happy to change
if people feel strongly.

## Test coverage

Added unit tests

## Other details

https://datadoghq.atlassian.net/browse/LANGPLAT-819

Part of a config stack


- #7522
- #7525
- #7530
- #7532
- #7543
- #7544
- #7721
- #7722 👈
- #7695
- #7723
- #7724

---------

Co-authored-by: Steven Bouwkamp <[email protected]>
@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch 3 times, most recently from 21e9e1c to 67beb6a Compare November 6, 2025 08:32
{
if (BuildNewSettings(dynamicConfigSource, manualSource, centralTelemetry) is { } newSettings)
{
NotifySubscribers(newSettings);
Copy link
Member

Choose a reason for hiding this comment

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

If two threads call UpdateSettings(), could there be a race condition where NotifySubscribers() is also called twice, since both can see the same _latest value in BuildNewSettings() below?

Ignore if you already considered this and decided that was acceptable.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmmm, yeah, good catch 🤔 This could happen if a customer calls Tracer.Configure() with manual instrumentation at the same time as remote config does a dynamic config update. I'd always expect two distinct calls in that case, and I think there would be races elsewhere, before this is called that I need to 👀 again (despite considering this at the time 😅)

Maybe I should stop trying to be cute and should just lock this whole UpdateSettings call... I was a bit concerned about doing that because it's relatively expensive, but I think otherwise we're just going to be fighting edge cases...

Copy link
Member

Choose a reason for hiding this comment

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

To be fair, calling NotifySubscribers() twice with the same settings is not the worst thing in the world.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, my (minor) concern is more around a mis-match of settings, if manual and remote config is happening at the same time. I think, currently, in that scenario, you could end up with a weird situation where you get the following:

  • Initially: no manual config, no remote config
  • Manual config and remote config happens at the same time, with conflicting values
    • Manual updates the "global" manual config source
    • Remote updates the "global" remote config source
    • This happens concurrently, and neither "sees" the update changes
  • Consumers get two updates:
  • One with the new manual config and the old remote config
  • One with the old manual config and the new remote config
  • Neither is correct 😅

So I think we need some locks around the global config updates... I'll add those in (technically not related to this PR, but makes sense to include here)

Copy link
Member Author

Choose a reason for hiding this comment

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

I reworked this quite a lot:

  • Instead of storing the manual and dynamic config sources as static globals, store them on SettingsManager
    • This is practically equivalent, because we only create a single TracerSettings instance in production, but it makes things much easier to reason about and manage
  • Have specific methods for "update manual" and "update dynamic config". That way we can lock inside these methods and avoid the specific scenario I described above
  • Locking around the whole update process avoids any future edge cases we might hit. They're very much edge cases, but given these updates should be relatively rare, I think playing it safest makes sense. There's not much to be gained by trying to reduce how long the lock is held.

Thanks for the 👀!

@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch from 67beb6a to 920071a Compare November 7, 2025 18:09
Copy link
Collaborator

@bouwkast bouwkast left a comment

Choose a reason for hiding this comment

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

👍

@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch from 9aa97ec to 98a10b7 Compare November 11, 2025 10:04
@andrewlock andrewlock force-pushed the andrew/settings/4-mutable-settings-service branch from 98a10b7 to 696fee1 Compare November 14, 2025 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:dynamic-configuration area:tracer The core tracer library (Datadog.Trace, does not include OpenTracing, native code, or integrations) type:refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants