Skip to content

Extract Datadog.AutoInstrumentation.Generator.Core shared library#8312

Merged
bouwkast merged 1 commit into
masterfrom
steven/auto-instrumentation-gen-core
Apr 23, 2026
Merged

Extract Datadog.AutoInstrumentation.Generator.Core shared library#8312
bouwkast merged 1 commit into
masterfrom
steven/auto-instrumentation-gen-core

Conversation

@bouwkast

Copy link
Copy Markdown
Collaborator

Summary of changes

This extracts the instrumentation code generation core from the GUI Datadog.AutoInstrumentation.Generator into a Core library that can be re-used in an upcoming CLI (mainly for LLM consumption).

Reason for change

We'd like to try and automate some of our validation logic that determines if our auto instrumentations still function with newer NuGet versions of the underlying libraries. Currently we rely upon just re-running CI against those tests, but this would allow us to build in the ability to in the future deterministically generate the code from one version to the next which will help with validating whether we are still functional.

Additionally, we'd like to help some ongoing initiatives to aid in the generation / support of auto-instrumentations via LLMs and this will set us up to be able to create a CLI that can be used by LLMs.

Implementation details

New Datadog.AutoInstrumentation.Generator.Core, you will see the "File renamed without changes." are the extracted files.

Main important changes:

  • AssemblyBrowser - assembly / method resolution logic that was in the MainViewModel
  • GenerationConfiguration takes all of the previous checkbox bool flags into a single object. Used by CreateForMethod() that handles the various async/static/void logic.
  • GenerationResult contains all the generated code stuff
  • InstrumentMethodMetadata - [InstrumentMethod] attribute values.

The GUI project now depends on Core and delegates all generation logic to it.

Test coverage

I re-ran the GUI and it seems all functional.

Other details

This is the base PR for another

Claude Code generated

@bouwkast bouwkast added the AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos label Mar 16, 2026
@dd-trace-dotnet-ci-bot

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

Copy link
Copy Markdown

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (8312) 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
duration75.89 ± (75.82 - 76.16) ms73.70 ± (73.81 - 74.22) ms-2.9%
.NET Framework 4.8 - Bailout
duration81.23 ± (81.03 - 81.42) ms78.20 ± (78.07 - 78.46) ms-3.7%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1108.04 ± (1109.03 - 1114.66) ms1082.64 ± (1083.49 - 1089.22) ms-2.3%
.NET Core 3.1 - Baseline
process.internal_duration_ms23.39 ± (23.33 - 23.45) ms22.72 ± (22.68 - 22.76) ms-2.9%
process.time_to_main_ms89.84 ± (89.62 - 90.06) ms86.21 ± (86.00 - 86.41) ms-4.0%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.92 ± (10.91 - 10.92) MB10.91 ± (10.91 - 10.91) MB-0.1%
runtime.dotnet.threads.count12 ± (12 - 12)12 ± (12 - 12)+0.0%
.NET Core 3.1 - Bailout
process.internal_duration_ms23.25 ± (23.19 - 23.31) ms22.65 ± (22.60 - 22.71) ms-2.6%
process.time_to_main_ms90.51 ± (90.27 - 90.75) ms88.77 ± (88.53 - 89.00) ms-1.9%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.95 ± (10.94 - 10.95) MB10.92 ± (10.92 - 10.93) MB-0.2%
runtime.dotnet.threads.count13 ± (13 - 13)13 ± (13 - 13)+0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms233.55 ± (232.37 - 234.72) ms228.18 ± (227.07 - 229.28) ms-2.3%
process.time_to_main_ms543.66 ± (542.52 - 544.79) ms529.84 ± (528.56 - 531.12) ms-2.5%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed47.82 ± (47.79 - 47.85) MB47.73 ± (47.70 - 47.76) MB-0.2%
runtime.dotnet.threads.count28 ± (28 - 29)28 ± (28 - 28)-1.1%
.NET 6 - Baseline
process.internal_duration_ms22.00 ± (21.95 - 22.05) ms21.36 ± (21.31 - 21.41) ms-2.9%
process.time_to_main_ms77.58 ± (77.39 - 77.77) ms74.62 ± (74.42 - 74.83) ms-3.8%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.63 ± (10.62 - 10.63) MB10.63 ± (10.62 - 10.63) MB-0.0%
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 6 - Bailout
process.internal_duration_ms21.89 ± (21.84 - 21.95) ms21.44 ± (21.40 - 21.49) ms-2.1%
process.time_to_main_ms79.02 ± (78.82 - 79.22) ms75.92 ± (75.73 - 76.11) ms-3.9%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.74 ± (10.74 - 10.74) MB10.75 ± (10.74 - 10.75) MB+0.1%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms385.29 ± (383.04 - 387.55) ms384.36 ± (381.99 - 386.73) ms-0.2%
process.time_to_main_ms544.30 ± (542.82 - 545.78) ms528.88 ± (527.90 - 529.85) ms-2.8%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed49.82 ± (49.79 - 49.85) MB50.02 ± (49.99 - 50.05) MB+0.4%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.1%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms20.25 ± (20.21 - 20.29) ms19.61 ± (19.57 - 19.65) ms-3.1%
process.time_to_main_ms76.95 ± (76.79 - 77.12) ms74.04 ± (73.88 - 74.20) ms-3.8%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.68 ± (7.67 - 7.68) MB7.65 ± (7.65 - 7.66) MB-0.3%
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 8 - Bailout
process.internal_duration_ms20.25 ± (20.20 - 20.29) ms19.68 ± (19.64 - 19.73) ms-2.8%
process.time_to_main_ms78.49 ± (78.30 - 78.68) ms76.01 ± (75.82 - 76.20) ms-3.2%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.74 ± (7.73 - 7.75) MB7.73 ± (7.72 - 7.73) MB-0.2%
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms305.49 ± (303.32 - 307.65) ms305.55 ± (303.43 - 307.67) ms+0.0%✅⬆️
process.time_to_main_ms507.97 ± (507.00 - 508.94) ms490.47 ± (489.60 - 491.34) ms-3.4%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed37.13 ± (37.10 - 37.15) MB37.02 ± (36.99 - 37.05) MB-0.3%
runtime.dotnet.threads.count27 ± (27 - 27)27 ± (27 - 27)+0.6%✅⬆️

HttpMessageHandler

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration215.04 ± (214.99 - 215.91) ms204.89 ± (204.63 - 205.58) ms-4.7%
.NET Framework 4.8 - Bailout
duration220.32 ± (220.02 - 220.95) ms209.94 ± (209.42 - 210.34) ms-4.7%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1241.14 ± (1241.46 - 1248.21) ms1198.70 ± (1197.98 - 1205.35) ms-3.4%
.NET Core 3.1 - Baseline
process.internal_duration_ms209.32 ± (208.87 - 209.78) ms199.29 ± (198.80 - 199.78) ms-4.8%
process.time_to_main_ms91.84 ± (91.54 - 92.13) ms86.00 ± (85.72 - 86.28) ms-6.4%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed15.97 ± (15.95 - 15.99) MB16.02 ± (16.00 - 16.05) MB+0.3%✅⬆️
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)-0.8%
.NET Core 3.1 - Bailout
process.internal_duration_ms208.73 ± (208.24 - 209.22) ms199.42 ± (198.92 - 199.93) ms-4.5%
process.time_to_main_ms92.71 ± (92.46 - 92.96) ms87.43 ± (87.22 - 87.65) ms-5.7%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed15.94 ± (15.92 - 15.97) MB16.07 ± (16.05 - 16.09) MB+0.8%✅⬆️
runtime.dotnet.threads.count21 ± (21 - 21)21 ± (21 - 21)-0.3%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms422.42 ± (420.83 - 424.01) ms407.43 ± (406.12 - 408.74) ms-3.5%
process.time_to_main_ms554.94 ± (553.59 - 556.29) ms534.19 ± (533.12 - 535.27) ms-3.7%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed58.69 ± (58.64 - 58.73) MB58.66 ± (58.60 - 58.71) MB-0.1%
runtime.dotnet.threads.count30 ± (30 - 30)30 ± (30 - 30)-0.5%
.NET 6 - Baseline
process.internal_duration_ms214.64 ± (214.12 - 215.16) ms204.45 ± (204.02 - 204.87) ms-4.8%
process.time_to_main_ms79.83 ± (79.58 - 80.08) ms75.08 ± (74.83 - 75.34) ms-5.9%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.14 ± (16.12 - 16.16) MB16.31 ± (16.29 - 16.34) MB+1.1%✅⬆️
runtime.dotnet.threads.count20 ± (19 - 20)19 ± (19 - 19)-2.0%
.NET 6 - Bailout
process.internal_duration_ms215.78 ± (215.27 - 216.29) ms203.86 ± (203.41 - 204.30) ms-5.5%
process.time_to_main_ms81.54 ± (81.32 - 81.77) ms76.27 ± (76.07 - 76.48) ms-6.5%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.17 ± (16.15 - 16.20) MB16.34 ± (16.31 - 16.37) MB+1.0%✅⬆️
runtime.dotnet.threads.count20 ± (20 - 20)21 ± (20 - 21)+0.7%✅⬆️
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms601.08 ± (598.58 - 603.58) ms598.15 ± (595.64 - 600.66) ms-0.5%
process.time_to_main_ms559.94 ± (558.65 - 561.23) ms537.98 ± (537.02 - 538.94) ms-3.9%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed61.25 ± (61.14 - 61.37) MB61.68 ± (61.59 - 61.77) MB+0.7%✅⬆️
runtime.dotnet.threads.count31 ± (31 - 31)31 ± (31 - 31)-1.1%
.NET 8 - Baseline
process.internal_duration_ms212.79 ± (212.23 - 213.35) ms202.19 ± (201.76 - 202.62) ms-5.0%
process.time_to_main_ms78.94 ± (78.68 - 79.19) ms74.20 ± (73.96 - 74.44) ms-6.0%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.51 ± (11.49 - 11.53) MB11.70 ± (11.69 - 11.72) MB+1.7%✅⬆️
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (18 - 19)-2.0%
.NET 8 - Bailout
process.internal_duration_ms211.78 ± (211.28 - 212.27) ms202.08 ± (201.61 - 202.55) ms-4.6%
process.time_to_main_ms80.43 ± (80.16 - 80.70) ms75.32 ± (75.10 - 75.55) ms-6.3%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.57 ± (11.55 - 11.59) MB11.72 ± (11.70 - 11.74) MB+1.3%✅⬆️
runtime.dotnet.threads.count20 ± (20 - 20)19 ± (19 - 20)-2.7%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms587.48 ± (579.86 - 595.10) ms521.21 ± (516.80 - 525.61) ms-11.3%
process.time_to_main_ms518.94 ± (517.73 - 520.16) ms495.84 ± (494.90 - 496.77) ms-4.5%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed51.43 ± (51.34 - 51.53) MB50.74 ± (50.69 - 50.79) MB-1.3%
runtime.dotnet.threads.count30 ± (30 - 30)30 ± (30 - 30)-0.4%
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 (8312) - mean (74ms)  : 71, 77
    master - mean (76ms)  : 74, 78

    section Bailout
    This PR (8312) - mean (78ms)  : 76, 81
    master - mean (81ms)  : 79, 84

    section CallTarget+Inlining+NGEN
    This PR (8312) - mean (1,086ms)  : 1044, 1128
    master - mean (1,112ms)  : 1071, 1153

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 (8312) - mean (116ms)  : 113, 120
    master - mean (121ms)  : 116, 125

    section Bailout
    This PR (8312) - mean (119ms)  : 114, 123
    master - mean (121ms)  : 118, 124

    section CallTarget+Inlining+NGEN
    This PR (8312) - mean (797ms)  : 778, 816
    master - mean (815ms)  : 791, 839

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

    section Bailout
    This PR (8312) - mean (104ms)  : 101, 107
    master - mean (108ms)  : 104, 112

    section CallTarget+Inlining+NGEN
    This PR (8312) - mean (943ms)  : 901, 985
    master - mean (960ms)  : 914, 1007

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

    section Bailout
    This PR (8312) - mean (104ms)  : 101, 107
    master - mean (107ms)  : 104, 110

    section CallTarget+Inlining+NGEN
    This PR (8312) - mean (828ms)  : 790, 866
    master - mean (844ms)  : 809, 880

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 (8312) - mean (205ms)  : 200, 211
    master - mean (215ms)  : 210, 221

    section Bailout
    This PR (8312) - mean (210ms)  : 205, 214
    master - mean (220ms)  : 216, 225

    section CallTarget+Inlining+NGEN
    This PR (8312) - mean (1,202ms)  : 1146, 1257
    master - mean (1,245ms)  : 1196, 1294

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 (8312) - mean (295ms)  : 287, 302
    master - mean (311ms)  : 304, 317

    section Bailout
    This PR (8312) - mean (296ms)  : 290, 303
    master - mean (311ms)  : 305, 318

    section CallTarget+Inlining+NGEN
    This PR (8312) - mean (977ms)  : 943, 1011
    master - mean (1,019ms)  : 987, 1052

Loading
HttpMessageHandler (.NET 6)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8312) - mean (289ms)  : 281, 296
    master - mean (303ms)  : 296, 311

    section Bailout
    This PR (8312) - mean (289ms)  : 283, 294
    master - mean (306ms)  : 299, 313

    section CallTarget+Inlining+NGEN
    This PR (8312) - mean (1,168ms)  : 1122, 1214
    master - mean (1,194ms)  : 1158, 1231

Loading
HttpMessageHandler (.NET 8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8312) - mean (287ms)  : 282, 293
    master - mean (303ms)  : 295, 310

    section Bailout
    This PR (8312) - mean (288ms)  : 280, 295
    master - mean (302ms)  : 295, 310

    section CallTarget+Inlining+NGEN
    This PR (8312) - mean (1,053ms)  : 978, 1128
    master - mean (1,141ms)  : 1025, 1257

Loading

Extract the generation engine, configuration models, and resource templates
from the GUI into a standalone Core library. The GUI now delegates to Core,
reducing MainViewModel.Editor.cs from ~300 lines of inline logic to ~109 lines.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@bouwkast
bouwkast force-pushed the steven/auto-instrumentation-gen-core branch from 7af054a to 72b14d2 Compare March 31, 2026 15:22
@bouwkast
bouwkast marked this pull request as ready for review April 7, 2026 21:56
@bouwkast
bouwkast requested review from a team as code owners April 7, 2026 21:56

@andrewlock andrewlock 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 👍 I made the assumption that the vast majority of the code (e.g. in InstrrunmentationGenerator.cs) was extracted as-is, so didn't review closely. And perf isn't an issue given it's an adhoc tool so all good

@bouwkast
bouwkast merged commit 8840657 into master Apr 23, 2026
143 checks passed
@bouwkast
bouwkast deleted the steven/auto-instrumentation-gen-core branch April 23, 2026 19:22
@github-actions github-actions Bot added this to the vNext-v3 milestone Apr 23, 2026
vandonr added a commit that referenced this pull request Jul 9, 2026
)

## Summary of changes

Adds a new CLI tool (`dd-autoinstrumentation`) for auto-instrumentation
code generation, designed
for scriptable and AI-agent-driven workflows with structured JSON
output.

  ## Reason for change

Creating integrations currently requires either the GUI or manual
boilerplate. A CLI with structured
JSON output enables LLM agents to autonomously discover types/methods in
an assembly, generate
instrumentation code, and recover from errors — all without human
intervention.

  ## Implementation details

New `Datadog.AutoInstrumentation.Generator.Cli` project with two
commands:

  **`inspect`** — assembly discovery
- `--list-types`: lists all non-compiler-generated types with
visibility, kind, method count
- `--list-methods <type>`: lists instrumentable methods with parameters,
async detection, overload
  index/count

  **`generate`** — code generation
- Resolves method from assembly/type/method with overload disambiguation
(`--overload-index`,
  `--parameter-types`)
- Smart defaults auto-detect async/static/void methods (disable with
`--no-auto-detect`)
- Configuration via `--set key=value`, `--config '{json}'`, or
`--config-file path.json`
- Shortcut flags: `--no-method-begin`, `--no-method-end`,
`--async-method-end`

**`--json` flag** (global) — all output (success and error) as
structured JSON on stdout with:
- Machine-readable error codes (`FILE_NOT_FOUND`, `TYPE_NOT_FOUND`,
`AMBIGUOUS_OVERLOAD`,
  `BAD_ASSEMBLY`, etc.)
- `AMBIGUOUS_OVERLOAD` includes full overload list in response data for
immediate retry
- `inspect` output includes `overloadIndex`/`overloadCount` so agents
know upfront if disambiguation
   is needed

**Nuke integration** — `RunInstrumentationGeneratorCli` target with
direct parameters and
  `--generator-args` passthrough.

  **Documentation:**
- `docs/development/InstrumentationGenerator.md` — comprehensive
reference for both GUI and CLI
- `docs/development/for-ai/InstrumentationGenerator-CLI.md` —
LLM-focused reference with full JSON
  schemas, error recovery patterns, and recommended autonomous workflow

  ## Test coverage

No automated tests in this PR — this is a developer/AI tooling utility,
not a production code path.
Manual testing performed against real assemblies for all commands, error
paths, and JSON output.

  ## Other details

#8312

 🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Raphaël Vandon <[email protected]>
Co-authored-by: Andrew Lock <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos area:tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants