Documentation forAppOptics

Trace Context in Logs

Adding trace context to application logs provides the ability to correlate the log messages from a single transaction, and if sampled, the log messages to the transaction trace detail.

The AppOptics .NET agent offers several options to include trace context into logs managed by several popular .NET logging frameworks, and provides a custom SDK call which can be used if the automatic options do not support your logger.

How to Add Trace Context to Logs

There are 3 options to include trace context into logs:

Automatic Insert

For supported frameworks (see below) the .NET agent can automatically insert the trace context to the end of the layout's output template. As a result, all log messages will have the Trace ID appended at the end.

This feature is disabled by default, to enable it see the configuration section.

Automatic Attribute

For supported frameworks (see below) the .NET agent can automatically add the %property{ao.traceId:long} attribute for Log4net, or the {aoTraceIdLong} attribute for Serilog, to the logging event objext. This attribute contains the Trace ID value that can then be included in the logging layout by using pattern such as %property{ao.traceId:long} for Log4net or {aoTraceIdLong} for Serilog.

This feature is disabled by default, to enable it see the configuration section.

Using the SDK

Trace context can be manually inserted into log messages if the automatic options do not support your logging framework. The string value of the Trace context can be obtained using the SDK GetCurrentLogTraceId method. Note that if the agent is not available or not started propertly, the value will be an empty string.

Supported Frameworks

Log4net

When using automatic insert, the PatternLayout is updated with %property{ao.traceId:long} at the end and when a message is logged the Trace ID will be at the end of the log message.

Copy
<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="%date [%thread] %level %logger - %message %property{ao.traceId:long} %newline" />
</layout>

Output:

Copy
2019-05-23 15:02:49,708 [6] INFO WebApp.Controllers.HelloController - hello world ao.traceId=C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1

When using automatic attribute, the PatternLayout layout must be manually updated %property{ao.traceId:long}

Copy
<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="%date [%thread] %level %logger %property{ao.traceId:long} - %message%newline" />
</layout>

Output:

Copy
2019-05-23 15:02:49,708 [6] INFO WebApp.Controllers.HelloController ao.traceId=C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1 - hello world

The %property{ao.traceId:<format>} allows the following formats:

  • %property{ao.traceId} - output contains only the log Trace ID

    Copy
    2019-05-23 15:02:49,708 [6] INFO WebApp.Controllers.HelloController C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1 - hello world
  • %property{ao.traceId:long} - default format used for auto inserting, the log Trace ID is prefixed with ao.traceId=

    Copy
    2019-05-23 15:02:49,708 [6] INFO WebApp.Controllers.HelloController ao.traceId=C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1 - hello world
  • %property{ao.traceId:json} - output is a JSON object

    Copy
    2019-05-23 15:02:49,708 [6] INFO WebApp.Controllers.HelloController {"ao":{"traceId":"C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1"}} - hello world

When using the XmlLayout layout and automatic attribute is enabled

Copy
<layout type="log4net.Layout.XmlLayout"></layout>

Output:

Copy
<log4net:event logger="WebApp.Controllers.HelloController" timestamp="2019-05-27T15:35:22.0626731-07:00" level="INFO" thread="6" domain="/LM/W3SVC/5/ROOT-1-132034701117372141" username="IIS APPPOOL\MVC5_TestLog4net">
  <log4net:message>hello world</log4net:message>
  <log4net:properties>
    <log4net:data name="log4net:HostName" value="TEST-MACHINE" />
    <log4net:data name="ao.traceId" value="C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1" />
  </log4net:properties>
</log4net:event>

When using an SimpleLayout layout and automatic insert is enabled

Copy
<layout type="log4net.Layout.SimpleLayout"></layout>

Output:

Copy
INFO - hello world ao.traceId=C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1

Serilog 2.8.0

This feature is only available when log events are enriched with built-in Serilog.Context.LogContext enricher. When creating logger object, a call to .Enrich.FromLogContext() method must be added.

When using automatic insert, the output template is updated at runtime to contain {aoTraceIdLong} attribute

Copy
// Output template
string outTemplate = "{Timestamp:HH:mm} [{Level}] {Message}{NewLine}{Exception}";

// Create serilog logger using provided output template

Log.Logger = new LoggerConfiguration()
  .Enrich.FromLogContext()
  .WriteTo.File(logFile, rollingInterval: RollingInterval.Infinite, outputTemplate: outTemplate)
  .CreateLogger();
  
Log.Information("hello world");

Output:

Copy
15:55 [Information] hello world ao.traceId=C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1

When using automatic attribute, the output template must be manually updated with {aoTraceIdLong} attribute

Copy
// Output template
string outTemplate = "{Timestamp:HH:mm} [{Level}] {aoTraceIdLong} {Message}{NewLine}{Exception}";

// Create serilog logger using provided output template

Log.Logger = new LoggerConfiguration()
  .Enrich.FromLogContext()
  .WriteTo.File(logFile, rollingInterval: RollingInterval.Infinite, outputTemplate: outTemplate)
  .CreateLogger();

Log.Information("hello world");

Output:

Copy
15:55 [Information] ao.traceId=C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1 hello world

The {aoTraceId<format>} allows the following formats:

  • {aoTraceId} - output contains only log trace context

    Copy
    15:55 [Information] C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1 hello world
  • {aoTraceIdLong} - default format used for auto inserting, the log Trace ID is prefixed with ao.traceId=

    Copy
    15:55 [Information] ao.traceId=C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1 hello world
  • {aoTraceIdJson} - output is a JSON object

    Copy
    15:55 [Information] {"ao":{"traceId":"C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1"}} hello world

When using automatic attribute in combination with CompactJsonFormatter formatter class, trace context is added as aoTraceId property of the JSON record

Copy
Log.Logger = new LoggerConfiguration()
  .Enrich.FromLogContext()
  .WriteTo.File(new CompactJsonFormatter(), logFile)
  .CreateLogger();
  
Log.Information("hello world");

Output:

Copy
{"@t":"2019-05-28T21:44:00.3293747Z","@mt":"hello world","aoTraceId":"C2E7EA546BC9C31BC18E1877C3191A0C6E952C08-1"}

When the APM Integrated Experience is enabled, AppOptics shares a common navigation and settings with the other integrated experiences' products. How you navigate AppOptics and access its features may vary from these instructions. For more information, go to the APM Integrated Experience documentation.

The scripts are not supported under any SolarWinds support program or service. The scripts are provided AS IS without warranty of any kind. SolarWinds further disclaims all warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The risk arising out of the use or performance of the scripts and documentation stays with you. In no event shall SolarWinds or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the scripts or documentation.