# How to Configure the Syslog Sink in spdlog: A Complete Guide

> Master spdlog syslog sink configuration with this complete guide. Learn to set up thread safety, identifiers, and formatting options for efficient log forwarding. Improve your logging today.

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

---

**spdlog provides dedicated syslog sinks (`syslog_sink_mt` and `syslog_sink_st`) that forward log messages to the system logger via the standard `syslog(3)` API, configurable through factory helpers that control thread safety, identifiers, and formatting options.**

The `gabime/spdlog` library offers robust support for system logging through its specialized syslog sink implementation. Configuring the syslog sink in spdlog requires selecting the appropriate thread-safety variant, setting the syslog facility code, and determining whether to apply spdlog's pattern formatting or forward raw payloads.

## Understanding the spdlog Syslog Sink Architecture

The syslog functionality is implemented in [`include/spdlog/sinks/syslog_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/syslog_sink.h). This header defines the `syslog_sink` template class that inherits from `base_sink<Mutex>`, providing a standard interface for routing log entries to the Unix syslog service.

### Thread Safety Variants

The implementation provides two mutex-specific type aliases for different concurrency requirements:

- **`syslog_sink_mt`** – Uses `std::mutex` for thread-safe access across multiple threads
- **`syslog_sink_st`** – Uses a null-mutex for single-threaded contexts where synchronization overhead is unnecessary

Both variants manage the syslog connection lifecycle automatically, calling `::openlog` in the constructor and `::closelog` in the destructor.

## How to Configure the Syslog Sink in spdlog

The most common approach uses the factory helpers `syslog_logger_mt` and `syslog_logger_st`. These functions instantiate a logger pre-configured with a syslog sink and accept five parameters:

1. **Logger name** – The spdlog identifier for retrieving the logger later
2. **Syslog ident** – The string that appears as the program name in system logs (defaults to the logger name if empty)
3. **Option flags** – Bitwise OR of syslog options like `LOG_PID` (include PID) or `LOG_CONS` (write to console on failure)
4. **Facility** – The syslog facility code (e.g., `LOG_USER`, `LOG_DAEMON`, `LOG_LOCAL0` through `LOG_LOCAL7`)
5. **Enable formatting** – Boolean flag determining whether spdlog applies its pattern formatter or sends raw payloads

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

int main() {
    // Single-threaded logger with raw message output
    auto syslog = spdlog::syslog_logger_st(
        "my_app",                // logger name
        "my_app_ident",          // syslog ident (appears in /var/log/syslog)
        LOG_PID,                 // syslog option flags
        LOG_LOCAL0,              // facility
        false);                  // disable spdlog formatting

    spdlog::register_logger(syslog);
    syslog->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,
        LOG_USER,
        true);                   // enable formatting (timestamp, level, etc.)

    spdlog::register_logger(syslog_mt);
    syslog_mt->warn("A warning with formatted output");
}

```

## Message Formatting and Priority Mapping

The `enable_formatting` parameter controls how messages appear in system logs. When set to `true`, the sink applies the attached formatter (typically adding timestamps, log levels, and source locations) before transmission. When `false`, only the raw `msg.payload` is forwarded via the `sink_it_` method.

Priority mapping follows a fixed array `syslog_levels_` that translates spdlog severity levels to syslog priorities. The implementation calls `syslog_prio_from_level` to perform this translation before sending to `::syslog`.

### Customizing Priority Mapping

For applications requiring non-standard level mappings (e.g., mapping `spdlog::level::info` to `LOG_NOTICE`), subclass `syslog_sink` and override the protected `syslog_prio_from_level` method:

```cpp
template <typename Mutex>
class my_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;               // custom mapping
        return base::syslog_prio_from_level(msg);
    }
};

```

Instantiate your custom sink using `my_syslog_sink_mt` or `my_syslog_sink_st` type aliases, then create a logger manually via `spdlog::logger`.

## Lifetime Management and Best Practices

Because `syslog_sink` calls `::openlog` in its constructor and `::closelog` in its destructor, the logger instance must remain alive for the duration of syslog usage. Premature destruction closes the system log connection, potentially dropping subsequent messages. Register the logger with `spdlog::register_logger` to ensure global accessibility, or store it in a static scope for application lifetime.

The [`example/example.cpp`](https://github.com/gabime/spdlog/blob/main/example/example.cpp) file in the repository demonstrates practical syslog usage at line 304, showing integration with the broader sink ecosystem.

## Summary

- **spdlog** provides `syslog_sink_mt` and `syslog_sink_st` in [`include/spdlog/sinks/syslog_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/syslog_sink.h) for system logging
- Factory helpers `syslog_logger_mt` and `syslog_logger_st` streamline configuration of the syslog ident, facility, and formatting options
- The `enable_formatting` boolean controls whether raw payloads or formatted messages reach the system log
- Priority mapping is customizable by overriding `syslog_prio_from_level` in a derived class
- Syslog connections persist for the sink's lifetime, requiring careful scope management to avoid premature closure

## Frequently Asked Questions

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

**`syslog_sink_mt`** uses `std::mutex` to protect internal state during concurrent logging, making it safe for multi-threaded applications. **`syslog_sink_st`** uses a null-mutex and provides better performance in single-threaded contexts where synchronization is unnecessary. Both implement identical message formatting and syslog API interaction.

### How do I change the syslog facility after creating the sink?

The facility is set during construction via `::openlog` and cannot be changed dynamically. To use a different facility, you must create a new sink instance with the desired facility code (such as `LOG_DAEMON` or `LOG_LOCAL0`) and replace the existing logger or add the new sink to a `dist_sink` or `multi_sink` logger.

### Why are my log messages not showing up in /var/log/syslog?

Ensure the syslog identifier matches your system configuration and that the facility code is not filtered by syslog daemon rules. Additionally, verify that `enable_formatting` is set appropriately—if `false`, only the raw message payload is sent without spdlog's timestamp or level prefixes. Check system-specific log locations (e.g., `/var/log/messages` or `journalctl`) depending on your Linux distribution.

### Can I use the syslog sink on Windows?

The syslog sink relies on the Unix `syslog(3)` API and is not available on Windows systems. For cross-platform applications, use conditional compilation to include [`syslog_sink.h`](https://github.com/gabime/spdlog/blob/main/syslog_sink.h) only on Unix-like systems, or create a custom sink that abstracts platform-specific logging mechanisms.