Skip to content

Logging In Serilog and SEQ

Overview

Seq is a structured log server that ingests logs from .NET applications and provides powerful querying, visualization, and alerting capabilities. It is commonly used with the Serilog logging library, but supports other sources as well.

Do not confuse Serilog and Seq:

Serilog is a logging library for .NET applications. Its primary job is to collect log events from your code and format them as structured data, which is essentially machine-readable data (e.g., JSON) instead of plain text.

Seq is a log server that is a separate application designed to receive, store, search, and visualize structured log data.

SEQ Features

  • Rich Querying: Use SQL-like syntax to filter and analyze logs.
  • Dashboards & Alerts: Visualize log data and set up alerts for specific conditions.
  • Integration: Works seamlessly with .NET logging frameworks and supports OpenTelemetry.

Serilog Features

  • Structured Logging: This is Serilog's most significant feature. Instead of logging simple, unformatted text strings, Serilog captures log data as rich, structured events. This makes it possible for log analysis tools (like Seq or Elasticsearch) to query and filter logs based on specific properties (e.g., UserId, OrderId, or TransactionId).
  • Flexible Sinks: A "sink" is a destination for log events. Serilog supports a vast number of sinks, allowing you to send logs to a wide variety of destinations.
  • Message Templates: Serilog uses a clean, simple message template syntax that is a powerful alternative to standard string formatting. By using named properties (e.g., {UserName}), Serilog can extract and serialize the values into structured data, maintaining their original type.
  • Enrichers: Enrichers are components that automatically add contextual information to every log event. This allows you to include data like the machine name, user ID, correlation ID, or application version in your logs without having to manually add it to each log statement.
  • Asynchronous Logging: For high-performance and high-volume applications, Serilog can be configured to use asynchronous and buffered sinks.
  • Easy Configuration: Serilog is easy to configure, either programmatically in code or declaratively using a JSON configuration file (e.g., appsettings.json).

Basic Usage

Install the necessary NuGet packages:

dotnet add package Serilog
dotnet add package Serilog.Sinks.Seq

You can also add additional packages for various different sinks which direct output to specific destinations, for example:

  • Serilog.Sinks.File will log to a file.
  • Serilog.Sinks.Console will log to the console.

Note: For Web API projects the package Serilog.AspNetCore will cover most of what you need.


Configure Serilog to send logs to Seq:

using Serilog;

Log.Logger = new LoggerConfiguration()
    .WriteTo.Seq("http://localhost:5341")
    .CreateLogger();

Log.Information("Hello, Seq!");

Using Seq with OpenTelemetry

Seq can receive logs and traces from OpenTelemetry. To forward OpenTelemetry traces to Seq, use the OpenTelemetry.Exporter.Seq exporter.

Install the exporter:

dotnet add package OpenTelemetry.Exporter.Seq

Configure OpenTelemetry:

using OpenTelemetry.Trace;

var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddSource("MyCompany.MyProduct.MyLibrary")
    .AddSeqExporter(options =>
    {
        options.Endpoint = new Uri("http://localhost:5341");
    })
    .Build();

Challenges and Considerations

  • Licensing: Seq is free for individual use, but commercial deployments may require a license.
  • Performance: High log volumes may require tuning Seq's storage and retention settings.
  • Security: Ensure Seq endpoints are secured, especially if exposed outside your network.
  • Compatibility: Some advanced features may require specific versions of Serilog or OpenTelemetry.

Destructuring Operator

Serilog has a useful destructuring operator, @, that makes logging out objects much simpler. For example:

Log.LogInformation("Data {@data}.", data);

The @ symbol in that C# code line is a Serilog-specific instruction called a destructuring operator. It tells Serilog to serialize the data object into structured properties, rather than converting it to a simple string.

Here's how it works:

  • Without @: Log.LogInformation("Data: {data}.", data); would call the ToString() method on the data object and log the resulting string. This loses all the internal properties of the object. For example, if data is a User object, the log might simply show "Data: Acme.User".
  • With @: Log.LogInformation("Data: {@data}.", data); tells Serilog to inspect the data object's properties (e.g., UserId, UserName, Email) and log them as individual, queryable key-value pairs. This allows you to later search your logs for things like all log events where UserId is 123, which is impossible with simple string logging.

This feature is a core component of Serilog's structured logging, providing the foundation for powerful log analysis and troubleshooting.

Further Reading