Documentation
DocumentationDiscussions
These docs are for v2020.1. Click to read the latest docs for v2024.2.

Audit Logging

Seq can be used as a store for audit events

Requirements sometimes dictate that a transaction is rolled back if a log event describing it can't be recorded. This is sometimes referred to as audit logging.

Seq itself doesn't provide intrinsic support for audit logging - a successful write to the Seq HTTP API are always durable, so clients that post events using HTTP can check the response status code and determine without ambiguity that the event has been flushed to disk.

Using Seq for audit logging through a client library such as Serilog does require specific configuration, detailed in this guide.

📘

The techniques described on this page only apply if "guaranteed writes" are required; Seq can always be used as an audit trail regardless of the client library configuration, if failed writes are acceptable.

Serilog's AuditTo

When Seq is configured as a Serilog sink, this is normally through WriteTo.Seq(). The default Serilog logging infrastructure uses asynchronous batching and suppresses errors, so callers can't determine whether methods like Log.Information(...) resulted in successful writes to Seq.

For audit logging, Serilog provides an alternative configuration API AuditTo, and the Seq sink hooks in on top of this:

    .AuditTo.Seq("http://localhost:5341")

There are two differences in the sink's behavior in audit mode:

  • Failures writing events to Seq will result in exceptions that propagate back out from the logger, and
  • Events are sent individually, in synchronous web requests.

Sending events individually increases latency and reduces throughput; this is a typical trade-off to make for audit logging, but it's important to keep in mind when deciding whether auditing is necessary in an application.

🚧

When AuditTo.Seq() is used, every log event will result in a blocking network round-trip. This has an impact on application performance that should be measured and monitored carefully.

To reduce the performance impact of audit logging, a separate logging pipeline should be created for audit logging vs. regular diagnostic logging.

For example:

Log.Logger = new LoggerConfiguration()
    .WriteTo.Seq("https://seq.example.com")
    .CreateLogger();

var auditLogger = new LoggerConfiguration()
    .AuditTo.Seq("https://seq.example.com")
    .CreateLogger();

Log.Information("Not audited");
auditLogger.Information("This is audited");

The auditLogger can be stored in a static property or otherwise made accessible to application components that need auditing facilities.