Atatus .NET APM Agent extends your application's logging capabilities with log correlation, allowing you to connect logs, traces, and transactions for easier debugging and deeper observability.
These features help you:
- Automatically include trace and transaction IDs in your application logs.
- Seamlessly connect logs and traces within the Atatus dashboard.
- Navigate from any log entry to its corresponding trace and vice versa.
Log Correlation
Log correlation lets you trace individual requests across systems by automatically adding correlation identifiers (trace and transaction IDs) to your logs.
The Atatus .NET Agent provides integrations for popular logging frameworks that take care of injecting these identifiers into your application's log records:
| Field | Description |
|---|---|
trace.id |
Uniquely identifies a request across distributed services |
transaction.id |
Marks the primary transaction being traced |
span.id |
Refers to the specific operation within a transaction |
These IDs connect your logs with traces, making it easy to jump from a log entry to its related transaction in the Atatus dashboard.
Supported Logging Frameworks
The Atatus .NET Agent ships with dedicated integrations for the following logging frameworks:
Microsoft.Extensions.Logging(ILogger) — captured by the agent whenCaptureLogsis enabled (no enricher or extra package needed)- Serilog — via the
Atatus.SerilogEnricherNuGet package - NLog — via the
Atatus.NLogNuGet package
If your logging framework is not listed above, you can still correlate logs with traces by manually injecting the IDs using the agent's public API.
Microsoft.Extensions.Logging (ILogger)
If your application uses Microsoft.Extensions.Logging.ILogger — the default logging abstraction in ASP.NET Core and modern .NET applications — enable log capture by setting CaptureLogs to true. It is disabled by default.
"Atatus": {
"AppName": "YOUR_APP_NAME",
"LicenseKey": "YOUR_LICENSE_KEY",
"CaptureLogs": true
}
You can also enable it with the environment variable ATATUS_CAPTURE_LOGS=true. See Customizing the agent for all configuration options.
Once enabled, the Atatus .NET Agent hooks into the ILogger pipeline and captures log events along with the active trace, transaction, and span IDs. As long as the agent is registered in your application (for example, via builder.Services.AddAllAtatus()), every ILogger call made within an active transaction is captured and visible in the Atatus dashboard.
public class OrdersController : ControllerBase
{
private readonly ILogger<OrdersController> _logger;
public OrdersController(ILogger<OrdersController> logger)
{
_logger = logger;
}
[HttpPost]
public IActionResult Create(Order order)
{
_logger.LogInformation("Creating order {OrderId}", order.Id);
// ...
return Ok();
}
}
Beyond enabling CaptureLogs, you don't need to add any enricher, layout renderer, or manual ID injection — the agent handles everything behind the scenes.
Serilog
Atatus offers a Serilog Enricher that automatically adds the trace and transaction IDs to every log line created during an active trace.
The enricher is published in the Atatus.SerilogEnricher NuGet package.
Enable it when configuring your Serilog logger. Make sure you add the required using directives so the WithAtatusCorrelationInfo() extension method is in scope:
using Serilog;
using Atatus.SerilogEnricher;
var logger = new LoggerConfiguration()
.Enrich.WithAtatusCorrelationInfo()
.WriteTo.Console(outputTemplate: "[{AtatusTraceId} {AtatusTransactionId}] {Message:lj} {NewLine}{Exception}")
.CreateLogger();
The .Enrich.WithAtatusCorrelationInfo() call activates the enricher, which sets the following properties on log events created during a transaction:
AtatusTraceIdAtatusTransactionId
You can reference these properties from any Serilog sink, not just the Console sink shown above.
NLog
For NLog, the Atatus .NET Agent provides LayoutRenderers that inject the current trace, transaction, and span IDs into log events.
The renderers are published in the Atatus.NLog NuGet package.
1. Register the extension in nlog.config
Add the package to the <extensions> section of your nlog.config and reference the layout renderers from any target layout:
<nlog>
<extensions>
<add assembly="Atatus.NLog"/>
</extensions>
<targets>
<target type="file" name="logfile" fileName="myfile.log">
<layout type="jsonlayout">
<attribute name="trace.id" layout="${AtatusTraceId}" />
<attribute name="transaction.id" layout="${AtatusTransactionId}" />
<attribute name="span.id" layout="${AtatusSpanId}" />
</layout>
</target>
</targets>
<rules>
<logger name="*" minLevel="Trace" writeTo="logfile" />
</rules>
</nlog>
The following layout renderers are available:
${AtatusTraceId}— current trace ID${AtatusTransactionId}— current transaction ID${AtatusSpanId}— current span ID
2. Load the configuration in Program.cs
Add the required using directives and load the nlog.config file at application startup:
using NLog;
using NLog.Web;
using Atatus.NLog;
var builder = WebApplication.CreateBuilder(args);
// Load NLog configuration from nlog.config
NLog.LogManager.Setup().LoadConfigurationFromFile("nlog.config");
builder.Host.UseNLog();
The
using Atatus.NLog;directive ensures the Atatus layout renderers are loaded into the NLog runtime alongside the assembly registration innlog.config.
Manual Log Correlation
If the agent's built-in logging integrations don't fit your application — for example, you use a different logging framework or want full control over how IDs are written — you can use the agent's public API to inject trace IDs manually.
There are two approaches depending on whether your logs are structured or unstructured.
Manual Correlation in Structured Logs
For structured logs, attach the following fields directly to your log events:
trace.idtransaction.id
Use the Agent.Tracer.CurrentTransaction property anywhere in your code to access the currently active transaction and read its IDs:
using Atatus;
public (string traceId, string transactionId) GetTraceIds()
{
if (!Agent.IsConfigured) return default;
if (Agent.Tracer.CurrentTransaction == null) return default;
return (Agent.Tracer.CurrentTransaction.TraceId, Agent.Tracer.CurrentTransaction.Id);
}
When the agent is configured and a transaction is active, the returned traceId and transactionId can be added to your structured log events under the trace.id and transaction.id fields.
Manual Correlation in Unstructured Logs
For unstructured (plain text) logs — such as Console.WriteLine or basic printf-style logging — embed the IDs directly into the log message string:
using Atatus;
var currentTransaction = Agent.Tracer.CurrentTransaction;
Console.WriteLine($"ERROR [trace.id={currentTransaction.TraceId} transaction.id={currentTransaction.Id}] an error occurred");
This produces output similar to:
ERROR [trace.id=cd04f33b9c0c35ae8abe77e799f126b7 transaction.id=cd04f33b9c0c35ae] an error occurred
+1-415-800-4104