Skip to content

Addressing Assembly Conflict Challenges in OpenTelemetry.AutoInstrumentation for .NET #4715

@alexeypukhov

Description

@alexeypukhov

Current State and Challenges

OpenTelemetry.AutoInstrumentation for .NET (Core) often requires setting the DOTNET_ADDITIONAL_DEPS and DOTNET_SHARED_STORE environment variables. This helps resolve assembly version conflicts between the instrumented application and the instrumentation tool, allowing both to load their required dependencies and ensuring that auto-instrumentation works correctly.
However, this is not a foolproof solution. The following issues remain:

Profiler-based Proposed Solution

Based on my initial experiments with the assembly reference redirection approach (already used in profiler-based instrumentation for .NET Framework), it seems promising that it can be effectively adapted for .NET (Core) by leveraging an already in-use custom AssemblyLoadContext which can be further enhanced (right now it is not used in its full potential).

StartupHook-only Proposed Solution

For StartupHook-only deployments (without a profiler), I experimented with a custom AssemblyLoadContext AND redirecting the instrumented application into this custom context (the secret sauce for this solution). I tried it in a sandbox project (not with the actual OpenTelemetry project yet) but loading the instrumented application into a custom context reduces the influence of the Trusted Platform Assemblies (TPA) list on the automatic resolution of assemblies by the .NET runtime. This makes it much easier to intervene and customize the assembly loading process, giving us more flexibility to resolve conflicts as needed in the use case where profiler is not loaded.


Both solutions could potentially work side by side, giving customers the option to choose their preferred approach (with assembly reference redirection as the default for profiler-based scenarios and the extended AssemblyLoadContext for StartupHook-only scenarios). Together, these approaches might address most dependency issues without requiring to set additional dependencies nor shared store environment variables. I would even go further and remove the store approach altogether; we may make it work with the store approach, but it will probably add unnecessary complexity. In addition, these two new approaches would build on what already works for .NET Framework and make a fuller use of already existing AssemblyLoadContext for assembly isolation in .NET (Core).

Potential Considerations

  • The StartupHook-only solution would result in the customer assembly being loaded twice (including once in the additional context) which will require additional handling to be eliminated.
  • Some applications may explicitly use AssemblyLoadContext.Default to load assemblies, which could require additional handling, especially for StartupHook-only deployments, where the application is loaded into a separate context.
  • If a customer subscribes to an assembly resolve event to load a newer version of an assembly than the one we've already loaded, this may not be supported, though this scenario should be relatively rare.

Overall, while these considerations exist, I believe these approaches should significantly reduce dependency conflicts and simplify deployment for most use cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions