Loading

Profiler auto instrumentation (zero-code)

Profiler auto instrumentation lets you add APM to a .NET application (including ASP.NET Core and ASP.NET apps) without modifying source code or adding NuGet packages. Set a few environment variables, start your application, and the profiler automatically captures incoming request transactions, outgoing HTTP calls, database queries, and more for the technologies in the following section. This approach is useful for getting started quickly with zero code changes, for instrumenting applications you don't own, or for applying a single configuration change across all services on a host.

Note

Not sure whether you have .NET or .NET Framework? ".NET" (formerly ".NET Core") refers to .NET 8, .NET 9, and .NET 10. ".NET Framework" is the older Windows-only runtime (versions 4.6.1 to 4.8.1). If you're unsure which your application targets, open its .csproj file and check the <TargetFramework> element: values like net8.0 or net10.0 mean .NET; values like net472 or net48 mean .NET Framework.

Tip

Not sure whether profiler auto instrumentation is the right setup for your application? Refer to Choosing an approach for a comparison of zero-code and code-based options.

This approach supports the following platforms and runtimes:

Architecture Windows Linux**
x64 .NET Framework 4.6.2-4.8.1*
.NET 8+
.NET 8+

* Due to binding issues introduced by Microsoft, we recommend at least .NET Framework 4.7.2 for best compatibility. Additionally, the VerifyServerCert and ServerCert configuration options require .NET Framework 4.7.2 or higher to take effect; they have no effect on .NET Framework 4.6.2-4.7.1.

** Minimum GLIBC version 2.14.

Note

The profiler-based agent is only officially tested and supported on .NET 8 and newer we recommend .NET 10 for new projects. While it might work on older runtimes no longer supported by Microsoft, this is not guaranteed. ARM and 32-bit processes are not supported. IIS web garden (multi-worker process) mode is not supported.

It instruments the following technologies:

Technology Required library Notes
ASP.NET built-in (.NET Framework)
ASP.NET Core built-in (.NET) (.NET only) startup hook†
HTTP client built-in (.NET Framework)
built-in (.NET)
gRPC client Grpc.Net.Client
≥2.23.2 <3.0.0
(.NET only) startup hook†
Note

gRPC server calls in ASP.NET Core applications are captured automatically using ASP.NET Core instrumentation. No separate integration is needed for the server side.

Technology Required library Notes
ADO.NET built-in (.NET Framework)
Elasticsearch Elastic.Clients.Elasticsearch
≥8.0.0 <10.0.0
(.NET only) startup hook†
Elasticsearch.Net (legacy) Elasticsearch.Net
≥7.6.0 <8.0.0
(.NET only) startup hook†
NEST (legacy) NEST
≥7.6.0 <8.0.0
(.NET only) startup hook†
Entity Framework Core Microsoft.EntityFrameworkCore
≥8.0.0 ≤10.0.x
(.NET only) startup hook†
MongoDB MongoDB.Driver
≥3.7.0 <4.0.0
startup hook†
OTel bridge‡
MySQL MySql.Data
≥6.7.0 <9.0.0
Oracle Oracle.ManagedDataAccess
≥12.2.1100 <22.0.0
Oracle.ManagedDataAccess.Core
≥2.0.0 <4.0.0
PostgreSQL Npgsql
≥4.0.0 <8.0.0
SqlClient built-in (.NET Framework)
System.Data.SqlClient
≥4.0.0 <5.0.0
Microsoft.Data.SqlClient
≥1.0.0 <6.0.0
SQLite (Microsoft.Data.Sqlite) Microsoft.Data.Sqlite
≥2.0.0 <9.0.0
SQLite (System.Data.SQLite) System.Data.SQLite
≥1.0.0 <3.0.0
Technology Required library Notes
Azure Service Bus Azure.Messaging.ServiceBus
≥7.0.0 <8.0.0
(.NET only) startup hook†
Kafka Confluent.Kafka
≥1.4.0 <3.0.0
RabbitMQ RabbitMQ.Client
≥3.6.9 <7.0.0
Technology Required library Notes
Azure Blob Storage Azure.Storage.Blobs
≥12.8.0 <13.0.0
(.NET only) startup hook†
Azure Queue Storage Azure.Storage.Queues
≥12.6.0 <13.0.0
(.NET only) startup hook†
Azure File Share Storage Azure.Storage.Files.Shares
≥12.6.0 <13.0.0
(.NET only) startup hook†

† .NET only; not supported on .NET Framework. The profiler uses the .NET startup hook mechanism to automatically load both DiagnosticSource subscribers and the built-in OpenTelemetry Bridge.

‡ Captured using the built-in OpenTelemetry Bridge rather than a dedicated subscriber. MongoDB.Driver ≥3.7.0 emits native OpenTelemetry spans that the profiler captures through this bridge. If you have MongoDB.Driver 3.0-3.6, use the MongoDB NuGet integration instead.

Important

The .NET CLR Profiling API allows only one profiler to be attached to a .NET process. Because of this, only one solution that uses the .NET CLR profiling API should be used by an application.

Auto instrumentation using the .NET CLR Profiling API can be used in conjunction with

  • OpenTelemetry native instrumentation using the Activity API and the OpenTelemetry Bridge.
  • The Public API to perform manual instrumentation.
  • NuGet packages that perform instrumentation using an IDiagnosticsSubscriber to subscribe to diagnostic events.

NuGet packages must use the same version number as the profiler zip file.

Before starting, ensure you have:

  • APM server URL: the URL of the APM server you want to send data to (for example, https://my-apm-server:8200). This can be found in the Elastic deployment settings.
  • API key: used by the agent to authenticate with APM server. Refer to API key for details. If your environment uses secret tokens, set ELASTIC_APM_SECRET_TOKEN in place of ELASTIC_APM_API_KEY in the examples below.
  • Host access: you must be able to set environment variables for the process or service you want to instrument (for example, using a Dockerfile, service definition, or system settings).
  • Supported platform: verify that your runtime and architecture appear in the support table in the Overview section. If you are unsure which runtime your app targets, refer to the note about .NET vs .NET Framework in the same section.
  • Profiler zip version: if you plan to add any Elastic.Apm NuGet packages alongside the profiler, download a zip whose version exactly matches the NuGet package versions you intend to use.

The general steps in configuring profiler auto instrumentation are as follows. Refer to Instrumenting containers and services for configuration for common deployment environments.

  1. Download elastic_apm_profiler_<version>.zip from the GitHub Releases page (look under Assets, where <version> is the release version number).

  2. Unzip the zip file into a folder on the host that is hosting the application to instrument.

  3. Configure the following environment variables:

    .NET Framework

    PowerShell:

    $env:COR_ENABLE_PROFILING = "1"
    $env:COR_PROFILER = "{FA65FE15-F085-4681-9B20-95E04F6C03CC}"
    $env:COR_PROFILER_PATH = "<unzipped directory>\elastic_apm_profiler.dll"
    $env:ELASTIC_APM_PROFILER_HOME = "<unzipped directory>"
    $env:ELASTIC_APM_PROFILER_INTEGRATIONS = "<unzipped directory>\integrations.yml"
    $env:ELASTIC_APM_SERVER_URL = "<apm server url>"
    $env:ELASTIC_APM_API_KEY = "<api key>"
    $env:ELASTIC_APM_SERVICE_NAME = "<your-service-name>"
    		
    1. <unzipped directory> is the directory to which the zip file was unzipped in step 2.
    2. The URL of the APM server intake to which traces and metrics should be sent.
    3. The API key used by the APM Agent to authenticate with APM server.
    4. The name used to identify your service in APM. If not set, the agent uses the application assembly name.

    Command Prompt:

    set COR_ENABLE_PROFILING=1
    set COR_PROFILER={FA65FE15-F085-4681-9B20-95E04F6C03CC}
    set COR_PROFILER_PATH=<unzipped directory>\elastic_apm_profiler.dll
    set ELASTIC_APM_PROFILER_HOME=<unzipped directory>
    set ELASTIC_APM_PROFILER_INTEGRATIONS=<unzipped directory>\integrations.yml
    set ELASTIC_APM_SERVER_URL=<apm server url>
    set ELASTIC_APM_API_KEY=<api key>
    set ELASTIC_APM_SERVICE_NAME=<your-service-name>
    		

    .NET on Windows

    PowerShell:

    $env:CORECLR_ENABLE_PROFILING = "1"
    $env:CORECLR_PROFILER = "{FA65FE15-F085-4681-9B20-95E04F6C03CC}"
    $env:CORECLR_PROFILER_PATH = "<unzipped directory>\elastic_apm_profiler.dll"
    $env:ELASTIC_APM_PROFILER_HOME = "<unzipped directory>"
    $env:ELASTIC_APM_PROFILER_INTEGRATIONS = "<unzipped directory>\integrations.yml"
    $env:ELASTIC_APM_SERVER_URL = "<apm server url>"
    $env:ELASTIC_APM_API_KEY = "<api key>"
    $env:ELASTIC_APM_SERVICE_NAME = "<your-service-name>"
    		
    1. <unzipped directory> is the directory to which the zip file was unzipped in step 2.
    2. The URL of the APM server intake to which traces and metrics should be sent.
    3. The API key used by the APM Agent to authenticate with APM server.
    4. The name used to identify your service in APM. If not set, the agent uses the application assembly name.

    Command Prompt:

    set CORECLR_ENABLE_PROFILING=1
    set CORECLR_PROFILER={FA65FE15-F085-4681-9B20-95E04F6C03CC}
    set CORECLR_PROFILER_PATH=<unzipped directory>\elastic_apm_profiler.dll
    set ELASTIC_APM_PROFILER_HOME=<unzipped directory>
    set ELASTIC_APM_PROFILER_INTEGRATIONS=<unzipped directory>\integrations.yml
    set ELASTIC_APM_SERVER_URL=<apm server url>
    set ELASTIC_APM_API_KEY=<api key>
    set ELASTIC_APM_SERVICE_NAME=<your-service-name>
    		
    Note

    The only difference between the .NET Framework and .NET on Windows configurations above is the environment variable prefix: COR_ for .NET Framework, CORECLR_ for .NET.

    .NET on Linux

    export CORECLR_ENABLE_PROFILING=1
    export CORECLR_PROFILER={FA65FE15-F085-4681-9B20-95E04F6C03CC}
    export CORECLR_PROFILER_PATH="<unzipped directory>/libelastic_apm_profiler.so"
    export ELASTIC_APM_PROFILER_HOME="<unzipped directory>"
    export ELASTIC_APM_PROFILER_INTEGRATIONS="<unzipped directory>/integrations.yml"
    export ELASTIC_APM_SERVER_URL=<apm server url>
    export ELASTIC_APM_API_KEY=<api key>
    export ELASTIC_APM_SERVICE_NAME=<your-service-name>
    		
    1. <unzipped directory> is the directory to which the zip file was unzipped in step 2.
    2. The URL of the APM server intake to which traces and metrics should be sent.
    3. The API key used by the APM Agent to authenticate with APM server.
    4. The name used to identify your service in APM. If not set, the agent uses the application assembly name.
  4. Start your application. The environment variables must be visible to the application process. Either set them in the same terminal session before starting, or configure them in your service or container definition.

  5. Verify the agent is running.

    Send a test request to your application, then open APM → Services in Elastic Observability and look for your service name. Data typically appears within a few seconds of the first request.

    If no data appears after a minute, check the profiler log files for errors:

    • Windows: %PROGRAMDATA%\elastic\apm-agent-dotnet\logs
    • Linux: /var/log/elastic/apm-agent-dotnet

    Setting OTEL_LOG_LEVEL=debug produces more verbose output useful during troubleshooting. See Troubleshoot APM .NET Agent for further guidance.

Note

At runtime, the .NET runtime loads Elastic's CLR profiler into the process early in startup. For .NET Framework, the profiler uses IL rewriting to instrument methods directly. For .NET, it additionally uses the startup hook mechanism to load DiagnosticSource subscribers and the built-in OpenTelemetry Bridge, which together cover the broader set of technologies marked †.

Using global environment variables causes profiler auto instrumentation to be loaded for any .NET process started on the host. Often, the environment variables should be set only for specific services or containers. The following sections demonstrate how to configure common containers and services.

The following example shows how to download the profiler and configure it as part of a multi-stage build. This example targets Linux containers, which use libelastic_apm_profiler.so. For Windows containers, use elastic_apm_profiler.dll and set CORECLR_PROFILER_PATH to point to the .dll file instead.

ARG AGENT_VERSION=<VERSION>

FROM alpine:latest AS profiler-download
ARG AGENT_VERSION
WORKDIR /source

RUN apk update && apk add unzip curl

RUN curl -L -o elastic_apm_profiler_${AGENT_VERSION}.zip \
    https://github.com/elastic/apm-agent-dotnet/releases/download/v${AGENT_VERSION}/elastic_apm_profiler_${AGENT_VERSION}.zip && \
    unzip elastic_apm_profiler_${AGENT_VERSION}.zip -d /elastic_apm_profiler

FROM <your-base-image>

COPY --from=profiler-download /elastic_apm_profiler /elastic_apm_profiler

ENV CORECLR_ENABLE_PROFILING=1
ENV CORECLR_PROFILER={FA65FE15-F085-4681-9B20-95E04F6C03CC}
ENV CORECLR_PROFILER_PATH=/elastic_apm_profiler/libelastic_apm_profiler.so
ENV ELASTIC_APM_PROFILER_HOME=/elastic_apm_profiler
ENV ELASTIC_APM_PROFILER_INTEGRATIONS=/elastic_apm_profiler/integrations.yml
ENV ELASTIC_APM_SERVICE_NAME=<your-service-name>

ENTRYPOINT ["dotnet", "your-application.dll"]
		
  1. Replace <VERSION> with the version number of the profiler zip file to be downloaded (for example, 1.34.1).
  2. Replace <your-base-image> with your application's base image (for example, mcr.microsoft.com/dotnet/aspnet:8.0).
  3. The name used to identify your service in APM.
Important

Pass ELASTIC_APM_SERVER_URL and ELASTIC_APM_API_KEY at container runtime rather than baking them into the image. For example, pass them with docker run -e ELASTIC_APM_SERVER_URL=... -e ELASTIC_APM_API_KEY=... or using your orchestrator's secret injection.

Environment variables can be added to specific Windows services by adding an entry to the Windows registry. Using PowerShell:

Note

The only difference between the .NET Framework and .NET service configurations below is the environment variable prefix: COR_ for .NET Framework, CORECLR_ for .NET.

.NET Framework service

$environment = [string[]]@(
  "COR_ENABLE_PROFILING=1",
  "COR_PROFILER={FA65FE15-F085-4681-9B20-95E04F6C03CC}",
  "COR_PROFILER_PATH=<unzipped directory>\elastic_apm_profiler.dll",
  "ELASTIC_APM_PROFILER_HOME=<unzipped directory>",
  "ELASTIC_APM_PROFILER_INTEGRATIONS=<unzipped directory>\integrations.yml",
  "ELASTIC_APM_SERVER_URL=<apm server url>",
  "ELASTIC_APM_API_KEY=<api key>",
  "ELASTIC_APM_SERVICE_NAME=<your-service-name>")

Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\<service-name> -Name Environment -Value $environment
		
  1. <unzipped directory> is the directory to which the zip file was unzipped.
  2. The URL of the APM server intake to which traces and metrics should be sent.
  3. The API key used by the APM Agent to authenticate with APM server.
  4. The name used to identify your service in APM.
  5. <service-name> is the name of the Windows service.

.NET service

$environment = [string[]]@(
  "CORECLR_ENABLE_PROFILING=1",
  "CORECLR_PROFILER={FA65FE15-F085-4681-9B20-95E04F6C03CC}",
  "CORECLR_PROFILER_PATH=<unzipped directory>\elastic_apm_profiler.dll",
  "ELASTIC_APM_PROFILER_HOME=<unzipped directory>",
  "ELASTIC_APM_PROFILER_INTEGRATIONS=<unzipped directory>\integrations.yml",
  "ELASTIC_APM_SERVER_URL=<apm server url>",
  "ELASTIC_APM_API_KEY=<api key>",
  "ELASTIC_APM_SERVICE_NAME=<your-service-name>")

Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\<service-name> -Name Environment -Value $environment
		
  1. <unzipped directory> is the directory to which the zip file was unzipped.
  2. The URL of the APM server intake to which traces and metrics should be sent.
  3. The API key used by the APM Agent to authenticate with APM server.
  4. The name used to identify your service in APM.
  5. <service-name> is the name of the Windows service.

The service must then be restarted for the change to take effect. With PowerShell:

Restart-Service <service-name>
		

Set environment variables on a specific Application Pool using AppCmd.exe (IIS 10+, available on Windows Server 2016 / Windows 10 and later). This scopes the profiler to that pool only and does not affect other .NET applications on the host. Run the following in an elevated PowerShell prompt:

.NET Framework

$appcmd = "$($env:systemroot)\system32\inetsrv\AppCmd.exe"
$appPool = "<application-pool>"
$profilerHomeDir = "<unzipped directory>"
$environment = @{
  COR_ENABLE_PROFILING = "1"
  COR_PROFILER = "{FA65FE15-F085-4681-9B20-95E04F6C03CC}"
  COR_PROFILER_PATH = "$profilerHomeDir\elastic_apm_profiler.dll"
  ELASTIC_APM_PROFILER_HOME = "$profilerHomeDir"
  ELASTIC_APM_PROFILER_INTEGRATIONS = "$profilerHomeDir\integrations.yml"
  COMPlus_LoaderOptimization = "1"
  ELASTIC_APM_SERVER_URL = "<apm server url>"
  ELASTIC_APM_API_KEY = "<api key>"
  ELASTIC_APM_SERVICE_NAME = "<your-service-name>"
}

$environment.Keys | ForEach-Object {
  & $appcmd set config -section:system.applicationHost/applicationPools /+"[name='$appPool'].environmentVariables.[name='$_',value='$($environment[$_])']"
}
		
  1. <application-pool> is the name of the Application Pool your application uses, as shown in IIS Manager. For example, DefaultAppPool.
  2. <unzipped directory> is the full path to the directory in which the zip file was unzipped.
  3. Forces assemblies not to be loaded domain-neutral. This is a .NET Framework IIS-specific workaround: the profiler cannot instrument assemblies loaded domain-neutral. This limitation is expected to be removed in future, but for now can be worked around by setting the COMPlus_LoaderOptimization environment variable. See the Microsoft documentation for further details. This setting is not needed for .NET (non-Framework) applications.
  4. The URL of the APM server intake to which traces and metrics should be sent.
  5. The API key used by the APM Agent to authenticate with APM server.
  6. The name used to identify your service in APM.

.NET

$appcmd = "$($env:systemroot)\system32\inetsrv\AppCmd.exe"
$appPool = "<application-pool>"
$profilerHomeDir = "<unzipped directory>"
$environment = @{
  CORECLR_ENABLE_PROFILING = "1"
  CORECLR_PROFILER = "{FA65FE15-F085-4681-9B20-95E04F6C03CC}"
  CORECLR_PROFILER_PATH = "$profilerHomeDir\elastic_apm_profiler.dll"
  ELASTIC_APM_PROFILER_HOME = "$profilerHomeDir"
  ELASTIC_APM_PROFILER_INTEGRATIONS = "$profilerHomeDir\integrations.yml"
  ELASTIC_APM_SERVER_URL = "<apm server url>"
  ELASTIC_APM_API_KEY = "<api key>"
  ELASTIC_APM_SERVICE_NAME = "<your-service-name>"
}

$environment.Keys | ForEach-Object {
  & $appcmd set config -section:system.applicationHost/applicationPools /+"[name='$appPool'].environmentVariables.[name='$_',value='$($environment[$_])']"
}
		
  1. <application-pool> is the name of the Application Pool your application uses, as shown in IIS Manager. For example, DefaultAppPool.
  2. <unzipped directory> is the full path to the directory in which the zip file was unzipped.
  3. The URL of the APM server intake to which traces and metrics should be sent.
  4. The API key used by the APM Agent to authenticate with APM server.
  5. The name used to identify your service in APM.
Important

Ensure that the <unzipped directory> is accessible and executable by the Identity account under which the Application Pool runs.

Once the variables are set, stop and start IIS:

Stop-Service WAS -Force
Start-Service W3SVC
		
  1. Stops WAS (Windows Process Activation Service) and all dependent services
  2. Starts the W3SVC (World Wide Web Publishing Service)
Note

You can also set these variables through IIS Manager: select your Application Pool → Advanced SettingsEnvironment Variables. The variable names and values are identical to those in the scripts above.

Warning

Avoid setting these as machine-wide system environment variables. Doing so loads the profiler into every .NET process on the host. If AppCmd is unavailable and system-level variables are your only option, use ELASTIC_APM_PROFILER_EXCLUDE_PROCESSES or ELASTIC_APM_PROFILER_EXCLUDE_SERVICE_NAMES (refer to Profiler environment variables) to limit scope.

In Kubernetes, set environment variables in your Pod or Deployment spec using the env field on your container. First, add the profiler files to your container image (for example, using a multi-stage build as shown in the Docker containers section), then add the variables under spec.containers[].env:

containers:
  - name: your-app
    image: your-image
    env:
      - name: CORECLR_ENABLE_PROFILING
        value: "1"
      - name: CORECLR_PROFILER
        value: "{FA65FE15-F085-4681-9B20-95E04F6C03CC}"
      - name: CORECLR_PROFILER_PATH
        value: "/elastic_apm_profiler/libelastic_apm_profiler.so"
      - name: ELASTIC_APM_PROFILER_HOME
        value: "/elastic_apm_profiler"
      - name: ELASTIC_APM_PROFILER_INTEGRATIONS
        value: "/elastic_apm_profiler/integrations.yml"
      - name: ELASTIC_APM_SERVICE_NAME
        value: "<your-service-name>"
      - name: ELASTIC_APM_SERVER_URL
        valueFrom:
          secretKeyRef:
            name: elastic-apm-secret
            key: server-url
      - name: ELASTIC_APM_API_KEY
        valueFrom:
          secretKeyRef:
            name: elastic-apm-secret
            key: api-key
		

Store ELASTIC_APM_SERVER_URL and ELASTIC_APM_API_KEY in a Kubernetes Secret rather than hard-coding them in the spec. Create the secret with:

kubectl create secret generic elastic-apm-secret \
  --from-literal=server-url=https://your-apm-server:8200 \
  --from-literal=api-key=your-api-key
		

On Linux, environment variables can be added to specific services managed by systemd by creating an environment file (for example, elastic-apm.env) containing the following:

CORECLR_ENABLE_PROFILING=1
CORECLR_PROFILER={FA65FE15-F085-4681-9B20-95E04F6C03CC}
CORECLR_PROFILER_PATH=/<unzipped directory>/libelastic_apm_profiler.so
ELASTIC_APM_PROFILER_HOME=/<unzipped directory>
ELASTIC_APM_PROFILER_INTEGRATIONS=/<unzipped directory>/integrations.yml
ELASTIC_APM_SERVER_URL=<apm server url>
ELASTIC_APM_API_KEY=<api key>
ELASTIC_APM_SERVICE_NAME=<your-service-name>
		
  1. <unzipped directory> is the directory to which the zip file was unzipped.
  2. The URL of the APM server intake to which traces and metrics should be sent.
  3. The API key used by the APM Agent to authenticate with APM server.
  4. The name used to identify your service in APM.

Then add an EnvironmentFile entry to the service's configuration file that references the path to the environment file:

[Service]
EnvironmentFile=/path/to/elastic-apm.env
ExecStart=<command>
		
  1. The command that starts your service.

After adding the EnvironmentFile entry, restart the service.

systemctl reload-or-restart <service>
		

The profiler captures spans automatically for the supported libraries and frameworks listed in the preceding section. It cannot, however, instrument your own application code. For example: a background job, a business operation you want to trace, or a code path that doesn't go through a supported library will not be automatically traced. For that, use the Public API to create custom transactions and spans manually.

The profiler initializes the agent at startup. You can call the Public API from your application code and your custom spans will appear nested within the transactions the profiler creates automatically. No additional agent setup is needed.

To access the Public API, add the Elastic.Apm NuGet package to your project:

dotnet add package Elastic.Apm --version <same-version-as-profiler>
		

Then use the API to create custom spans within an active transaction:

using Elastic.Apm;

ElasticApm.Tracer.CurrentTransaction?.CaptureSpan("ProcessOrder", "business",
    span =>
    {
        // your application code here
    });
		
Note

If there is no active transaction (for example, in a background job or startup code not triggered by an HTTP request), CurrentTransaction is null and the span is silently dropped. Use ElasticApm.Tracer.CaptureTransaction(...) to create a root transaction for those code paths.

Important

The Elastic.Apm package version must exactly match the version of the profiler zip file. A mismatch will cause assembly binding errors at startup.

Some technologies are not covered by the profiler and require a dedicated Elastic APM NuGet package: Entity Framework 6, Redis (StackExchange.Redis), Azure CosmosDB, Azure Functions, and legacy Azure Service Bus (Microsoft.Azure.ServiceBus). For these technologies, install the corresponding package and follow its setup guide.

For technologies that the profiler already covers, dedicated NuGet packages also exist, for example Entity Framework Core, SqlClient, MongoDB, gRPC, Azure Service Bus, and Azure Storage. You can add these packages alongside the profiler. Both mechanisms use the same DiagnosticSource/Activity-based instrumentation and do not conflict with each other.

Refer to Supported technologies for the full table showing which technologies are covered by the profiler, by NuGet packages, or by both.

Important

When combining the profiler with any Elastic APM NuGet integration packages, every package version must exactly match the version of the profiler zip file. A version mismatch will cause errors at startup.

The profiler auto instrumentation has its own set of environment variables to manage the instrumentation. These are used in addition to agent configuration through environment variables.

ELASTIC_APM_PROFILER_HOME

The home directory of the profiler auto instrumentation. The home directory typically contains:

  • platform-specific profiler libraries
  • a directory for each compatible target framework, where each directory contains supporting libraries for auto instrumentation
  • an integrations.yml file that determines which methods to target for auto instrumentation
ELASTIC_APM_PROFILER_INTEGRATIONS (optional)
The path to the integrations.yml file that determines which methods to target for auto instrumentation. You don't normally need to set this. The profiler automatically looks for integrations.yml in the directory specified by ELASTIC_APM_PROFILER_HOME. Set it only if your integrations file is at a different location.
ELASTIC_APM_PROFILER_EXCLUDE_INTEGRATIONS (optional)

A semicolon-separated list of integrations to exclude from auto-instrumentation. Valid values are: AdoNet, AspNet, Kafka, MySqlCommand, NpgsqlCommand, OracleCommand, RabbitMQ, SqlCommand, SqliteCommand.

This variable only controls integrations that use IL rewriting (the integrations.yml-based mechanism). Technologies instrumented using the startup hook (such as ASP.NET Core, Entity Framework Core, Elasticsearch, gRPC, Azure SDKs, and MongoDB) cannot be selectively turned off using this variable.

ELASTIC_APM_PROFILER_EXCLUDE_PROCESSES (optional)
A semi-colon separated list of process names to exclude from auto-instrumentation. For example, dotnet.exe;powershell.exe. Can be used in scenarios where profiler environment variables have a global scope that would end up auto-instrumenting applications that should not be.

The following processes are always excluded from profiling by default.

  • powershell.exe
  • ServerManager.exe
  • ReportingServicesService.exe
  • RSHostingService.exe
  • RSManagement.exe
  • RSPortal.exe
  • RSConfigTool.exe
ELASTIC_APM_PROFILER_EXCLUDE_SERVICE_NAMES (optional)
A semi-colon separated list of APM service names to exclude from auto-instrumentation. Values defined are checked against the value of ELASTIC_APM_SERVICE_NAME environment variable.

The following service names are always excluded from profiling by default.

  • SQLServerReportingServices
Note

OTEL_LOG_LEVEL, OTEL_DOTNET_AUTO_LOG_DIRECTORY, and ELASTIC_OTEL_LOG_TARGETS use the OTEL_ / ELASTIC_OTEL_ prefix to align with EDOT .NET and OpenTelemetry SDK conventions, making migration between agents simpler.

OTEL_LOG_LEVEL (optional)

The log level at which the profiler should log. Valid values are

  • trace
  • debug
  • info
  • warn
  • error
  • none

The default value is warn. More verbose log levels like trace and debug can affect the runtime performance of profiler auto instrumentation, so are recommended only for diagnostics purposes.

Supersedes the deprecated ELASTIC_APM_PROFILER_LOG environment variable.

OTEL_DOTNET_AUTO_LOG_DIRECTORY (optional)

The directory in which to write profiler log files. If unset, defaults to

  • %PROGRAMDATA%\elastic\apm-agent-dotnet\logs on Windows
  • /var/log/elastic/apm-agent-dotnet on Linux

If the default directory cannot be written to, the profiler falls back to a logs subdirectory inside ELASTIC_APM_PROFILER_HOME.

Supersedes the deprecated ELASTIC_APM_PROFILER_LOG_DIR environment variable.

Important

The user account under which the profiler process runs must have permission to write to the destination log directory. Specifically, ensure that when running on IIS, the AppPool identity has write permissions in the target directory.

ELASTIC_OTEL_LOG_TARGETS (optional)

A semi-colon separated list of targets for profiler logs. Valid values are

  • file
  • stdout

The default value is file, which logs to the directory specified by OTEL_DOTNET_AUTO_LOG_DIRECTORY.

Supersedes the deprecated ELASTIC_APM_PROFILER_LOG_TARGETS.

Windows might automatically block downloaded DLL files if it considers them suspicious.

To unblock a DLL file on Windows, you can do the following:

  • Right-click the DLL file in File Explorer
  • Select Properties
  • In the General tab, look for the Security section at the bottom
  • Select the Unblock check box and click OK

Unblock DLL in Windows file properties

For further troubleshooting guidance, refer to Troubleshoot APM .NET Agent.