Syslog and rsyslog
The syslog model classifies messages by facility (auth, cron, daemon…) cross severity (emerg…debug). rsyslog rules route by facility.severity to files or remote collectors. journald can forward to syslog via imjournal, bridging the structured and classic worlds.
You inherit a server where all auth events go to /var/log/auth.log, cron output goes to /var/log/syslog, and kernel messages are in /var/log/kern.log — but nobody set this up recently and there is no journald config that explains it. This is rsyslog at work, implementing a routing scheme that predates systemd by 30 years: the syslog model. Every log message carries two tags — a facility (what subsystem sent it) and a severity (how bad it is) — and rsyslog rules route the cross-product of those two dimensions to files, pipes, or remote servers. Understanding this model is essential because rsyslog still runs on most Linux boxes alongside journald, it is the standard way to ship logs to a central collector, and every observability pipeline you encounter in production grew from this same facility/severity taxonomy.
After this lesson you can read the syslog facility/severity matrix, interpret rsyslog routing rules in rsyslog.conf, configure rsyslog to forward logs to a remote collector, and understand how journald bridges to the classic syslog world via imjournal.
The syslog model: facility × severity.
Every syslog message has two classification dimensions:
# FACILITIES — what subsystem generated the message:
# kern kernel messages
# user user-level messages
# mail mail subsystem
# daemon system daemons
# auth security/authorization (also: authpriv for sensitive auth)
# syslog messages generated by syslogd itself
# lpr line printer subsystem
# news network news subsystem
# cron clock daemon (cron and at)
# local0-7 reserved for local use
# SEVERITIES (0=most critical, 7=least):
# 0 emerg system is unusable
# 1 alert action must be taken immediately
# 2 crit critical conditions
# 3 err error conditions
# 4 warning warning conditions
# 5 notice normal but significant condition
# 6 info informational messages
# 7 debug debug-level messages
# In rsyslog rules, the selector is facility.severity:
# auth.err → auth messages at err level and above
# *.warning → all facilities at warning and above
# kern.=debug → kernel debug messages ONLY (= means exact match)
# auth,authpriv.* → auth and authpriv at any severityThe facility/severity pair is encoded as an integer in the syslog protocol. The kernel uses kern.emerg for panics; SSH uses auth.info for logins; cron uses cron.notice for job completions.
Reading rsyslog.conf routing rules.
/etc/rsyslog.conf and files in /etc/rsyslog.d/ contain rules that match selectors and route them to actions:
# View the main config:
cat /etc/rsyslog.conf
# Typical Ubuntu/Debian routing block:
# auth,authpriv.* /var/log/auth.log
# *.*;auth,authpriv.none -/var/log/syslog
# kern.* -/var/log/kern.log
# mail.* -/var/log/mail.log
# cron.* /var/log/cron.log
# Syntax: <selector> <action>
# Selector: facility.severity (comma-separate multiple facilities)
# Action: /path/to/file (leading - means async write, slightly faster)
# @host:port (UDP forwarding)
# @@host:port (TCP forwarding)
# |/path/pipe (named pipe)
# The .none modifier excludes a facility:
# *.*;auth,authpriv.none → all facilities at all severities
# EXCEPT auth and authpriv
# Check rsyslog is running:
systemctl status rsyslogrsyslog processes rules top-to-bottom. A message can match multiple rules and be written to multiple destinations. Unlike iptables, there is no implicit “stop” — a message continues down the ruleset unless you explicitly use the stop action or a discard modifier (~).
Forwarding logs to a central collector.
The most common production use of rsyslog beyond local routing is shipping logs to a central syslog server (Graylog, Loki rsyslog input, a SIEM, or another rsyslog instance).
# Forward all logs to a remote syslog server over TCP:
# /etc/rsyslog.d/50-forward.conf
cat <<'EOF' | sudo tee /etc/rsyslog.d/50-forward.conf
# Load the TCP output module:
module(load="omfwd")
# Forward everything to central collector at 10.0.0.5:514 via TCP:
*.* action(type="omfwd"
target="10.0.0.5"
port="514"
protocol="tcp"
action.resumeRetryCount="-1"
queue.type="linkedList"
queue.size="10000"
queue.filename="fwd-queue"
queue.saveOnShutdown="on")
EOF
sudo systemctl restart rsyslog
# Verify rsyslog loaded the config without errors:
sudo rsyslogd -N1
# rsyslogd: version ..., config validation run ...
# rsyslogd: End of config validation run. Bye.
# Test by sending a message manually:
logger -p auth.info "test message from $(hostname)"
# On the collector, you should see the message arriveThe queue.saveOnShutdown="on" setting persists the outbound queue to disk so messages are not lost if rsyslog is restarted while the network is down. action.resumeRetryCount="-1" retries indefinitely instead of dropping messages after N failures.
journald forwarding to syslog via imjournal.
On modern Ubuntu/Debian, journald is the primary log collector. rsyslog reads from the journal via the imjournal input module, bridging structured journal entries into the classic syslog pipeline.
# The imjournal module is usually already enabled in /etc/rsyslog.conf:
grep -A5 'imjournal' /etc/rsyslog.conf
# module(load="imjournal"
# StateFile="/var/spool/rsyslog/imjournal.state"
# RateLimit.Interval="600"
# RateLimit.Burst="20000"
# IgnorePreviousMessages="off")
# This means:
# - rsyslog reads new journal entries as they arrive
# - StateFile tracks position (so a restart does not re-send old messages)
# - RateLimit prevents a logging storm from overwhelming rsyslog
# The alternative — ForwardToSyslog in journald.conf — was deprecated:
# DO NOT use ForwardToSyslog=yes (creates a Unix socket that rsyslog reads;
# less reliable than imjournal and not recommended in recent systemd versions)
# To verify messages are flowing from journal → rsyslog:
logger "test-syslog-routing"
grep "test-syslog-routing" /var/log/syslogThe key insight: on a modern box you usually only need to configure rsyslog’s forwarding destination. The journald → rsyslog bridge (imjournal) is already wired up. You are not replacing journald with rsyslog — you are using rsyslog as the forwarding agent for journal data.
Using logger to send test messages and verify routing.
logger is the command-line syslog client. It sends a message to syslog using any facility and severity you specify — essential for testing routing rules without triggering real events.
# Send a message at auth.info:
logger -p auth.info "login attempt from 203.0.113.42"
# Send a message at daemon.err:
logger -p daemon.err "connection pool exhausted"
# Send with a custom tag (appears in the log as the program name):
logger -t myapp -p local0.warning "rate limit hit for user 9812"
# Verify routing:
grep "login attempt" /var/log/auth.log # should appear here
grep "connection pool" /var/log/syslog # should appear here
grep "rate limit hit" /var/log/syslog # local0 → syslog by default
# Send to a remote rsyslog (useful for end-to-end test):
logger --server 10.0.0.5 --port 514 -p daemon.warning "remote test message"logger is indispensable when verifying a new rsyslog routing rule before it goes live: create the rule, restart rsyslog, send a logger test, confirm it appears in the right destination.
Configuring rsyslog to forward only auth events to a SIEM.
Security team asks: forward all auth and authpriv messages at any severity to a SIEM at 10.0.1.100:6514 over TCP. Local routing should be unchanged.
# Create a targeted forwarding rule:
sudo tee /etc/rsyslog.d/60-siem-forward.conf <<'EOF'
module(load="omfwd")
# Forward auth and authpriv at all severities to SIEM:
if ($syslogfacility-text == "auth" or $syslogfacility-text == "authpriv") then {
action(type="omfwd"
target="10.0.1.100"
port="6514"
protocol="tcp"
queue.type="linkedList"
queue.size="5000"
queue.saveOnShutdown="on")
}
EOF
# Validate config before restarting:
sudo rsyslogd -N1
# rsyslogd: config validation run: OK
sudo systemctl restart rsyslog
# Test:
logger -p auth.warning "sudo: user artemmac ran ls as root"
# Check SIEM received it (from the collector side)
# Verify it still appears locally:
tail /var/log/auth.log
# Jun 21 15:32:01 host artemmac: sudo: user artemmac ran ls as root
# Local routing intact — the forward rule does not remove from local files▸Why this works
Why rsyslog still matters alongside journald. journald is excellent for local structured storage and querying. It is not a log shipper. rsyslog (or Fluentd, Vector, Promtail) is how logs leave the box. The facility/severity taxonomy from 1983 is still the universal language: Graylog, Elasticsearch, Splunk, and every SIEM accept syslog-formatted input. Understanding facility.severity lets you write routing rules that send noisy daemon.debug to /dev/null locally while forwarding auth.* to the SIEM — without changing the application.
▸Common mistake
ForwardToSyslog=yes in journald.conf is deprecated and unreliable. An older pattern had journald forward over a Unix socket to rsyslog. This is superseded by rsyslog’s imjournal module, which reads the journal natively and tracks its position with a state file. If you see ForwardToSyslog=yes in a journald config, it may still work but is not recommended — use imjournal instead.
An rsyslog rule reads: auth,authpriv.* /var/log/auth.log. A second rule reads: *.*;auth,authpriv.none -/var/log/syslog. An SSH login event arrives tagged auth.info. Which files does it appear in?
The syslog model classifies every log message by facility (which subsystem: auth, cron, daemon, kern…) and severity (how bad: emerg through debug). rsyslog reads these and routes by facility.severity selectors to files, pipes, or remote destinations. On modern Ubuntu/Debian, rsyslog reads from journald via the imjournal module — journald is the collector, rsyslog is the router and shipper. omfwd forwards messages over TCP/UDP to a central collector. logger sends test syslog messages to verify routing rules. The .none modifier excludes a facility from a wildcard match (*.*;auth.none = everything except auth). rsyslog processes rules top to bottom; messages can match multiple rules and reach multiple destinations.
Practice
Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.