Skip to content

.NET

OpenTelemetry .NET automatic instrumentation loads into the runtime through a profiler and instruments ASP.NET Core, HttpClient, SQL clients, gRPC and other libraries without code changes.

Use this page when you run a .NET or .NET Framework service and want it in FuseScope.

Signal Status What is sent
Traces Stable Spans for requests, HTTP calls, database and messaging.
Metrics Stable Runtime, ASP.NET Core and HttpClient metrics.
Logs Stable (SDK) ILogger, log4net and NLog records with trace IDs. The log instrumentations in the agent are marked experimental.
  • Any .NET version Microsoft still supports, or .NET Framework 4.6.2 or later.
  • x64 or ARM64 (ARM64 is experimental). Linux (glibc and Alpine/musl), macOS or Windows.
  • Linux and macOS: curl; the default installer also uses the GitHub CLI (gh) to verify the download. macOS needs coreutils.
  1. Download and run the installer. It puts the files in $HOME/.otel-dotnet-auto:

    Terminal window
    version="v1.17.0"
    curl -sSfL -o otel-dotnet-auto-install.sh \
    "https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/download/$version/otel-dotnet-auto-install.sh"
    VERSION="$version" sh ./otel-dotnet-auto-install.sh

    The script verifies the release with gh. The upstream guide shows the full verification steps.

  2. Load the instrumentation into the current shell:

    Terminal window
    chmod +x $HOME/.otel-dotnet-auto/instrument.sh
    . $HOME/.otel-dotnet-auto/instrument.sh
  3. Configure and run your app from the same shell:

    Terminal window
    export OTEL_SERVICE_NAME=checkout
    export OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production,service.version=1.4.2
    export OTEL_EXPORTER_OTLP_ENDPOINT=http://fusescope-collector.example.com:4318
    export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
    ./Checkout

Traces, metrics and logs are all exported over OTLP by default.

See the configuration reference for every setting.

Terminal window
OTEL_EXPORTER_OTLP_ENDPOINT=http://fusescope-collector.example.com:4317
OTEL_EXPORTER_OTLP_PROTOCOL=grpc

Needs .NET 8+ and a reference to Grpc.Net.Client.

Install the instrumentation in the image and start the app through instrument.sh:

Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0
ARG OTEL_VERSION=v1.17.0
RUN apt-get update && apt-get install -y --no-install-recommends curl unzip ca-certificates \
&& rm -rf /var/lib/apt/lists/*
ENV OTEL_DOTNET_AUTO_HOME=/otel-dotnet-auto
RUN curl -sSfL -o /tmp/install.sh \
"https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/download/${OTEL_VERSION}/otel-dotnet-auto-install.sh" \
&& SKIP_RELEASE_VERIFICATION=true VERSION="${OTEL_VERSION}" sh /tmp/install.sh \
&& rm /tmp/install.sh
WORKDIR /app
COPY publish/ .
ENTRYPOINT ["/bin/sh", "-c", ". $OTEL_DOTNET_AUTO_HOME/instrument.sh && exec dotnet Checkout.dll"]

SKIP_RELEASE_VERIFICATION=true skips the gh check, since the image has no GitHub CLI. Verify the script yourself, or download it in a separate build stage that has gh.

Terminal window
docker run \
-e OTEL_SERVICE_NAME=checkout \
-e OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production \
-e OTEL_EXPORTER_OTLP_ENDPOINT=http://fusescope-collector.example.com:4318 \
-e OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
checkout:latest

Set the variables in the pod spec. The downward API adds the pod name and namespace:

deployment.yaml
env:
- name: OTEL_SERVICE_NAME
value: checkout
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://fusescope-otel-collector.fusescope.svc.cluster.local:4318
- name: OTEL_EXPORTER_OTLP_PROTOCOL
value: http/protobuf
- name: K8S_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: K8S_NAMESPACE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: OTEL_RESOURCE_ATTRIBUTES
value: deployment.environment.name=production,k8s.pod.name=$(K8S_POD_NAME),k8s.namespace.name=$(K8S_NAMESPACE_NAME)

$(VAR) only expands variables defined earlier in the list, so keep OTEL_RESOURCE_ATTRIBUTES last.

Logs written through ILogger (Microsoft.Extensions.Logging) are exported over OTLP with TraceId and SpanId attached. log4net and NLog are bridged the same way.

Library Versions Notes
Microsoft.Extensions.Logging 8.0 up to 12.0 Not on .NET Framework.
log4net 2.0.13 up to 4.0 Exports and injects trace context.
NLog 5.0 up to 7.0 Exports and injects trace context.

To include the formatted message rather than only the template, set OTEL_DOTNET_AUTO_LOGS_INCLUDE_FORMATTED_MESSAGE=true. To stop exporting logs, set OTEL_LOGS_EXPORTER=none, for example when a collector already reads them from stdout.

  1. Send a few requests to the service.
  2. Open Services. The service appears under its OTEL_SERVICE_NAME within a minute.
  3. Open the Traces explorer and filter by service.name.

Nothing arrives? Check that instrument.sh was sourced in the same shell (or Register-OpenTelemetry… ran), and that the endpoint and protocol match. The agent writes its own logs to /var/log/opentelemetry/dotnet on Linux and %ProgramData%\OpenTelemetry .NET AutoInstrumentation\logs on Windows.