Skip to content

Detect whether an app has been trimmed#8281

Merged
andrewlock merged 12 commits into
masterfrom
andrew/detect-trimming
Mar 12, 2026
Merged

Detect whether an app has been trimmed#8281
andrewlock merged 12 commits into
masterfrom
andrew/detect-trimming

Conversation

@andrewlock

@andrewlock andrewlock commented Mar 9, 2026

Copy link
Copy Markdown
Member

Summary of changes

Detects whether an app has been published with trimming and whether our Trimming.xml file has been used.

Reason for change

Using trimming and not using our trimming file can cause all sorts of strange errors. It would be useful for support (and for informing customers) if an app is using trimming and is not using our trimming file

Implementation details

Uses three Types in the BCL as "probes" for whether an app is trimmed:

  • System.Resources.ResourceWriter, System.Resources.Writer
  • System.IO.IsolatedStorage.IsolatedStorageScope, System.IO.IsolatedStorage
  • System.Net.NetworkInformation.PingCompletedEventArgs, System.Net.Ping

These are intentionally somewhat obtuse types that we would expect to be trimmed. Settled on them by iterating with 🤖 but we could certainly change these.

The overall approach is

  • Try to load the first two types. These are manually specified in our trimming file, so if we fail to load either one, then we know we are in a trimmed app, and they didn't add our file
  • Try to load the third type, which isn't in our trimming file. If it loads, we're not trimmed at all. If it doesn't load, we're in a trimmed app, but they did add our file.

If we detect the bad situation, we add a warning to the logs. Either way, we tag the telemetry error logs with trim:err/yes/no where:

  • err is trimmed and didn't add our file
  • yes is trimmed but they added our file
  • no not trimmed

Test coverage

  • Updated unit tests
  • Added integration test about telemetry error logs in app trimming scenario

Pushed an initial test without adding anything to the trimming file, and confirmed that we tagged as err and write the error log (which correctly caused the integration tests and trimming smoke tests to fail).

Other details

The main consideration is the performance impact of loading these extra types, from obtuse assemblies, on the hot path of app load. Each of the assemblies is ~80kb (I swapped from System.Net.Mail because it's ~5x as big), but then there's the dependency tree too... I considered using an ACL and unloading, but as I understand it, that wouldn't necessarily actually unload them, seeing as they're part of the shared framework, but I confess I'm trusting the AI on that one 😅

@pr-commenter

pr-commenter Bot commented Mar 9, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-03-11 16:44:56

Comparing candidate commit 4e4bce1 in PR branch andrew/detect-trimming with baseline commit c976de1 in branch master.

Found 6 performance improvements and 7 performance regressions! Performance is the same for 168 metrics, 11 unstable metrics.

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net6.0

  • 🟥 execution_time [+97.824ms; +97.906ms] or [+95.895%; +95.974%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net6.0

  • 🟥 execution_time [+10.321ms; +15.978ms] or [+5.221%; +8.082%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net6.0

  • 🟩 execution_time [-24.417ms; -18.097ms] or [-11.148%; -8.262%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1

  • 🟥 execution_time [+10.673ms; +14.776ms] or [+7.139%; +9.884%]
  • 🟥 throughput [-131.512op/s; -91.129op/s] or [-8.777%; -6.082%]

scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net6.0

  • 🟩 execution_time [-63.317µs; -60.256µs] or [-5.812%; -5.531%]
  • 🟩 throughput [+53.848op/s; +56.539op/s] or [+5.866%; +6.159%]

scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net6.0

  • 🟥 execution_time [+144.275µs; +205.858µs] or [+7.498%; +10.699%]
  • 🟥 throughput [-51.312op/s; -36.245op/s] or [-9.865%; -6.968%]

scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog netcoreapp3.1

  • 🟩 throughput [+17669.299op/s; +23393.822op/s] or [+6.749%; +8.936%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net6.0

  • 🟩 execution_time [-850.939µs; -773.428µs] or [-65.877%; -59.876%]

scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net472

  • 🟥 throughput [-31774.939op/s; -30306.967op/s] or [-8.213%; -7.833%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore netcoreapp3.1

  • 🟩 throughput [+14498720.420op/s; +15755141.600op/s] or [+6.423%; +6.980%]

@dd-trace-dotnet-ci-bot

dd-trace-dotnet-ci-bot Bot commented Mar 9, 2026

Copy link
Copy Markdown

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (8281) 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
duration73.59 ± (73.51 - 73.78) ms73.31 ± (73.28 - 73.57) ms-0.4%
.NET Framework 4.8 - Bailout
duration78.57 ± (78.40 - 78.74) ms77.46 ± (77.25 - 77.58) ms-1.4%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1088.53 ± (1088.57 - 1095.13) ms1071.47 ± (1075.82 - 1084.53) ms-1.6%
.NET Core 3.1 - Baseline
process.internal_duration_ms23.00 ± (22.93 - 23.08) ms22.70 ± (22.65 - 22.74) ms-1.3%
process.time_to_main_ms87.12 ± (86.80 - 87.44) ms84.99 ± (84.79 - 85.18) ms-2.4%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.91 ± (10.91 - 10.92) MB10.90 ± (10.89 - 10.90) MB-0.1%
runtime.dotnet.threads.count12 ± (12 - 12)12 ± (12 - 12)+0.0%
.NET Core 3.1 - Bailout
process.internal_duration_ms22.95 ± (22.90 - 23.00) ms22.61 ± (22.57 - 22.66) ms-1.5%
process.time_to_main_ms88.40 ± (88.17 - 88.64) ms86.31 ± (86.10 - 86.51) ms-2.4%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.95 ± (10.94 - 10.95) MB10.92 ± (10.91 - 10.92) MB-0.3%
runtime.dotnet.threads.count13 ± (13 - 13)13 ± (13 - 13)+0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms245.52 ± (241.38 - 249.67) ms249.96 ± (246.08 - 253.84) ms+1.8%✅⬆️
process.time_to_main_ms493.48 ± (492.77 - 494.19) ms490.44 ± (489.77 - 491.12) ms-0.6%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed47.52 ± (47.50 - 47.55) MB47.70 ± (47.68 - 47.72) MB+0.4%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.2%✅⬆️
.NET 6 - Baseline
process.internal_duration_ms21.67 ± (21.62 - 21.71) ms21.40 ± (21.36 - 21.44) ms-1.3%
process.time_to_main_ms74.68 ± (74.51 - 74.86) ms73.82 ± (73.65 - 74.00) ms-1.1%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.63 ± (10.62 - 10.63) MB10.61 ± (10.61 - 10.62) MB-0.1%
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 6 - Bailout
process.internal_duration_ms21.57 ± (21.52 - 21.61) ms21.21 ± (21.17 - 21.26) ms-1.6%
process.time_to_main_ms75.21 ± (75.02 - 75.40) ms74.46 ± (74.27 - 74.66) ms-1.0%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.68 ± (10.67 - 10.68) MB10.74 ± (10.73 - 10.74) MB+0.5%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms255.62 ± (252.68 - 258.56) ms258.49 ± (256.09 - 260.89) ms+1.1%✅⬆️
process.time_to_main_ms468.89 ± (468.18 - 469.61) ms469.80 ± (469.06 - 470.53) ms+0.2%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed48.36 ± (48.34 - 48.38) MB48.49 ± (48.46 - 48.51) MB+0.3%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.0%
.NET 8 - Baseline
process.internal_duration_ms19.73 ± (19.69 - 19.77) ms19.56 ± (19.52 - 19.59) ms-0.9%
process.time_to_main_ms73.98 ± (73.82 - 74.14) ms72.81 ± (72.66 - 72.96) ms-1.6%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.65 ± (7.65 - 7.66) MB7.67 ± (7.66 - 7.68) MB+0.3%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 8 - Bailout
process.internal_duration_ms19.68 ± (19.64 - 19.72) ms19.60 ± (19.56 - 19.64) ms-0.4%
process.time_to_main_ms75.04 ± (74.85 - 75.23) ms73.58 ± (73.46 - 73.70) ms-1.9%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.72 ± (7.71 - 7.73) MB7.71 ± (7.71 - 7.72) MB-0.1%
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms189.10 ± (188.15 - 190.06) ms189.33 ± (188.44 - 190.23) ms+0.1%✅⬆️
process.time_to_main_ms451.81 ± (451.00 - 452.63) ms454.13 ± (453.45 - 454.81) ms+0.5%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed36.14 ± (36.09 - 36.20) MB36.27 ± (36.23 - 36.31) MB+0.4%✅⬆️
runtime.dotnet.threads.count27 ± (27 - 27)27 ± (27 - 27)-0.1%

HttpMessageHandler

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration193.60 ± (193.19 - 194.07) ms192.87 ± (192.93 - 193.73) ms-0.4%
.NET Framework 4.8 - Bailout
duration195.66 ± (195.50 - 195.94) ms195.84 ± (195.63 - 196.20) ms+0.1%✅⬆️
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1141.64 ± (1140.99 - 1146.79) ms1144.88 ± (1146.02 - 1152.47) ms+0.3%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms190.79 ± (190.45 - 191.12) ms187.43 ± (187.10 - 187.76) ms-1.8%
process.time_to_main_ms81.42 ± (81.19 - 81.64) ms80.55 ± (80.33 - 80.78) ms-1.1%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.17 ± (16.15 - 16.20) MB16.14 ± (16.11 - 16.17) MB-0.2%
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)+0.3%✅⬆️
.NET Core 3.1 - Bailout
process.internal_duration_ms188.75 ± (188.39 - 189.11) ms187.19 ± (186.87 - 187.51) ms-0.8%
process.time_to_main_ms82.54 ± (82.37 - 82.72) ms81.89 ± (81.76 - 82.03) ms-0.8%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.25 ± (16.23 - 16.28) MB16.17 ± (16.10 - 16.24) MB-0.5%
runtime.dotnet.threads.count21 ± (21 - 21)20 ± (20 - 20)-1.2%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms440.86 ± (438.89 - 442.84) ms440.62 ± (438.63 - 442.61) ms-0.1%
process.time_to_main_ms473.04 ± (472.38 - 473.70) ms474.50 ± (473.93 - 475.07) ms+0.3%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed57.75 ± (57.64 - 57.86) MB57.92 ± (57.79 - 58.04) MB+0.3%✅⬆️
runtime.dotnet.threads.count29 ± (29 - 30)29 ± (29 - 29)-0.1%
.NET 6 - Baseline
process.internal_duration_ms191.70 ± (191.36 - 192.04) ms192.72 ± (192.32 - 193.12) ms+0.5%✅⬆️
process.time_to_main_ms69.92 ± (69.73 - 70.11) ms70.30 ± (70.12 - 70.47) ms+0.5%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.31 ± (16.22 - 16.41) MB15.90 ± (15.75 - 16.05) MB-2.5%
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (18 - 19)-0.8%
.NET 6 - Bailout
process.internal_duration_ms192.34 ± (191.91 - 192.78) ms191.68 ± (191.39 - 191.98) ms-0.3%
process.time_to_main_ms71.02 ± (70.86 - 71.18) ms70.94 ± (70.81 - 71.06) ms-0.1%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.13 ± (15.98 - 16.27) MB16.01 ± (15.86 - 16.16) MB-0.7%
runtime.dotnet.threads.count19 ± (19 - 20)19 ± (19 - 19)-1.3%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms452.75 ± (450.98 - 454.52) ms455.74 ± (453.76 - 457.72) ms+0.7%✅⬆️
process.time_to_main_ms451.48 ± (450.96 - 452.00) ms453.97 ± (453.37 - 454.57) ms+0.6%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed57.95 ± (57.85 - 58.04) MB58.16 ± (58.05 - 58.27) MB+0.4%✅⬆️
runtime.dotnet.threads.count29 ± (29 - 30)29 ± (29 - 29)-0.3%
.NET 8 - Baseline
process.internal_duration_ms190.16 ± (189.74 - 190.57) ms190.04 ± (189.71 - 190.37) ms-0.1%
process.time_to_main_ms69.43 ± (69.26 - 69.60) ms69.76 ± (69.54 - 69.97) ms+0.5%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.69 ± (11.67 - 11.72) MB11.80 ± (11.77 - 11.82) MB+0.9%✅⬆️
runtime.dotnet.threads.count18 ± (18 - 18)18 ± (18 - 18)+0.4%✅⬆️
.NET 8 - Bailout
process.internal_duration_ms189.42 ± (189.08 - 189.76) ms189.94 ± (189.48 - 190.40) ms+0.3%✅⬆️
process.time_to_main_ms70.43 ± (70.30 - 70.55) ms70.61 ± (70.49 - 70.72) ms+0.3%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.80 ± (11.77 - 11.83) MB11.81 ± (11.78 - 11.84) MB+0.1%✅⬆️
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)+0.1%✅⬆️
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms365.56 ± (364.21 - 366.92) ms368.13 ± (366.63 - 369.63) ms+0.7%✅⬆️
process.time_to_main_ms432.68 ± (431.89 - 433.47) ms437.34 ± (436.74 - 437.94) ms+1.1%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed47.83 ± (47.79 - 47.87) MB47.97 ± (47.94 - 48.00) MB+0.3%✅⬆️
runtime.dotnet.threads.count29 ± (29 - 29)29 ± (29 - 29)+0.0%✅⬆️
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 (8281) - mean (73ms)  : 71, 75
    master - mean (74ms)  : 72, 75

    section Bailout
    This PR (8281) - mean (77ms)  : 76, 79
    master - mean (79ms)  : 77, 81

    section CallTarget+Inlining+NGEN
    This PR (8281) - mean (1,080ms)  : 1017, 1143
    master - mean (1,092ms)  : 1045, 1138

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 (8281) - mean (115ms)  : 111, 119
    master - mean (118ms)  : 112, 124

    section Bailout
    This PR (8281) - mean (116ms)  : 113, 118
    master - mean (119ms)  : 116, 122

    section CallTarget+Inlining+NGEN
    This PR (8281) - mean (769ms)  : 709, 829
    master - mean (773ms)  : 712, 835

Loading
FakeDbCommand (.NET 6)
gantt
    title Execution time (ms) FakeDbCommand (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8281) - mean (102ms)  : 98, 105
    master - mean (103ms)  : 100, 106

    section Bailout
    This PR (8281) - mean (102ms)  : 99, 105
    master - mean (103ms)  : 101, 106

    section CallTarget+Inlining+NGEN
    This PR (8281) - mean (755ms)  : 701, 810
    master - mean (749ms)  : 685, 813

Loading
FakeDbCommand (.NET 8)
gantt
    title Execution time (ms) FakeDbCommand (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8281) - mean (100ms)  : 98, 102
    master - mean (101ms)  : 99, 104

    section Bailout
    This PR (8281) - mean (101ms)  : 99, 102
    master - mean (103ms)  : 99, 106

    section CallTarget+Inlining+NGEN
    This PR (8281) - mean (671ms)  : 653, 690
    master - mean (669ms)  : 650, 688

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 (8281) - mean (193ms)  : 189, 197
    master - mean (194ms)  : 189, 198

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

    section CallTarget+Inlining+NGEN
    This PR (8281) - mean (1,149ms)  : 1103, 1195
    master - mean (1,144ms)  : 1102, 1185

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 (8281) - mean (276ms)  : 270, 282
    master - mean (281ms)  : 276, 285

    section Bailout
    This PR (8281) - mean (277ms)  : 274, 281
    master - mean (279ms)  : 274, 284

    section CallTarget+Inlining+NGEN
    This PR (8281) - mean (943ms)  : 911, 975
    master - mean (943ms)  : 907, 979

Loading
HttpMessageHandler (.NET 6)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8281) - mean (271ms)  : 266, 277
    master - mean (270ms)  : 265, 274

    section Bailout
    This PR (8281) - mean (270ms)  : 267, 273
    master - mean (271ms)  : 266, 276

    section CallTarget+Inlining+NGEN
    This PR (8281) - mean (938ms)  : 902, 975
    master - mean (934ms)  : 904, 964

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

    section Bailout
    This PR (8281) - mean (270ms)  : 264, 275
    master - mean (269ms)  : 263, 275

    section CallTarget+Inlining+NGEN
    This PR (8281) - mean (838ms)  : 810, 866
    master - mean (828ms)  : 810, 846

Loading

@andrewlock
andrewlock force-pushed the andrew/detect-trimming branch from a75f5b7 to 6ed5beb Compare March 10, 2026 10:34
@andrewlock
andrewlock marked this pull request as ready for review March 10, 2026 16:51
@andrewlock
andrewlock requested review from a team as code owners March 10, 2026 16:51
@andrewlock
andrewlock requested a review from Copilot March 10, 2026 16:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds runtime detection for whether a customer app was published with trimming and whether the Datadog.Trace.Trimming descriptor was applied, surfacing the result via telemetry/log tags and a startup warning to aid supportability.

Changes:

  • Introduces TrimmingDetector (NET6+) that probes for selected BCL types to classify trimming state.
  • Adds trim:err/yes/no tagging to telemetry error-log tags and records new config telemetry flags.
  • Updates unit/integration tests and trimming/build artifacts to preserve “canary” types and validate behavior in trimmed sample apps.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tracer/test/test-applications/integrations/Samples.Trimming/Program.cs Adds an env-var-controlled reflected call to emit an error log for telemetry assertions.
tracer/test/Datadog.Trace.Tests/Telemetry/TelemetryControllerLogTagBuilderTests.cs Updates expected log tag strings to include the new trim:no suffix on NET6+.
tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/TelemetryTests.cs Ensures redacted error logs include trim:no on NET6+.
tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AppTrimmingTests.cs Adds an integration test validating trim:yes in trimmed app telemetry error logs.
tracer/src/Datadog.Trace/Telemetry/TelemetryController.cs Appends trim:err/yes/no to telemetry log tags (NET6+).
tracer/src/Datadog.Trace/Telemetry/DTOs/ConfigTelemetryData.cs Adds config telemetry keys for trimming detection outcomes.
tracer/src/Datadog.Trace/PlatformHelpers/TrimmingDetector.cs New detector that classifies trimming state by probing for specific BCL types (NET6+).
tracer/src/Datadog.Trace/Configuration/TracerSettings.cs Records trimming detection results into configuration telemetry (NET6+).
tracer/src/Datadog.Trace/ClrProfiler/Instrumentation.cs Emits a warning when trimming is detected without the trimming descriptor (NET6+).
tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml Preserves canary BCL types needed by the trimming detector.
tracer/build/_build/Build.Steps.cs Ensures generated trimming descriptor includes canary types; ignores the new test log line in error-log scanning.

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

Comment thread tracer/build/_build/Build.Steps.cs Outdated
Comment thread tracer/build/_build/Build.Steps.cs Outdated

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

Copy link
Copy Markdown

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.

Reviewed commit: a23b88fb9b

ℹ️ 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".

Comment on lines +33 to +34
if (Type.GetType("System.Resources.ResourceWriter, System.Resources.Writer", throwOnError: false) is null
|| Type.GetType("System.IO.IsolatedStorage.IsolatedStorageScope, System.IO.IsolatedStorage", throwOnError: false) is null)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Detect missing trim file without relying on two canary types

This branch assumes that if ResourceWriter and IsolatedStorageScope are present then the app must be using Datadog.Trace.Trimming.xml, but that is not guaranteed: a trimmed app can preserve both types through its own code or transitive dependencies even when our trim descriptor is not referenced. In that case this detector reports TrimmedAppUsingTrimmingFile instead of TrimmedAppMissingTrimmingFile, so the startup warning in Instrumentation.InitializeNoNativeParts() is skipped and support telemetry is mislabeled for the exact failure mode this change is trying to surface.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, that's the point 🙄

@bouwkast

Copy link
Copy Markdown
Collaborator

Maybe a silly question but instead of Ping could we use something from Microsoft.VisualBasic.Core?

Obviously we'd need to still choose something that is still obscure (and there aren't a ton of options) like an attribute? https://github.com/dotnet/dotnet/blob/main/src/runtime/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/HideModuleNameAttribute.vb

@bouwkast bouwkast left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

Only thing I was wondering if we should use something other than that Ping object #8281 (comment)

$",prof:{(_isProfilingEnabled ? '1' : '0')}" +
$",dyn:{(_isDynamicInstrumentationEnabled ? '1' : '0')}" +
#if NET6_0_OR_GREATER
$",trim:{(trimState == TrimmingDetector.TrimState.TrimmedAppMissingTrimmingFile

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice will be helpful 👍

Comment thread tracer/src/Datadog.Trace/Telemetry/TelemetryController.cs
@andrewlock

Copy link
Copy Markdown
Member Author

Maybe a silly question but instead of Ping could we use something from Microsoft.VisualBasic.Core?

Obviously we'd need to still choose something that is still obscure (and there aren't a ton of options) like an attribute? https://github.com/dotnet/dotnet/blob/main/src/runtime/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/HideModuleNameAttribute.vb

Yeah, I considered it, and actually initially discounted it because obvs people using VB would have it loaded and give a false positive, but that does seem very unlikely 😅

However... it's 1.1MB... and it has a ton of references too, so I think it will end up being a lot "heavier" than Ping. Just to be clear, was your reasoning that it would provide a better signal to noise ratio than Ping?

@bouwkast

Copy link
Copy Markdown
Collaborator

Maybe a silly question but instead of Ping could we use something from Microsoft.VisualBasic.Core?
Obviously we'd need to still choose something that is still obscure (and there aren't a ton of options) like an attribute? https://github.com/dotnet/dotnet/blob/main/src/runtime/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/HideModuleNameAttribute.vb

Yeah, I considered it, and actually initially discounted it because obvs people using VB would have it loaded and give a false positive, but that does seem very unlikely 😅

However... it's 1.1MB... and it has a ton of references too, so I think it will end up being a lot "heavier" than Ping. Just to be clear, was your reasoning that it would provide a better signal to noise ratio than Ping?

Yep I just assumed that the people using VB.NET these days may be less than the people using Ping, but if it is 1.1MB I'd say ping is good 👍

@tonyredondo tonyredondo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@andrewlock
andrewlock merged commit fb1ebae into master Mar 12, 2026
142 checks passed
@andrewlock
andrewlock deleted the andrew/detect-trimming branch March 12, 2026 15:07
@github-actions github-actions Bot added this to the vNext-v3 milestone Mar 12, 2026
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.

4 participants