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:

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. If the source is set to a value other than csharp, you may need to add a trace remapper to the appropriate log processing pipeline for the correlation to work correctly.

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

Configure injection in logs

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

See the samples in dd-trace-dotnet for more examples.
Note: Starting with .NET Tracer version 2.0.1, automatic injection for the Serilog 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.

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. Add dd.env, dd.service, dd.version, dd.trace_id, and dd.span_id log properties into your logging output. This can be done by including these properties individually or by including all log properties. Both approaches are 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" />

    <!-- Include Datadog properties -->
    <!-- EITHER Include individual properties with value='<property_name>' -->
    <member value='dd.env' />
    <member value='dd.service' />
    <member value='dd.version' />
    <member value='dd.trace_id' />
    <member value='dd.span_id' />
    <!-- OR Include all properties with value='properties' -->
    <member value='properties'/>
  </layout>

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

Note: Starting with .NET Tracer version 2.0.1, automatic injection for the NLog 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 for NLog version 5.0+:

  <!-- Add includeScopeProperties="true" to emit ScopeContext properties -->
  <layout xsi:type="JsonLayout" includeScopeProperties="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.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.

Note: To correlate traces with logs, you might need to set up a trace ID remapper to parse dd_trace_id as the log’s trace ID. See Correlated Logs Not Showing Up in the Trace ID Panel for more information.

Beta: Starting in version 2.35.0, if Agent Remote Configuration is enabled where this service runs, you can set DD_LOGS_INJECTION in the Service Catalog UI.

Manual injection

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

Required keyDescription
dd.envGlobally configures the env for the tracer. Defaults to "" if not set.
dd.serviceGlobally configures the root service name. Defaults to the name of the application or IIS site name if not set.
dd.versionGlobally configures version for the service. Defaults to "" if not set.
dd.trace_idActive trace ID during the log statement. Defaults to 0 if no trace.
dd.span_idActive 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 Correlated Logs Not Showing Up in the Trace ID Panel.

Note: If you are using Serilog, Nlog or log4net through ILogger, see the Microsoft.Extensions.Logging section to configure these properties using BeginScope().

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
}

You can read more about using BeginScope to create structured log messages for the following log providers:

Further Reading