Skip to content

Conversation

lucaspimentel
Copy link
Member

@lucaspimentel lucaspimentel commented Sep 25, 2025

DO NOT MERGE YET. This PR is stacked on #7594. Merge that PR first.

Summary of changes

Make DD_DOTNET_TRACER_HOME optional. If not set, try to figure out the path from COR_PROFILER_PATH and friends.

Reason for change

One less env var for users to set manually = easier onboarding, less steps, less error-prone.

Implementation details

The implementation makes DD_DOTNET_TRACER_HOME optional by adding fallback logic to derive the tracer home path from the profiler path environment variables:

  1. New method GetTracerHomePath (Startup.cs:150-178):

    • First checks for explicit DD_DOTNET_TRACER_HOME setting (preserves backward compatibility)
    • Falls back to computing the path from architecture-specific profiler path env vars (e.g., CORECLR_PROFILER_PATH_64, COR_PROFILER_PATH_64)
    • If not found, tries the generic profiler path env var (e.g., CORECLR_PROFILER_PATH, COR_PROFILER_PATH)
  2. New method ComputeTracerHomePathFromProfilerPath (Startup.cs:180-218):

    • Takes a profiler path like C:\tracer\win-x64\Datadog.Trace.ClrProfiler.Native.dll
    • Extracts the parent directory
    • If the parent directory name matches a known architecture folder (e.g., win-x64, linux-arm64, osx), goes up one more level
    • Returns the computed tracer home path
  3. Platform-specific helper methods:

    • GetProfilerPathEnvVarNameForArch(): Returns the architecture-specific env var name (CORECLR_PROFILER_PATH_64 on .NET Core x64, COR_PROFILER_PATH_32 on .NET Framework x86, etc.)
    • GetProfilerPathEnvVarNameFallback(): Returns the generic env var name (CORECLR_PROFILER_PATH or COR_PROFILER_PATH)
  4. Architecture directory detection:

    • Maintains a HashSet<string> of known architecture directories (win-x64, win-x86, linux-x64, linux-arm64, linux-musl-x64, linux-musl-arm64, osx, osx-arm64, osx-x64)
    • Uses case-insensitive comparison for robustness

Test coverage

Unit tests (tracer/test/Datadog.Trace.Tests/ClrProfiler/Managed/Loader/):

  • Environment variable reading and fallback logic (StartupNetCoreTests.cs, StartupNetFrameworkTests.cs)
  • GetTracerHomePath() with explicit DD_DOTNET_TRACER_HOME (with/without whitespace)
  • GetTracerHomePath() with architecture-specific profiler path fallback
  • GetTracerHomePath() with generic profiler path fallback
  • ComputeTracerHomePathFromProfilerPath() with all 10 architecture directories
  • Edge cases: empty values, whitespace, missing variables, null handling

Integration tests:

  • Added WhenOmittingTracerHome_InstrumentsApp() test in InstrumentationTests.cs that explicitly omits DD_DOTNET_TRACER_HOME and verifies instrumentation works via fallback logic
  • Modified all smoke tests (SmokeTests/SmokeTestBase.cs) to omit DD_DOTNET_TRACER_HOME by default, providing comprehensive real-world validation of the fallback behavior across multiple regression scenarios

Other details

⚠️ Based on #7567, which was originally generated by OpenAI Codex, but I made substantial changes to clean up and refactor.

@lucaspimentel lucaspimentel changed the title Lpimentel/remove tracer home dependency make DD_DOTNET_TRACER_HOME optional Sep 25, 2025
@lucaspimentel lucaspimentel marked this pull request as ready for review September 25, 2025 22:45
@lucaspimentel lucaspimentel requested review from a team as code owners September 25, 2025 22:45
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

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

dd-trace-dotnet-ci-bot bot commented Sep 25, 2025

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing the following branches/commits:

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 shown 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).

gantt
    title Execution time (ms) FakeDbCommand (.NET Framework 4.8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7568) - mean (72ms)  : 71, 73
     .   : milestone, 72,
    master - mean (72ms)  : 71, 73
     .   : milestone, 72,

    section Baseline
    This PR (7568) - mean (71ms)  : 60, 83
     .   : milestone, 71,
    master - mean (68ms)  : 66, 71
     .   : milestone, 68,

    section CallTarget+Inlining+NGEN
    This PR (7568) - mean (1,049ms)  : 995, 1103
     .   : milestone, 1049,
    master - mean (1,043ms)  : 1007, 1080
     .   : milestone, 1043,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7568) - mean (106ms)  : 105, 108
     .   : milestone, 106,
    master - mean (106ms)  : 105, 107
     .   : milestone, 106,

    section Baseline
    This PR (7568) - mean (105ms)  : 103, 108
     .   : milestone, 105,
    master - mean (105ms)  : 103, 108
     .   : milestone, 105,

    section CallTarget+Inlining+NGEN
    This PR (7568) - mean (740ms)  : 721, 759
     .   : milestone, 740,
    master - mean (741ms)  : 722, 760
     .   : milestone, 741,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7568) - mean (94ms)  : 93, 95
     .   : milestone, 94,
    master - mean (94ms)  : 93, 95
     .   : milestone, 94,

    section Baseline
    This PR (7568) - mean (93ms)  : 91, 95
     .   : milestone, 93,
    master - mean (93ms)  : 91, 95
     .   : milestone, 93,

    section CallTarget+Inlining+NGEN
    This PR (7568) - mean (698ms)  : 673, 724
     .   : milestone, 698,
    master - mean (703ms)  : 683, 723
     .   : milestone, 703,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET 8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7568) - mean (93ms)  : 92, 94
     .   : milestone, 93,
    master - mean (93ms)  : 92, 94
     .   : milestone, 93,

    section Baseline
    This PR (7568) - mean (92ms)  : 90, 95
     .   : milestone, 92,
    master - mean (92ms)  : 90, 94
     .   : milestone, 92,

    section CallTarget+Inlining+NGEN
    This PR (7568) - mean (654ms)  : 641, 667
     .   : milestone, 654,
    master - mean (664ms)  : 648, 680
     .   : milestone, 664,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Framework 4.8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7568) - mean (202ms)  : 196, 207
     .   : milestone, 202,
    master - mean (213ms)  : 209, 217
     .   : milestone, 213,

    section Baseline
    This PR (7568) - mean (199ms)  : 194, 203
     .   : milestone, 199,
    master - mean (207ms)  : 203, 212
     .   : milestone, 207,

    section CallTarget+Inlining+NGEN
    This PR (7568) - mean (1,180ms)  : 1118, 1241
     .   : milestone, 1180,
    master - mean (1,229ms)  : 1145, 1313
     .   : milestone, 1229,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7568) - mean (284ms)  : 275, 293
     .   : milestone, 284,
    master - mean (300ms)  : 294, 305
     .   : milestone, 300,

    section Baseline
    This PR (7568) - mean (284ms)  : 277, 291
     .   : milestone, 284,
    master - mean (299ms)  : 292, 306
     .   : milestone, 299,

    section CallTarget+Inlining+NGEN
    This PR (7568) - mean (952ms)  : 906, 998
     .   : milestone, 952,
    master - mean (988ms)  : 958, 1019
     .   : milestone, 988,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7568) - mean (276ms)  : 271, 281
     .   : milestone, 276,
    master - mean (291ms)  : 284, 298
     .   : milestone, 291,

    section Baseline
    This PR (7568) - mean (277ms)  : 272, 283
     .   : milestone, 277,
    master - mean (291ms)  : 283, 299
     .   : milestone, 291,

    section CallTarget+Inlining+NGEN
    This PR (7568) - mean (931ms)  : 881, 981
     .   : milestone, 931,
    master - mean (977ms)  : 940, 1015
     .   : milestone, 977,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7568) - mean (275ms)  : 270, 279
     .   : milestone, 275,
    master - mean (291ms)  : 286, 296
     .   : milestone, 291,

    section Baseline
    This PR (7568) - mean (276ms)  : 271, 281
     .   : milestone, 276,
    master - mean (291ms)  : 281, 301
     .   : milestone, 291,

    section CallTarget+Inlining+NGEN
    This PR (7568) - mean (861ms)  : 837, 886
     .   : milestone, 861,
    master - mean (923ms)  : 838, 1007
     .   : milestone, 923,

Loading

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! I just think we need

  1. Potential some perf tweaks
  2. Tests (unit and smoke/integration)

private static bool IsDatadogAssembly(string path, out Assembly? cachedAssembly)
{
for (var i = 0; i < _assemblies.Length; i++)
if (_assemblies is not null)
Copy link
Member

Choose a reason for hiding this comment

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

We can (and probably should) restructure Startup so that _assemblies is non-nullable, which avoids all these superfluous checks (we know it can't be null here in practice)

Copy link
Member Author

@lucaspimentel lucaspimentel Oct 2, 2025

Choose a reason for hiding this comment

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

At a quick glance I couldn't make it non-nullable without defaulting to = [], which allocates an array (only the first time, but this only runs once). Since we know they can't be null, I suppressed the warnings with ! instead.

}

// if the directory name is one of these, go one level higher
List<string> architectures = ["win-x64", "win-x86", "linux-x64", "linux-arm64", "linux-musl-x64", "linux-musl-arm64", "osx", "osx-arm64", "osx-x64"];
Copy link
Member

Choose a reason for hiding this comment

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

  1. this list should probably be a static readonly list at the top of the class instead of buried here
  2. osx? Is that a thing?! 😅
  3. It'll be easy to miss adding a new arch here, I wonder how we can avoid that? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

this list should probably be a static readonly list at the top of the class instead of buried here

Agreed. I'll fix it. (and I blame AI)

osx? Is that a thing?!

Yes, in Datadog.Trace.Bundle.

It'll be easy to miss adding a new arch here

Yeah, I had the same concern. A previous version would try all combinations of OS and arch, but that seems a bit wasteful since we know we don't support many of those (like win-arm64 or linux-x86).

On the other hand, we'll notice quickly if something is missing because the tracer won't work?

Copy link
Member Author

Choose a reason for hiding this comment

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

this list should probably be a static readonly list at the top of the class instead of buried here

fixed

@lucaspimentel lucaspimentel force-pushed the lpimentel/remove-tracer-home-dependency branch from 7a38278 to 8c6e15a Compare September 30, 2025 15:17
@lucaspimentel lucaspimentel marked this pull request as draft September 30, 2025 22:37
@lucaspimentel lucaspimentel force-pushed the lpimentel/remove-tracer-home-dependency branch from 01ee21f to 401e2b7 Compare October 2, 2025 02:39
@lucaspimentel lucaspimentel changed the base branch from master to lpimentel/managed-loader-cleanup October 2, 2025 02:41
@lucaspimentel lucaspimentel marked this pull request as ready for review October 2, 2025 03:05
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

@lucaspimentel lucaspimentel force-pushed the lpimentel/managed-loader-cleanup branch from caaa220 to 7d426a8 Compare October 2, 2025 14:01
@lucaspimentel lucaspimentel requested a review from a team October 2, 2025 14:05
@lucaspimentel lucaspimentel force-pushed the lpimentel/managed-loader-cleanup branch from 3a9626d to 2df2a24 Compare October 2, 2025 17:52
@lucaspimentel lucaspimentel force-pushed the lpimentel/remove-tracer-home-dependency branch from fc18f1d to 958c6b9 Compare October 2, 2025 17:53
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@lucaspimentel lucaspimentel force-pushed the lpimentel/remove-tracer-home-dependency branch from 958c6b9 to 786176e Compare October 2, 2025 18:04
@lucaspimentel lucaspimentel requested a review from a team as a code owner October 2, 2025 18:49
@bouwkast bouwkast added the status:do-not-merge Work is done. Can review, but do not merge yet. label Oct 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:do-not-merge Work is done. Can review, but do not merge yet.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants