How to Configure the Syslog Sink in spdlog: A Complete Guide
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. 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– Usesstd::mutexfor thread-safe access across multiple threadssyslog_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:
- Logger name – The spdlog identifier for retrieving the logger later
- Syslog ident – The string that appears as the program name in system logs (defaults to the logger name if empty)
- Option flags – Bitwise OR of syslog options like
LOG_PID(include PID) orLOG_CONS(write to console on failure) - Facility – The syslog facility code (e.g.,
LOG_USER,LOG_DAEMON,LOG_LOCAL0throughLOG_LOCAL7) - Enable formatting – Boolean flag determining whether spdlog applies its pattern formatter or sends raw payloads
#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:
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 file in the repository demonstrates practical syslog usage at line 304, showing integration with the broader sink ecosystem.
Summary
- spdlog provides
syslog_sink_mtandsyslog_sink_stininclude/spdlog/sinks/syslog_sink.hfor system logging - Factory helpers
syslog_logger_mtandsyslog_logger_ststreamline configuration of the syslog ident, facility, and formatting options - The
enable_formattingboolean controls whether raw payloads or formatted messages reach the system log - Priority mapping is customizable by overriding
syslog_prio_from_levelin 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 only on Unix-like systems, or create a custom sink that abstracts platform-specific logging mechanisms.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →