# Configuring Syslog Sink on Linux with spdlog: Implementation Guide

> Learn how to configure a syslog sink in spdlog on Linux. This guide details setting up your logger to send messages to the system log via the syslog API. Implement spdlog's syslog functionality easily.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: how-to-guide
- Published: 2026-07-25

---

**To configure a syslog sink in spdlog, instantiate `syslog_logger_mt` or `syslog_logger_st` with your desired identifier, syslog options, facility code, and formatting flag, which creates a logger that forwards messages to the Linux system logger via the `syslog(3)` API.**

Configuring syslog sink on Linux with spdlog integrates your C++ application with the system's centralized logging infrastructure. The implementation resides in the [`include/spdlog/sinks/syslog_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/syslog_sink.h) header within the gabime/spdlog repository, providing template-based sink classes that wrap the standard POSIX syslog interface.

## Understanding the Syslog Sink Architecture

The syslog sink implementation uses a template class `syslog_sink<Mutex>` defined in [`include/spdlog/sinks/syslog_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/syslog_sink.h) (lines 19-34) that inherits from `base_sink<Mutex>`. This design provides two distinct thread-safety variants through type aliases:

- **`syslog_sink_mt`** – Thread-safe variant using `std::mutex` for synchronized access
- **`syslog_sink_st`** – Single-threaded variant using a null-mutex for maximum performance in single-threaded contexts

The sink manages the syslog connection lifecycle internally. The constructor invokes `::openlog` to establish the connection with the specified identifier and facility, while the destructor automatically calls `::closelog` to release system resources. This RAII pattern ensures that syslog handles are properly cleaned up when the logger is destroyed.

## Core Configuration Parameters

When configuring the syslog sink, you must specify five key parameters through the factory helpers `syslog_logger_mt` and `syslog_logger_st` (lines 84-103):

1. **Logger name** – The identifier used within spdlog's registry
2. **Syslog ident** – The program name displayed in syslog output (defaults to logger name if empty)
3. **Option flags** – Bitwise OR of `LOG_PID` (include process ID), `LOG_CONS` (write to console on syslog failure), or `LOG_NDELAY` (open connection immediately)
4. **Facility** – The syslog facility code such as `LOG_USER`, `LOG_DAEMON`, `LOG_LOCAL0` through `LOG_LOCAL7`
5. **Enable formatting** – Boolean flag determining whether spdlog applies its pattern formatter (`true`) or forwards raw message payloads (`false`)

## Basic Configuration Examples

The following example demonstrates both single-threaded and multi-threaded syslog logger creation with different configuration profiles:

```cpp
#include <spdlog/spdlog.h>
#include <spdlog/sinks/syslog_sink.h>

int main() {
    // Single-threaded logger with raw message output
    auto syslog_st = spdlog::syslog_logger_st(
        "my_app",                // spdlog logger name
        "my_app_ident",          // syslog identifier (appears in /var/log/syslog)
        LOG_PID,                 // include PID in log entries
        LOG_LOCAL0,              // use local0 facility
        false);                  // disable formatting (send raw payload only)
    
    spdlog::register_logger(syslog_st);
    syslog_st->info("Application started");

    // Thread-safe logger with full spdlog formatting
    auto syslog_mt = spdlog::syslog_logger_mt(
        "my_app_mt",
        "my_app_mt",
        LOG_PID | LOG_CONS,      // include PID and console fallback
        LOG_USER,                // standard user-level facility
        true);                   // enable pattern formatting (timestamps, levels)
    
    spdlog::register_logger(syslog_mt);
    syslog_mt->warn("Warning with formatted metadata");
}

```

When `enable_formatting` is set to `true`, the sink applies the attached formatter in the `sink_it_` method (lines 41-51), producing structured output with timestamps and log levels. When `false`, the sink forwards `msg.payload` directly to `syslog(3)` without modification.

## Mapping spdlog Levels to Syslog Priorities

Internally, the sink maps spdlog severity levels to syslog priorities through a fixed `std::array<int,7>` named `syslog_levels_`. The protected virtual method `syslog_prio_from_level` (lines 65-70) performs this translation, converting levels like `spdlog::level::info` to `LOG_INFO` and `spdlog::level::err` to `LOG_ERR`.

## Advanced: Custom Priority Mapping

To override the default level-to-priority mapping, subclass `syslog_sink` and override the `syslog_prio_from_level` method. The following example maps `info` level messages to `LOG_NOTICE`:

```cpp
template <typename Mutex>
class custom_syslog_sink : public spdlog::sinks::syslog_sink<Mutex> {
public:
    using base = spdlog::sinks::syslog_sink<Mutex>;
    using base::base;  // inherit constructors

protected:
    int syslog_prio_from_level(const spdlog::details::log_msg &msg) const override {
        if (msg.level == spdlog::level::info)
            return LOG_NOTICE;  // elevate info to notice priority
        return base::syslog_prio_from_level(msg);
    }
};

using custom_syslog_sink_mt = custom_syslog_sink<std::mutex>;
using custom_syslog_sink_st = custom_syslog_sink<spdlog::details::null_mutex>;

```

After defining your custom sink type, instantiate it directly and add it to a logger, or create corresponding factory functions following the pattern in [`syslog_sink.h`](https://github.com/gabime/spdlog/blob/main/syslog_sink.h).

## Logger Lifetime Management

Because the syslog sink opens the system log connection in its constructor via `::openlog` and closes it in the destructor via `::closelog`, you must ensure the logger remains alive for the duration of your application's logging activity. Destroying the logger prematurely closes the syslog connection, potentially causing subsequent log attempts to fail or recreate the connection repeatedly.

Register the logger with `spdlog::register_logger` and store it in a scope that persists until application shutdown, or use the global spdlog registry to maintain ownership.

## Summary

- **Include [`syslog_sink.h`](https://github.com/gabime/spdlog/blob/main/syslog_sink.h)** to access `syslog_logger_mt` and `syslog_logger_st` factory functions
- **Choose thread-safety** based on your concurrency needs: `_mt` for multi-threaded, `_st` for single-threaded
- **Configure facility and options** using standard syslog constants like `LOG_LOCAL0` and `LOG_PID`
- **Control formatting** with the `enable_formatting` boolean to toggle between raw payloads and formatted messages
- **Override `syslog_prio_from_level`** to customize severity mapping for specific operational requirements
- **Manage object lifetime** to ensure syslog connections remain open during the application's logging phase

## Frequently Asked Questions

### What is the difference between syslog_sink_mt and syslog_sink_st?

`syslog_sink_mt` uses a `std::mutex` to synchronize access to the syslog connection, making it safe for concurrent logging from multiple threads. `syslog_sink_st` uses a null-mutex and provides better performance when logging occurs from a single thread or when external synchronization is already in place. Both are defined in [`include/spdlog/sinks/syslog_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/syslog_sink.h) as type aliases for the template class `syslog_sink<Mutex>`.

### How do I change the syslog facility in spdlog?

Pass the desired facility constant as the fourth parameter to `syslog_logger_mt` or `syslog_logger_st`. Standard options include `LOG_USER` for user-level messages, `LOG_DAEMON` for system daemons, or `LOG_LOCAL0` through `LOG_LOCAL7` for local use. The facility determines how the system log daemon routes and filters your application's messages.

### Can I customize which spdlog levels map to which syslog priorities?

Yes, derive a new class from `syslog_sink<Mutex>` and override the protected virtual method `syslog_prio_from_level`. This method receives the log message and returns an integer priority constant such as `LOG_INFO` or `LOG_ERR`. Return custom values for specific spdlog levels while delegating others to the base class implementation.

### Why are my syslog messages missing timestamps and log levels?

This occurs when the `enable_formatting` parameter is set to `false` in the factory function. Set this parameter to `true` to apply spdlog's pattern formatter, which prepends timestamps, log levels, and other metadata before forwarding to syslog. Alternatively, configure your system log daemon (rsyslog/syslog-ng) to add timestamps during processing.