Implementation:ClickHouse ClickHouse Poco RemoteSyslogChannel
base/poco/Net/src/RemoteSyslogChannel.cpp:1-348
ClickHouse_ClickHouse
ClickHouse_ClickHouse_Remote_Syslog_Logging
| Source File | base/poco/Net/src/RemoteSyslogChannel.cpp |
|---|---|
| Lines of Code | 348 |
| Principle | Principle:ClickHouse_ClickHouse_Remote_Syslog_Logging |
| Domain | Networking, Logging |
| Language | C++ |
| Last Updated | 2026-02-08 00:00 GMT |
Purpose
Implements a Poco logging channel that sends syslog messages over UDP to a remote syslog collector. Supports both RFC 5424 (modern) and RFC 3164 (BSD legacy) message formats. This enables ClickHouse to forward log events to centralized logging infrastructure such as rsyslog, syslog-ng, or cloud log aggregators.
Code Reference
Message Formatting and Sending
void RemoteSyslogChannel::log(const Message& msg)
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (!_open) open();
std::string m;
m.reserve(1024);
m += '<';
Poco::NumberFormatter::append(m, getPrio(msg) + _facility);
m += '>';
if (_bsdFormat)
{
// RFC 3164: <PRI>Mmm dd HH:MM:SS hostname message
Poco::DateTimeFormatter::append(m, msg.getTime(), BSD_TIMEFORMAT);
m += ' ';
m += _host;
}
else
{
// RFC 5424: <PRI>VERSION TIMESTAMP HOSTNAME APP-NAME PROCID MSGID SD MSG
m += "1 "; // version
Poco::DateTimeFormatter::append(m, msg.getTime(), SYSLOG_TIMEFORMAT);
m += ' ';
m += _host;
m += ' ';
m += _name;
m += ' ';
Poco::NumberFormatter::append(m, msg.getPid());
m += ' ';
m += msg.getSource();
m += ' ';
m += "-"; // no structured data
}
m += ' ';
m += msg.getText();
_socket.sendTo(m.data(), static_cast<int>(m.size()), _socketAddress);
}
Priority Mapping
int RemoteSyslogChannel::getPrio(const Message& msg)
{
switch (msg.getPriority())
{
case Message::PRIO_TEST:
case Message::PRIO_TRACE:
case Message::PRIO_DEBUG: return SYSLOG_DEBUG;
case Message::PRIO_INFORMATION: return SYSLOG_INFORMATIONAL;
case Message::PRIO_NOTICE: return SYSLOG_NOTICE;
case Message::PRIO_WARNING: return SYSLOG_WARNING;
case Message::PRIO_ERROR: return SYSLOG_ERROR;
case Message::PRIO_CRITICAL: return SYSLOG_CRITICAL;
case Message::PRIO_FATAL: return SYSLOG_ALERT;
default: return 0;
}
}
Channel Opening
void RemoteSyslogChannel::open()
{
if (_open) return;
if (_logHost.find(':') != std::string::npos)
_socketAddress = SocketAddress(_logHost);
else
_socketAddress = SocketAddress(_logHost, SYSLOG_PORT);
_socket = DatagramSocket(_socketAddress.family());
if (_host.empty())
{
try { _host = DNS::thisHost().name(); }
catch (Poco::Exception&)
{ _host = _socket.address().host().toString(); }
}
_open = true;
}
I/O Contract
| Input | Output | Side Effects |
|---|---|---|
| `log(msg)` -- a `Poco::Message` with priority, text, timestamp, source, PID | None (void) | Formats a syslog message (RFC 5424 or RFC 3164) and sends it as a single UDP datagram to `_socketAddress`. Auto-opens the channel on first call. |
| `open()` | None (void) | Resolves the log host address, creates a `DatagramSocket`, resolves the local hostname via DNS if not set. |
| `close()` | None (void) | Closes the underlying `DatagramSocket` and marks channel as closed. |
| `setProperty(name, value)` | None (void) | Configures channel properties: `name`, `facility`, `format` ("bsd"/"rfc3164" vs default RFC 5424), `loghost`, `host`. |
| `getProperty(name)` | Property value as `std::string` | None. Returns current property values; facility is returned as uppercase string (e.g., "USER", "DAEMON"). |
Usage Examples
// Create channel targeting a remote syslog server
RemoteSyslogChannel* pChannel = new RemoteSyslogChannel(
"logserver.example.com:514", // target address
"clickhouse-server", // application name
RemoteSyslogChannel::SYSLOG_DAEMON, // facility
false // use RFC 5424 format
);
pChannel->open();
// Send a log message
Poco::Message msg("QueryEngine", "Query completed in 150ms",
Poco::Message::PRIO_INFORMATION);
pChannel->log(msg);
// Or configure via properties
pChannel->setProperty("facility", "LOCAL0");
pChannel->setProperty("format", "bsd"); // switch to RFC 3164
pChannel->setProperty("loghost", "192.168.1.100:1514");
// Register with logging factory for config-based setup
RemoteSyslogChannel::registerChannel();
Internal Details
Message Format
RFC 5424 format:
<PRI>1 TIMESTAMP HOSTNAME APP-NAME PROCID MSGID - MESSAGE
Example: <14>1 2024-01-15T10:30:00.000000+00:00 server1 clickhouse 12345 QueryEngine - Query completed
RFC 3164 (BSD) format:
<PRI>Mmm dd HH:MM:SS hostname MESSAGE
Example: <14>Jan 15 10:30:00 server1 Query completed
Priority Calculation
The syslog priority value is facility + severity. Facility values are pre-shifted by 3 bits (e.g., `SYSLOG_USER = 8`, `SYSLOG_DAEMON = 24`), and severity occupies the lower 3 bits (0-7).
Facility Codes Supported
KERN, USER, MAIL, DAEMON, AUTH, AUTHPRIV, SYSLOG, LPR, NEWS, UUCP, CRON, FTP, NTP, LOGAUDIT, LOGALERT, CLOCK, LOCAL0 through LOCAL7.
Thread Safety
The `log` method acquires a `FastMutex`, ensuring that concurrent logging from multiple threads produces well-formed, non-interleaved UDP datagrams.