Configuring Syslog Sink on Linux with spdlog: Implementation Guide
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 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 (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 usingstd::mutexfor synchronized accesssyslog_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):
- Logger name – The identifier used within spdlog's registry
- Syslog ident – The program name displayed in syslog output (defaults to logger name if empty)
- Option flags – Bitwise OR of
LOG_PID(include process ID),LOG_CONS(write to console on syslog failure), orLOG_NDELAY(open connection immediately) - Facility – The syslog facility code such as
LOG_USER,LOG_DAEMON,LOG_LOCAL0throughLOG_LOCAL7 - 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:
#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:
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.
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.hto accesssyslog_logger_mtandsyslog_logger_stfactory functions - Choose thread-safety based on your concurrency needs:
_mtfor multi-threaded,_stfor single-threaded - Configure facility and options using standard syslog constants like
LOG_LOCAL0andLOG_PID - Control formatting with the
enable_formattingboolean to toggle between raw payloads and formatted messages - Override
syslog_prio_from_levelto 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 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.
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 →