net_profiler_rust 0.7: OpenTelemetry Logs for .NET


net_profiler_rust 0.7 adds log ingestion to the existing OpenTelemetry trace and metric support. The profiler can now export logs from common .NET logging stacks without adding OpenTelemetry code or packages to the instrumented application.

The first versions of the profiler focused on traces and metrics. That already made it possible to see ASP.NET Core requests, outgoing HTTP calls, selected custom method spans, runtime metrics, and process metrics. Version 0.7 closes an important gap: logs can now travel through the same OTLP configuration and keep their trace and span context when they are written inside an active .NET Activity.

What is new in 0.7

The new log pipeline supports:

Logs are disabled by default. Existing profiler settings keep the same behavior until the Monitoring.Logs section is added and enabled.

Why log correlation matters

Traces are very good at showing the request path and timing. Logs are better for the detailed statements developers already write while handling a request, executing a job, or catching an exception.

The useful part is the connection between both signals. If an ASP.NET Core controller writes an ILogger<HomeController> message while a request span is active, version 0.7 exports the log record with the active trace ID and span ID. In Dynatrace, or in another backend that understands OpenTelemetry logs, the log can then be shown together with the trace.

Dynatrace trace details showing correlated OpenTelemetry logs exported by net_profiler_rust
Logs exported by the profiler and linked to the trace context.

Enabling logs

Add a Logs section below Monitoring in settings.yaml:

General:
  Enabled: true
  Provider: dynatrace
  Type: aspnetcore

Connection:
  EndpointUrl: https://<your-environment>.live.dynatrace.com/api/v2/otlp
  Type: http
  BearerToken: <your-api-token>

Monitoring:
  ServiceName: demo-api
  Enabled: true
  Special:
    - HttpClientInstrumentation

  Metrics:
    ServiceName: demo-api
    Enabled: true
    CollectionInterval: 10
    Cpu: true
    Memory: true

  Logs:
    Enabled: true
    MinimumLevel: Information
    IncludeFormattedMessage: true
    IncludeScopes: true
    ParseStateValues: true
    CaptureTraceContext: true
    Providers:
      MicrosoftExtensionsLogging:
        Enabled: true
      Serilog:
        Enabled: true
      Log4Net:
        Enabled: true

For Provider: dynatrace, the profiler derives the log ingest endpoint from the configured OTLP base URL and sends logs to:

https://<your-environment>.live.dynatrace.com/api/v2/otlp/v1/logs

The export protocol for Dynatrace logs is HTTP/protobuf. The bearer token from the settings file is sent as a Dynatrace API token header. The token needs the Dynatrace OpenTelemetry log ingest permission in addition to the trace and metric ingest permissions used by earlier profiler versions.

For Provider: otel, the configured endpoint is used directly, just like with traces and metrics. This is useful when sending telemetry to an OpenTelemetry Collector:

General:
  Enabled: true
  Provider: otel
  Type: aspnetcore

Connection:
  EndpointUrl: http://localhost:4318/v1/logs
  Type: http

Monitoring:
  ServiceName: demo-api
  Enabled: true
  Logs:
    Enabled: true
    MinimumLevel: Information
    IncludeFormattedMessage: true
    IncludeScopes: true
    ParseStateValues: true
    CaptureTraceContext: true
    Providers:
      MicrosoftExtensionsLogging:
        Enabled: true

Microsoft.Extensions.Logging

For hosted ASP.NET Core applications the profiler wires OpenTelemetry into the application logging builder. This covers the normal ILogger<T> path used by controllers, minimal APIs, hosted services, middleware, and framework components.

Example application code does not need to know about OpenTelemetry:

public sealed class HomeController : Controller
{
    private readonly ILogger<HomeController> logger;

    public HomeController(ILogger<HomeController> logger)
    {
        this.logger = logger;
    }

    public IActionResult Index()
    {
        logger.LogInformation(
            "Home page handled for cart {CartId}",
            HttpContext.TraceIdentifier);

        return View();
    }
}

When the request is traced, the exported log record carries the same trace and span identity.

Serilog and log4net

Version 0.7 also includes direct bridges for applications that use Serilog or log4net directly instead of routing everything through Microsoft.Extensions.Logging.

The bridges are activated only when the matching provider is enabled in settings and the logging framework is loaded by the application. They forward log events into the profiler’s OpenTelemetry logging pipeline. They do not create additional spans; they only attach the current trace context when one exists.

This keeps the behavior predictable:

Local validation

The feature is covered by settings tests, managed exporter tests, bridge tests, and local integration tests. The integration test runs the ASP.NET MVC sample under the profiler, enables logs, emits an ILogger<HomeController> message from a request action, and checks that a local OTLP HTTP capture server receives /v1/logs.

The Dynatrace contract test uses a local capture server as well. It verifies that Provider: dynatrace sends logs to /api/v2/otlp/v1/logs, uses HTTP/protobuf, and includes the Dynatrace API token header.

During testing, one small but important transport issue surfaced: the OpenTelemetry exporter can send HTTP requests with Transfer-Encoding: chunked. The local capture server now reads chunked OTLP request bodies correctly, so log assertions inspect the actual protobuf payload instead of an empty request body.

Upgrading

Download version 0.7 from the net_profiler_rust download page, update your profiler package, and add Monitoring.Logs to the settings file.

If you use Dynatrace, make sure the token can ingest OpenTelemetry logs. If you use an OpenTelemetry Collector, add a log pipeline to the collector configuration and point the profiler at the collector’s OTLP log endpoint.

The defaults are conservative: if Monitoring.Logs is omitted, no logs are exported.