Table of Contents

Enhanced SlackSink

Overview

Albatross.Logging provides enhanced support for the Serilog Slack sink, addressing common configuration challenges when deploying applications across multiple servers with shared environment variables.

The Problem

The standard Slack sink configuration stores the webhook URL in SlackSinkOptions:

{
  "Serilog": {
    "WriteTo": {
      "SlackSink": {
        "Name": "Slack",
        "Args": {
          "SlackSinkOptions": {
            "WebHookUrl": "https://hooks.slack.com/services/...",
            "BatchSizeLimit": 20,
            "ShowDefaultAttachments": false,
            "ShowPropertyAttachments": false,
            "ShowExceptionAttachments": false
          },
          "restrictedToMinimumLevel": "Error",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ssz} {MachineName} {SourceContext} [{Level:w3}] {Message:lj}"
        }
      }
    }
  }
}

Since the webhook URL is a secret, it's typically stored as an environment variable. The Serilog configuration system expects:

Serilog__WriteTo__SlackSink__Args__SlackSinkOptions__WebHookUrl=https://hooks.slack.com/services/...

The problem: This environment variable is global on the server. Any application using Serilog configuration (even without Slack sink) will try to partially initialize SlackSinkOptions and fail because other required options are missing.

Solutions

Solution 1: Single App Per Server

Only run one application per server. This is often not practical in production environments.

Solution 2: Remove Legacy Environment Variable

For applications that don't use the Slack sink, call RemoveLegacySlackSinkOptions() at startup to clear the problematic environment variable:

using Albatross.Logging;

// Call this before Serilog initialization
Extensions.RemoveLegacySlackSinkOptions();

// Now configure Serilog normally
var logger = new SetupSerilog()
    .UseConfigFile(environment, null, null, true)
    .UseConsole(LogEventLevel.Information)
    .Create();

This removes the Serilog__WriteTo__SlackSink__Args__SlackSinkOptions__WebHookUrl environment variable for the current process.

Use the SinkOptions.SlackSink static property which reads the webhook URL from a dedicated environment variable SlackSinkWebHookUrl:

Step 1: Set the environment variable on your server:

# Linux/macOS
export SlackSinkWebHookUrl="https://hooks.slack.com/services/..."

# Windows
setx SlackSinkWebHookUrl "https://hooks.slack.com/services/..."

Step 2: Configure serilog.json to use the SinkOptions provider:

{
  "Serilog": {
    "Using": [
      "Albatross.Logging"
    ],
    "WriteTo": {
      "SlackSink": {
        "Name": "Slack",
        "Args": {
          "SlackSinkOptions": "Albatross.Logging.SinkOptions::SlackSink, Albatross.Logging",
          "restrictedToMinimumLevel": "Error",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ssz} {MachineName} {SourceContext} [{Level:w3}] {Message:lj}{ErrorMessage}"
        }
      }
    },
    "Enrich": [
      "FromLogContext",
      "WithThreadId",
      "WithMachineName",
      "WithErrorMessage"
    ]
  }
}

The "Albatross.Logging.SinkOptions::SlackSink, Albatross.Logging" syntax tells Serilog to use the static SlackSink property from the SinkOptions class.

Solution 4: Mixed Approach

On servers with both legacy and new applications:

  1. Keep the legacy environment variable for older apps
  2. Use RemoveLegacySlackSinkOptions() in apps that don't need Slack
  3. Use SinkOptions.SlackSink in apps that need Slack with the new configuration

SinkOptions Configuration

The SinkOptions.SlackSink property provides these default settings:

Setting Value
WebHookUrl From SlackSinkWebHookUrl environment variable
BatchSizeLimit 20
ShowDefaultAttachments false
ShowPropertyAttachments false
ShowExceptionAttachments false

Complete Example

Here's a complete serilog.json configuration using the enhanced Slack sink with the ErrorMessage enricher:

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Using": [
      "Albatross.Logging"
    ],
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ssz} [{Level:w3}] {SourceContext} {Message:lj}{ErrorMessage}{NewLine}{Exception}"
        }
      },
      {
        "Name": "File",
        "Args": {
          "path": "logs/app.log",
          "rollingInterval": "Day",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ssz} [{Level:w3}] {SourceContext} {Message:lj}{ErrorMessage}{NewLine}{Exception}"
        }
      },
      {
        "Name": "Slack",
        "Args": {
          "SlackSinkOptions": "Albatross.Logging.SinkOptions::SlackSink, Albatross.Logging",
          "restrictedToMinimumLevel": "Error",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ssz} {MachineName} {SourceContext} [{Level:w3}] {Message:lj}{ErrorMessage}"
        }
      }
    ],
    "Enrich": [
      "FromLogContext",
      "WithThreadId",
      "WithMachineName",
      "WithErrorMessage"
    ]
  }
}

API Reference

Extensions.RemoveLegacySlackSinkOptions()

Removes the Serilog__WriteTo__SlackSink__Args__SlackSinkOptions__WebHookUrl environment variable for the current process.

public static void RemoveLegacySlackSinkOptions();

SinkOptions.SlackSink

Static property that returns a SlackSinkOptions instance configured with the webhook URL from the SlackSinkWebHookUrl environment variable.

public static SlackSinkOptions SlackSink { get; }

See Also