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"
}
The syslog receiver form on the Sources page: id network-syslog, port 6514, transport tcp, allow from 10.20.0.0/16 and 192.168.1.20.
Open complete screenshot ↗
The syslog receiver form on the Sources page: id network-syslog, port 6514, transport tcp, allow from 10.20.0.0/16 and 192.168.1.20.
Open complete screenshot ↗
The same source in the Sources page's add dialog, before you pick its identity.

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. allowFrom is 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.

Examples
65141514

transport 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 needs allowFrom.

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.

Examples
10.0.0.0/810.20.0.0/16192.168.1.20fd00::/8

Advanced

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.

Example
syslog-tls

maxRequestBytes integer default 10485760

The largest message it reads, between 1024 and 67108864. A larger one closes the connection; a larger datagram is dropped.

Examples
655361048576

encoding 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.bytes alone. A pipeline reads it as text with decode(__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.

Examples
(\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: allowFrom lists the networks a sender may connect from, as CIDR blocks such as 10.0.0.0/8 or 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 allowFrom empty, 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). Set lineBreaker to 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 maxRequestBytes closes 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.

FieldTypeHolds
__source.namestrThe name of the source that read the record.
__source.typestrThe kind of source that read it, its type, such as kafka, s3List, httpApi or hecReceiver.
__source.remotestrThe address of the sender that delivered the record to a receiver.
__source.bytesbytesThe 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.

Verify

  1. Point a sender at the receiver, as in Send from rsyslog.
  2. On the sender, run logger -t smeltr-test hello to log a line you can recognize. To send it straight to a UDP receiver, run logger --udp --server worker1.example.com --port 514 -t smeltr-test hello.
  3. Find it at the destination, its _raw starting 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 allowFrom lists. 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's syslog() 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_total grows
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 than maxRequestBytes, 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.

See also