Use Level-Specific Serilog Output Without Duplicate Events

Two overlapping Serilog sinks can write an error twice: once through the general sink and again through the error-only sink. When both outputs go to the same destination, use one ExpressionTemplate and conditionally include the extra error fields.

Last updated: October 21, 2026.

{
  "Serilog": {
    "Using": [
      "Serilog.Sinks.Console",
      "Serilog.Expressions"
    ],
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "formatter": {
            "type": "Serilog.Templates.ExpressionTemplate, Serilog.Expressions",
            "template": "[{@t:HH:mm:ss} {@l:u3}] {@m}{#if @l = 'Error' or @l = 'Fatal'}\nSource: {SourceContext}\nException: {@x}{#end}\n"
          }
        }
      }
    ]
  }
}

Install Serilog.Expressions, keep Serilog.Sinks.Console available, and load the Serilog section through ReadFrom.Configuration(). Test one information event and one error event at startup.

Put the condition inside the formatter

The official Serilog.Expressions documentation supports {#if}, {#else}, and {#end} blocks inside an ExpressionTemplate. The built-in @l value represents the event level, @m renders the message, and @x renders the exception.

This arrangement sends every accepted event through one sink. Information events use the compact line, while Error and Fatal events append source and exception details. Add properties such as a correlation ID only if they are actually enriched on the event; a missing optional property should not make the logger fail.

Use filters only when destinations differ

If errors must go to a separate file or service, nested loggers or WriteTo.Conditional() are appropriate. Make the branches mutually exclusive with ByIncludingOnly and ByExcluding, or accept that an error intentionally appears in both destinations. The Serilog configuration provider documents JSON sink and filter configuration.

Enable Serilog self-diagnostics during setup so invalid expression syntax is visible, then remove noisy console diagnostics from normal production output. Keep timestamps, levels, and correlation fields consistent across templates so log searches and alerts remain reliable. Avoid recording passwords, tokens, complete request bodies, or personal data merely because an event is severe.

Continue with designing SaaS audit logs, logging HTTP traffic safely, and tracing an error to its source.

Related Web Cheat Sheet guides

Sergey Kornilov

Sergey Kornilov