Connecting .NET Logs and Traces

Connecting .NET Logs and Traces

You can set up your logging library and .NET tracing configurations so that trace and span IDs are injected into application logs, providing you with application performance monitoring data correlated with log data.

Configure the .NET Tracer with Unified Service Tagging for the best experience and helpful context when correlating application traces and logs.

The .NET Tracer supports the following logging libraries:

Getting started

To inject correlation identifiers into your log messages, follow the instructions for your logging library.

To automatically inject correlation identifiers into your log messages:

  1. Configure the .NET Tracer with the following tracer settings:

    • DD_ENV
    • DD_SERVICE
    • DD_VERSION
  2. Enable log enrichment, as shown in the following example code:

var log = new LoggerConfiguration()
    // Add Enrich.FromLogContext to emit Datadog properties
    .Enrich.FromLogContext()
    .WriteTo.File(new JsonFormatter(), "log.json")
    .CreateLogger();

For additional examples, see the Serilog automatic trace ID injection project on GitHub.

Note: Starting with .NET Tracer version 1.29.0, automatic injection for the log4net logging library requires the application to be instrumented with automatic instrumentation.

To automatically inject correlation identifiers into your log messages:

  1. Configure the .NET Tracer with the following tracer settings:

    • DD_ENV
    • DD_SERVICE
    • DD_VERSION
  2. Enable auto-instrumentation tracing of your app by following the instructions to install the .NET Tracer.

  3. Enable mapped diagnostic context (MDC), as shown in the following example code:

  <layout type="log4net.Layout.SerializedLayout, log4net.Ext.Json">
    <decorator type="log4net.Layout.Decorators.StandardTypesDecorator, log4net.Ext.Json" />
    <default />
    <!--explicit default members-->
    <remove value="ndc" />
    <!--remove the default preformatted message member-->
    <remove value="message" />
    <!--add raw message-->
    <member value="message:messageobject" />
    <!-- Add value='properties' to emit Datadog properties -->
    <member value='properties'/>
  </layout>

For additional examples, see the log4net automatic trace ID injection project on GitHub.

To automatically inject correlation identifiers into your log messages:

  1. Configure the .NET Tracer with the following tracer settings:

    • DD_ENV
    • DD_SERVICE
    • DD_VERSION
  2. Enable mapped diagnostic context (MDC), as shown in the following example code for NLog version 4.6+:

 <!-- Add includeMdlc="true" to emit MDC properties -->
  <layout xsi:type="JsonLayout" includeMdlc="true">
    <attribute name="date" layout="${longdate}" />
    <attribute name="level" layout="${level:upperCase=true}"/>
    <attribute name="message" layout="${message}" />
    <attribute name="exception" layout="${exception:format=ToString}" />
  </layout>

For NLog version 4.5:

 <!-- Add includeMdc="true" to emit MDC properties -->
  <layout xsi:type="JsonLayout" includeMdc="true">
    <attribute name="date" layout="${longdate}" />
    <attribute name="level" layout="${level:upperCase=true}"/>
    <attribute name="message" layout="${message}" />
    <attribute name="exception" layout="${exception:format=ToString}" />
  </layout>

For additional examples, see the automatic trace ID injection projects using NLog 4.0, NLog 4.5, or NLog 4.6 on GitHub.

To automatically inject correlation identifiers into your log messages:

  1. Configure the .NET Tracer with the following tracer settings:

    • DD_ENV
    • DD_SERVICE
    • DD_VERSION
  2. Enable auto-instrumentation tracing of your app by following the instructions to install the .NET Tracer.

  3. Enable log scopes for your logging provider, as shown in the example code. Only providers that support log scopes will have correlation identifiers injected.

Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging => 
    {
        logging.AddFile(opts =>
        {
            opts.IncludeScopes = true; // must include scopes so that correlation identifiers are added
            opts.FormatterName = "json";
        });
    }

If there is an active trace when the log is being written, trace and span IDs are automatically injected into the application logs with dd_trace_id and dd_span_id properties. If there is not an active trace, only dd_env, dd_service, and dd_version properties are injected.

Note: If you are using a logging library that replaces the default LoggerFactory implementation such as the Serilog.Extensions.Hosting or Serilog.Extensions.Logging packages, follow the framework-specific instructions (in this example, see Serilog).

For additional examples, see the Microsoft.Extensions.Logging automatic trace id injection project on GitHub.

Next, complete the setup for either automatic or manual injection.

Automatic injection

The final step to enable automatic correlation identifier injection is to:

  1. Enable DD_LOGS_INJECTION=true in the .NET Tracer’s environment variables. To configure the .NET Tracer with a different method, see Configuring the .NET Tracer.

After configuring the correlation identifier injection, see C# Log Collection to configure your log collection.

Manual injection

If you prefer to manually correlate your traces with your logs, you can add correlation identifiers to your logs.

Required key Description
dd.env Globally configures the env for the tracer. Defaults to "" if not set.
dd.service Globally configures the root service name. Defaults to the name of the application or IIS site name if not set.
dd.version Globally configures version for the service. Defaults to "" if not set.
dd.trace_id Active trace ID during the log statement. Defaults to 0 if no trace.
dd.span_id Active span ID during the log statement. Defaults to 0 if no trace.

Note: If you are not using a Datadog Log Integration to parse your logs, custom log parsing rules must parse dd.trace_id and dd.span_id as strings. For information, see the FAQ on this topic.

After completing the getting started steps, finish your manual log enrichment setup:

  1. Reference the Datadog.Trace NuGet package in your project.

  2. Use the CorrelationIdentifier API to retrieve correlation identifiers and add them to the log context while a span is active.

Lastly, see C# Log Collection to configure your log collection.

Examples:

Note: The Serilog library requires message property names to be valid C# identifiers. The required property names are: dd_env, dd_service, dd_version, dd_trace_id, and dd_span_id.

using Datadog.Trace;
using Serilog.Context;

// there must be spans started and active before this block.
using (LogContext.PushProperty("dd_env", CorrelationIdentifier.Env))
using (LogContext.PushProperty("dd_service", CorrelationIdentifier.Service))
using (LogContext.PushProperty("dd_version", CorrelationIdentifier.Version))
using (LogContext.PushProperty("dd_trace_id", CorrelationIdentifier.TraceId.ToString()))
using (LogContext.PushProperty("dd_span_id", CorrelationIdentifier.SpanId.ToString()))
{
    // Log something
}
using Datadog.Trace;
using log4net;

// there must be spans started and active before this block.
try
{
    LogicalThreadContext.Properties["dd.env"] = CorrelationIdentifier.Env;
    LogicalThreadContext.Properties["dd.service"] = CorrelationIdentifier.Service;
    LogicalThreadContext.Properties["dd.version"] = CorrelationIdentifier.Version;
    LogicalThreadContext.Properties["dd.trace_id"] = CorrelationIdentifier.TraceId.ToString();
    LogicalThreadContext.Properties["dd.span_id"] = CorrelationIdentifier.SpanId.ToString();

    // Log something

}
finally
{
    LogicalThreadContext.Properties.Remove("dd.env");
    LogicalThreadContext.Properties.Remove("dd.service");
    LogicalThreadContext.Properties.Remove("dd.version");
    LogicalThreadContext.Properties.Remove("dd.trace_id");
    LogicalThreadContext.Properties.Remove("dd.span_id");
}
using Datadog.Trace;
using NLog;

// there must be spans started and active before this block.
using (MappedDiagnosticsLogicalContext.SetScoped("dd.env", CorrelationIdentifier.Env))
using (MappedDiagnosticsLogicalContext.SetScoped("dd.service", CorrelationIdentifier.Service))
using (MappedDiagnosticsLogicalContext.SetScoped("dd.version", CorrelationIdentifier.Version))
using (MappedDiagnosticsLogicalContext.SetScoped("dd.trace_id", CorrelationIdentifier.TraceId.ToString()))
using (MappedDiagnosticsLogicalContext.SetScoped("dd.span_id", CorrelationIdentifier.SpanId.ToString()))
{
    // Log something
}
using Datadog.Trace;
using Microsoft.Extensions.Logging;

ILogger _logger;

// there must be spans started and active before this block.
using(_logger.BeginScope(new Dictionary<string, object>
{
    {"dd.env", CorrelationIdentifier.Env},
    {"dd.service", CorrelationIdentifier.Service},
    {"dd.version", CorrelationIdentifier.Version},
    {"dd.trace_id", CorrelationIdentifier.TraceId.ToString()},
    {"dd.span_id", CorrelationIdentifier.SpanId.ToString()},
}))
{
    // Log something
}

Configure log collection

Ensure that log collection is configured in the Datadog Agent and that the Logs Agent configuration for the specified files to tail is set to source: csharp so log pipelines can parse the log files. For more information, see C# Log Collection.

Note: Automatic log collection only works for logs formatted as JSON. Alternatively, use custom parsing rules.

Further Reading