Syslog receiver
Takes what syslog senders send over TCP, plain or under TLS, or over UDP: rsyslog, syslog-ng, network devices and appliances. Each message is a record, exactly as the sender wrote it.
Every worker in the group listens on its port, and a sender, or a balancer in front of the workers, picks one. Add workers to take more.
Example
Takes syslog on port 6514 over TLS with the identity syslog-tls, from senders in 10.20.0.0/16 and from the one host 192.168.1.20.
{
"id": "network-syslog",
"type": "syslogReceiver",
"port": 6514,
"allowFrom": [
"10.20.0.0/16",
"192.168.1.20"
],
"identity": "syslog-tls"
} 

Before you start
- Pick TCP or UDP. See TCP or UDP.
- Pick a port no other receiver of that transport in the group uses.
- Decide how senders are admitted: the networks they connect from, a client certificate, or both. See Who it admits.
- For TLS, add an identity with the receiver's certificate and key, and give each sender the authority that signed that certificate.
- Open the port on every worker, and give senders the address of each, or of a balancer in front of them. See Open its port.
TCP or UDP
transport is tcp unless the receiver gives udp. Take TCP
wherever the sender can send it. Take UDP for senders that send only UDP.
Over UDP each datagram is one message (RFC 5426). UDP costs this:
- No TLS. Messages cross the network in the clear, and the leader refuses a UDP
receiver that names an
identity. - No backpressure. Nothing slows a UDP sender. A datagram that arrives while
the receiver is full or blocked is dropped, and counted in
smeltr_source_dropped_total. - Spoofable senders.
allowFromis the only thing that admits a UDP sender, and a datagram's source address is whatever its sender writes. See Who it admits.
A TCP and a UDP receiver may share a port number, so one group can take syslog on TCP 514 and UDP 514.
Settings
It also takes the settings every source takes.
port integer required
The port it listens on. Every worker of the group binds it, so no two receivers of one transport share one; a TCP and a UDP receiver may.
65141514transport string default tcp
What senders send over.
tcp- Takes connections, under TLS when it names an
identity. A full receiver stops reading, which slows the sender. udp- Takes datagrams, one message each, for senders that send only UDP. No TLS, and nothing slows a sender: a datagram that arrives while the receiver is full or blocked is dropped and counted in
smeltr_source_dropped_total. It needsallowFrom.
allowFrom list of strings default every address TLS admits
The networks a sender may connect from: CIDR blocks such as 10.0.0.0/8, or single addresses. A connection from anywhere else is closed before any of it is read, and a datagram from anywhere else is dropped. Without it, a TCP receiver needs an identity with authorities, and admits every sender whose certificate chains to one of them. A UDP receiver needs it. A datagram's source address is whatever its sender writes, so over UDP it admits whoever can reach the port and claim an address in these networks.
10.0.0.0/810.20.0.0/16192.168.1.20fd00::/8Advanced
identity identity default plain TCP
The connection identity it serves TLS under (RFC 5425): its certificate and key. With authorities, a sender must present a certificate that chains to one of them. A UDP receiver takes none.
syslog-tlsmaxRequestBytes integer default 10485760
The largest message it reads, between 1024 and 67108864. A larger one closes the connection; a larger datagram is dropped.
655361048576encoding string default auto
How a message's bytes become _raw's text: auto, none, or a WHATWG encoding label other than the replacement ones, such as utf-8 or windows-1252. Syslog over TCP names no charset, and an older sender may write Latin-1.
auto- Detects each message's encoding.
utf-8- Decodes every message as UTF-8, as any other label decodes as its own encoding. Bytes that do not decode become U+FFFD.
none- Decodes nothing: the record has no
_raw, and its payload is__source.bytesalone. A pipeline reads it as text withdecode(__source.bytes, encoding).
lineBreaker string default a message per line
Where a message ends. The first capture group is required and will be dropped. E.g. (\x00) ends a message at a NUL, and ()CEF:0\| starts a new one at each CEF record. TCP only.
(\x00)()CEF:0\|Who it admits
Anyone a receiver admits can put records into the group's pipelines. Syslog carries no token, so
a receiver needs allowFrom, an identity with authorities, or both. The leader
refuses a receiver with neither.
- Networks:
allowFromlists the networks a sender may connect from, as CIDR blocks such as10.0.0.0/8or as single addresses. The receiver closes a connection from any other address before reading any of it. - Client certificates: with an identity, the receiver serves TLS (RFC 5425) with the
identity's certificate and key. If the identity has authorities, every sender must present a
certificate that chains to one of them. With
allowFromempty, every sender TLS admits is admitted.
With both, a sender must connect from a listed network and present a certificate.
Over UDP there is no TLS, so allowFrom is required and is all that admits a sender.
The receiver drops a datagram from any other address. It is weaker than over TCP: a TCP sender
must answer from its address to connect, but a datagram's source address is whatever its sender
writes, so anyone who can reach the port can claim an address in allowFrom. Take
UDP only where the network between senders and workers drops datagrams that forge their source,
and take TCP with an identity wherever a sender offers it.
allowFrom checks the address the connection or datagram comes from. A balancer or address
translation in front of the workers makes that the balancer's address, unless it keeps the sender's.
Without an identity, messages cross the network in the clear. Serve TLS wherever the network between senders and workers is not trusted.
Send from rsyslog
Use rsyslog's omfwd action with TCP_Framing="octet-counted", so a message holding a newline arrives as one record.
This example sends over TLS, checks the receiver's certificate against smeltr-ca.pem, and queues on disk while the receiver is out of reach:
global(
DefaultNetstreamDriver="gtls"
DefaultNetstreamDriverCAFile="/etc/rsyslog.d/smeltr-ca.pem"
)
action(
type="omfwd"
target="worker1.example.com"
port="6514"
protocol="tcp"
TCP_Framing="octet-counted"
StreamDriver="gtls"
StreamDriverMode="1"
StreamDriverAuthMode="x509/name"
StreamDriverPermittedPeers="workers.example.com"
template="RSYSLOG_SyslogProtocol23Format"
queue.type="LinkedList"
queue.filename="smeltr"
queue.saveOnShutdown="on"
action.resumeRetryCount="-1"
) For a client certificate, add DefaultNetstreamDriverCertFile and DefaultNetstreamDriverKeyFile to global. Without TLS, leave out the StreamDriver settings and send to the plain port:
action(
type="omfwd"
target="worker1.example.com"
port="1514"
protocol="tcp"
TCP_Framing="octet-counted"
template="RSYSLOG_SyslogProtocol23Format"
) To a UDP receiver, use protocol="udp":
action(
type="omfwd"
target="worker1.example.com"
port="514"
protocol="udp"
template="RSYSLOG_SyslogProtocol23Format"
) Send from syslog-ng
This example uses syslog-ng's syslog() driver over TLS and checks the receiver's certificate against smeltr-ca.pem:
destination d_smeltr {
syslog("worker1.example.com"
transport("tls")
port(6514)
tls(ca-file("/etc/syslog-ng/smeltr-ca.pem"))
);
};
log { source(s_src); destination(d_smeltr); }; For a client certificate, add cert-file() and key-file() to tls(). Without TLS, use transport("tcp") and the plain port.
To a UDP receiver, use transport("udp"):
destination d_smeltr {
network("worker1.example.com"
transport("udp")
port(514)
);
}; Messages it takes
- RFC 5424 messages, and RFC 3164 messages, the older BSD format.
- Messages are framed by their octet count, as
123 <34>1 ..., or end at a newline (RFC 6587). SetlineBreakerto end them at its pattern instead. - Plain TCP, or TLS (RFC 5425) when the receiver names an identity.
- Over UDP, one message to a datagram (RFC 5426). A newline, or carriage return and newline, that ends the datagram is dropped. An empty datagram gives no record.
- A message larger than
maxRequestBytescloses the connection. The sender connects again and goes on from where its own rules take it. A datagram larger than it is dropped.
An RFC 5424 message, as it arrives in _raw:
<165>1 2026-10-11T22:14:15.003Z fw01.example.com sshd 4123 AUTH [origin ip="10.20.0.7"] Accepted publickey for deploy An RFC 3164 message:
<34>Oct 11 22:14:15 fw01 su: 'su root' failed for deploy on /dev/pts/8 Fields it gives
Each message is a record. Its _raw is the message as the sender sent it, its <PRI> header included. __source.remote holds the address the sender's
connection or datagram came from.
| Field | Type | Holds |
|---|---|---|
__source.name | str | The name of the source that read the record. |
__source.type | str | The kind of source that read it, its type, such as kafka, s3List, httpApi or hecReceiver. |
__source.remote | str | The address of the sender that delivered the record to a receiver. |
__source.bytes | bytes | The record's payload as the source read it, before any decoding. The source decodes _raw from it. A bytes destination writes it unless the destination names another field. Text functions refuse it; decode(__source.bytes, encoding) reads it as text. |
Parse the header
The receiver does not parse the header, since every vendor writes syslog its own way. A Parser step with the Regex/Grok format reads it in the pipeline, where each source's quirks can have a pattern of their own. This step reads an RFC 5424 header with its first pattern and an RFC 3164 header with its second:
{
"id": "syslog-header",
"type": "parser",
"input": "_raw",
"kind": {
"type": "grok",
"patterns": [
"^<%{INT:pri}>%{INT:version} %{TIMESTAMP_ISO8601:time} %{NOTSPACE:host} %{NOTSPACE:app} %{NOTSPACE:procid} %{NOTSPACE:msgid} (?<sd>-|(?:\\[[^\\]]*\\])+)(?: %{GREEDYDATA:message})?$",
"^<%{INT:pri}>%{SYSLOGTIMESTAMP:time} %{SYSLOGHOST:host} %{DATA:app}(?:\\[%{POSINT:procid}\\])?: %{GREEDYDATA:message}$"
]
},
"declared": [
{
"name": "pri",
"type": "i64"
},
{
"name": "time",
"type": "str"
},
{
"name": "host",
"type": "str"
},
{
"name": "app",
"type": "str"
},
{
"name": "procid",
"type": "str"
},
{
"name": "msgid",
"type": "str"
},
{
"name": "sd",
"type": "str"
},
{
"name": "message",
"type": "str"
}
]
} Given these two messages as _raw:
<165>1 2026-10-11T22:14:15.003Z fw01.example.com sshd 4123 AUTH [origin ip="10.20.0.7"] Accepted publickey for deploy<34>Oct 11 22:14:15 fw01 su: 'su root' failed for deploy on /dev/pts/8 it gives these fields:
{
"pri": 165,
"version": "1",
"time": "2026-10-11T22:14:15.003Z",
"host": "fw01.example.com",
"app": "sshd",
"procid": "4123",
"msgid": "AUTH",
"sd": "[origin ip=\"10.20.0.7\"]",
"message": "Accepted publickey for deploy"
}{
"pri": 34,
"time": "Oct 11 22:14:15",
"host": "fw01",
"app": "su",
"message": "'su root' failed for deploy on /dev/pts/8"
} The facility is pri / 8 and the severity pri % 8: 165 is facility 20, local4, at severity 5, notice. To make time a datetime, declare it
with a format; see Parser step.
Delivery
Syslog has no acknowledgement. The receiver never tells a sender a message arrived, so a sender counts a message delivered once it has written it to the connection.
- Delivery is best-effort. What a connection carries when it is cut is lost, and so is what a worker holds and has not yet delivered when it stops.
- A receiver that is full, or blocked, stops reading from its
connections. The sender's TCP window fills, and the sender buffers or drops by its own rules.
Give rsyslog a disk-assisted queue, as in the example above, or
syslog-ng a
disk-buffer(), so that a pause holds messages rather than losing them. - Over UDP nothing slows the sender. A receiver that is full or blocked drops each datagram that
arrives, and counts it in
smeltr_source_dropped_total. On a Linux or other Unix host, datagrams wait in the host's receive buffer while a worker deploys a new configuration, until that buffer fills.
Open its port
Every worker in the group listens on the receiver's port. Open that port to senders
on each worker, for TCP or UDP as its transport says. A balancer in front of a UDP
receiver must balance UDP and keep each sender's source address, or allowFrom sees the
balancer's. A sender names one address: a balancer in front of the workers, or a DNS name that resolves
to each of them.
- On Kubernetes, add the port to the worker pods: Expose a receiver.
- On a host or in a container, open the host's firewall or publish the container's port: Enroll a worker on a host.
Verify
- Point a sender at the receiver, as in Send from rsyslog.
- On the sender, run
logger -t smeltr-test helloto log a line you can recognize. To send it straight to a UDP receiver, runlogger --udp --server worker1.example.com --port 514 -t smeltr-test hello. - Find it at the destination, its
_rawstarting with its PRI header.
Troubleshooting
- The sender cannot connect
- Check that the port is open on every worker and that the sender's address reaches them. An identity with authorities refuses a connection without a certificate that chains to one of them.
- The sender connects and is closed at once
- Its address is in none of the networks
allowFromlists. Behind a balancer or address translation, the address is the balancer's. - A message with several lines arrives as one record per line
- The sender ends messages with a newline. Set it to frame them by octet count:
TCP_Framing="octet-counted"in rsyslog, or syslog-ng'ssyslog()driver. - The connection closes on a long message
- The message is larger than
maxRequestBytes. Raise it, or have the sender cut its messages shorter. - Nothing arrives, and the sender's queue grows
- Check the source's status. A blocked receiver reads nothing until its destinations take records again. A full one takes more with more workers.
- Datagrams are missing, and
smeltr_source_dropped_totalgrows - The UDP receiver was full or blocked when they arrived. Check the source's status. A blocked receiver takes nothing until its destinations take records again; a full one takes more with more workers. A sender that can send TCP loses nothing to a full receiver over it.
- Datagrams are missing, and nothing is counted
- The receiver drops a datagram from an address outside
allowFrom, and one larger thanmaxRequestBytes, before counting anything. A datagram can also be lost on the network, or in the host's receive buffer when it fills. - Messages are missing after a worker stopped
- Syslog has no acknowledgement, so what was in flight when the connection was cut is lost. See Delivery.