Serilog
Begin logging to Seq by adding the Serilog.Sinks.Seq
package.
Seq has excellent support for all of Serilog's features including complex event data, enrichment and structured events. To collect traces as well as logs see SerilogTracing.
Structured Logging with Serilog and Seq
Datalust maintains a Serilog sink for Seq, which is released via NuGet. It supports all recent .NET versions.
ASP.NET Core
If your application uses ASP.NET Core, you'll also need the
Serilog.AspNetCore
package.
At the terminal, or in the Visual Studio Package Manager Console, type:
dotnet add package Serilog.Sinks.Seq
dotnet add package Serilog.Sinks.Console
Then, configure the logger and write some events. If you installed Seq to the default port you can use "http://your-seq-server:5341"
as the Seq address; if you configured Seq to listen on a different port or hostname, enter those details in the WriteTo.Seq()
line.
using System;
using Serilog;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.Seq("http://localhost:5341")
.CreateLogger();
Log.Information("Hello, {Name}!", Environment.UserName);
// Important to call at exit so that batched events are flushed.
Log.CloseAndFlush();
Console.ReadKey(true);
Run the application - you will see something like:
Now in the events view of your Seq server, press the Refresh button, which is shown with a green triangle 'play' button on the right side of the filter box. The events you've just logged will appear.
Clicking on the events will expand them to show their structured properties (Name
in this example) and some controls for filtering.
Try typing some text into the filter bar and pressing Enter
: Seq will display log events that contain the text in the message or associated exception.
Each property associated with an event, as well as its level and type, can be used for searching. Use the 'green tick' and 'red cross', Level, and Type menus to get started.
Beside the refresh button is the tail button. Choose this to see events in Seq as they arrive!
Troubleshooting
Nothing showed up, what can I do?
If the events don't display when Seq is refreshed, the console application was probably unable to contact the Seq server.
Add the following line after the logger is configured to print any error information to the console:
Serilog.Debugging.SelfLog.Enable(Console.Error);
It is also important to close the console window by pressing a key; Windows console apps are terminated "hard" if the close button in the title bar is used, so events buffered for sending to Seq may be lost if you use it.
Dynamic Level Control
Logging is indispensable when it’s needed, but too much logging can be a drain on performance and resources when everything is going smoothly and you don’t need really fine-grained log data.
Seq API Keys can be used to dynamically control the logging level of Serilog at runtime.
There are three things required for this to work:
- Serilog must be configured to use a level-controlled API key when connecting to Seq. In your own projects the API key should be stored securely rather than directly in the source code
- A LoggingLevelSwitch is shared between the root Serilog configuration and the Seq sink
- At least one event must reach the Seq sink on start-up, so, for example, if the initial level is the default
Information
, an informational or higher event must be logged (it doesn't matter whether Seq actually accepts it)
All three aspects are shown in the code sample.
var levelSwitch = new LoggingLevelSwitch();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(levelSwitch)
.WriteTo.Seq("http://localhost:5341",
apiKey: "yeEZyL3SMcxEKUijBjN",
controlLevelSwitch: levelSwitch)
.CreateLogger();
Log.Information("Starting up");
Now, whenever a batch of events is sent to Seq, the logging level associated with the corresponding API key will be returned by Seq (or at two minute intervals, when things are quiet). The Seq sink will apply this to controlLevelSwitch
, so the whole logging pipeline will be adjusted up or down.
Asynchronous Batching and Durable Log Shipping
The sink transmits log events to the server asynchronously to avoid heavy performance penalties. Buffered events will be flushed and any outstanding network requests will be completed when the hosting application terminates normally.
If the application is terminated via an attached debugger, the Task Manager or as a result of hard termination such as stack overflow, events in transit might be lost. To avoid this, and store events when network or server issues prevent delivery, a buffer file set may be specified.
Log.Logger = new LoggerConfiguration()
.WriteTo.Seq("http://localhost:5341",
bufferBaseFilename: @"C:\MyApp\Logs\myapp")
.CreateLogger();
Be aware that problems with the buffer file can affect logging in this configuration. Most applications should not use this option, but instead rely on the Seq sink's default in-memory buffering and retry support to handle short periods of server or network unavailability.
If multiple apps use the same folder on disk to buffer messages, it is crucial that they use unique file names. If this is not possible, consider using Fluent Bit or Seq Forwarder instead.
Use with IIS web sites
If you're using durable log shipping with IIS web sites, it is recommended that you set the Disable Overlapped Recycle setting to True on the application pool for the site. This will prevent the buffer file from remaining locked by the old worker process while the new worker process starts up.
Audit Logging with AuditTo
AuditTo
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 section.
The techniques described here 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.
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.
Best Practices and Further Reading
The articles and resources below can help you get the most of Serilog and Seq.
- The comprehensive Serilog Wiki on GitHub
- How (not) to parameterize Serilog events
- Don't Serialize Arbitrary Objects
- Contextual Logging in Serilog
Updated 11 months ago