YAML Configuration Format
rsyslog supports YAML as an additional configuration format for YAML-centric environments. YAML and RainerScript express the same core rsyslog model and share the same semantics.
rsyslog supports configuration via YAML files as an additional format alongside RainerScript. It is one of the supported configuration formats and is a good fit when rsyslog is part of a broader YAML-centric operational workflow.
Typical examples include Kubernetes deployments, Ansible-managed systems, GitOps-style repositories, generated configuration, and AI-assisted infrastructure workflows. In those environments YAML support reduces integration friction because rsyslog can stay in the same format family as the surrounding tooling instead of relying on conversion steps or embedded RainerScript text.
This is about workflow fit, not about replacing RainerScript. The two formats
express the same core rsyslog concepts, including inputs, actions, rulesets,
filters and routing, templates, and queues. Every YAML configuration key maps
directly to a RainerScript parameter of the same name, so all per-module
documentation remains applicable unchanged. You can also mix formats: a YAML
main config may include RainerScript .conf fragments and vice versa.
Continuity with RainerScript
Existing RainerScript configurations remain fully valid and fully supported. You do not need to migrate them in order to use current rsyslog features.
Existing RainerScript knowledge also transfers directly. YAML changes the surface syntax, but it does not introduce a separate rsyslog model or separate runtime semantics.
If you want to migrate an existing RainerScript config into YAML, rsyslog can
generate canonical YAML directly via rsyslogd -N1 -F yaml -o .... Simple
rulesets are emitted as structured YAML such as actions: or filter: +
actions:, and a limited set of common legacy selector/action forms is
normalized into structured YAML statements:. More complex bodies still
fall back to script: |. See
Translating Between RainerScript and YAML for the workflow and caveats.
When to Use YAML or RainerScript
Choose the format that fits your environment and workflow:
Use YAML when rsyslog is part of a broader YAML-centric deployment or automation workflow.
Use RainerScript when you already work effectively with it, when your team authors rsyslog logic directly, or when it is simply the clearer fit for your operational model.
Mix formats when that is practical. YAML and RainerScript can include each other and share the same object names and parameter semantics.
Activation
rsyslog automatically selects the YAML loader whenever the configuration
file name ends in .yaml or .yml. No special flag or directive is
required:
rsyslogd -f /etc/rsyslog.yaml
The same detection applies to files pulled in via include() (from a
RainerScript config) or the include: section of a YAML config. It is
therefore valid to mix formats: a YAML main config may include .conf
RainerScript fragments and vice versa.
Note
YAML configuration support requires rsyslog 8.2604.0 or later. Older distribution packages do not include this feature. Up-to-date packages for many platforms are available via www.rsyslog.com. The easiest option is often a containerized build: the rsyslog team publishes ready-to-use images documented in Rsyslog Containers.
In addition, rsyslog must have been compiled with libyaml
(yaml-0.1). If libyaml is absent at build time the daemon will
print an error and refuse to load a .yaml / .yml file.
Install the libyaml-dev (Debian/Ubuntu) or libyaml-devel
(RHEL/Fedora) package before compiling.
Schema Overview
A YAML config file is a single YAML mapping (dictionary) whose top-level keys correspond to rsyslog configuration object types:
version: 2 # optional, informational only
global: { ... }
modules: [ ... ]
inputs: [ ... ]
templates: [ ... ]
rulesets: [ ... ]
mainqueue: { ... }
include: [ ... ]
parsers: [ ... ]
lookup_tables: [ ... ]
dyn_stats: [ ... ]
perctile_stats: [ ... ] # note: spelt "perctile" — matches rsyslog internal naming
ratelimits: [ ... ]
timezones: [ ... ]
All section names are case-sensitive. Unknown top-level keys are logged
as errors and ignored. Each top-level key must appear at most once;
duplicate keys are undefined behaviour in the YAML specification and
unsupported by rsyslog — a warning is logged if a duplicate is detected.
To specify multiple items of the same type use a sequence under one key,
or use include: for file-level composition.
Singleton Sections
global and mainqueue are singleton sections: their value is a
mapping of parameter names to values.
global:
workdirectory: "/var/spool/rsyslog"
maxmessagesize: 8192
defaultnetstreamdriver: "gtls"
privdrop.user.name: "syslog"
privdrop.group.name: "syslog"
mainqueue:
type: linkedlist
size: 100000
dequeuebatchsize: 1024
Parameter names are identical to their RainerScript counterparts (see global configuration parameters and queue parameters).
Sequence Sections
modules, inputs, templates, rulesets, parsers,
lookup_tables, dyn_stats, perctile_stats, ratelimits, and
timezones are sequences: each list element is a mapping that describes
one object of that type.
modules
Each item must contain a load key (the module name). Additional keys
supply module-level parameters:
modules:
- load: imuxsock
- load: imklog
- load: imtcp
threads: 2
- load: imudp
inputs
Each item must contain a type key. All other keys are input instance
parameters:
inputs:
- type: imtcp
port: "514"
ruleset: main
- type: imudp
port: "514"
ruleset: main
- type: imfile
file: "/var/log/app/*.log"
tag: "applog"
ruleset: main
templates
Four template types are supported:
String template — the most common type; a format string with %PROPERTY%
placeholders:
templates:
- name: myFormat
type: string
string: "%HOSTNAME% %syslogfacility-text%.%syslogseverity-text% %msg%\n"
- name: filePerHost # use with omfile dynafile: filePerHost
type: string
string: "/var/log/hosts/%HOSTNAME%.log"
Subtree template — serialises a JSON sub-tree of the message object:
templates:
- name: jsonApp
type: subtree
subtree: "$!app"
List template — assembles output from an explicit sequence of property
and constant items. Each element maps to a property() or
constant() call; all parameters accepted by those RainerScript
functions can be used:
templates:
- name: listFmt
type: list
elements:
- property:
name: timestamp
dateformat: rfc3339
- constant:
value: " "
- property:
name: hostname
- constant:
value: " "
- property:
name: msg
droplastlf: "on"
- constant:
value: "\n"
Plugin template — delegates formatting to an external string-generator
plugin (the type="plugin" form from RainerScript):
templates:
- name: myPlugin
type: plugin
plugin: strgen_addprimary
rulesets
Ruleset items specify a name and may carry queue parameters. Rule
logic is expressed in one of three ways:
Structured shortcut (
filter:+actions:) — for simple priority- or property-based routing without scripting. See Structured Filter Shortcut below.YAML-native statements (
statements:key) — for conditional routing,if/then/else,call,call_indirect,foreach,stop,unset, variable assignment — without writing raw RainerScript blocks. See YAML-Native Statements below. Recommended for most YAML configs.Inline RainerScript (
script:key) — intentional escape hatch for advanced logic that is better expressed directly in RainerScript. See Scripting below.
filter: + actions: example:
rulesets:
- name: main
filter: "*.*"
actions:
- type: omfile
file: "/var/log/syslog"
- name: errors
filter: "*.err"
actions:
- type: omfile
file: "/var/log/errors.log"
- type: omfwd
target: "logserver.example.com"
port: "514"
protocol: "tcp"
# Property filter — starts with ':'
- name: tag_filter
filter: ":syslogtag, startswith, \"myapp\""
actions:
- type: omfile
file: "/var/log/myapp.log"
# No filter — unconditional routing
- name: archive
actions:
- type: omfile
file: "/var/log/archive.log"
script: example (complex logic):
rulesets:
- name: errors
script: |
if $syslogseverity <= 3 then {
action(type="omfile" file="/var/log/errors.log")
}
stop
parsers
Custom parser chains (loaded via lmregdups, pmrfc3164, etc.).
Each item must contain a name key and the parser-specific parameters:
parsers:
- name: pmrfc3164.default
force.tagEndingByColon: "on"
lookup_tables
In-memory lookup tables loaded from JSON files. The name and
filename keys are required.
lookup_tables:
- name: hostmap
filename: "/etc/rsyslog.d/hostmap.json"
reloadOnHUP: "on"
timezones
Named timezone definitions for use in template date formatting:
timezones:
- id: "CET"
offset: "+01:00"
dyn_stats, perctile_stats, ratelimits
These advanced sections follow the same key=value mapping pattern. Refer to the respective module documentation for available parameters. Example:
dyn_stats:
- name: "msg_rate"
resetsIntervals: 60
ratelimits:
- name: "input_rl"
interval: 5
burst: 1000
Arrays
Parameters that accept a list of values are expressed as YAML sequences:
global:
environment:
- "TZ=UTC"
- "LC_ALL=C"
Including Other Files
The include: section accepts a sequence of items. Each item must have
a path key (which may contain shell globs) and an optional optional
flag:
include:
- path: "/etc/rsyslog.d/*.yaml"
optional: "on"
- path: "/etc/rsyslog.d/*.conf"
optional: "on"
- path: "/etc/rsyslog.d/tls.conf"
If optional is on (or yes or 1) a missing file or empty
glob result is not an error. Files with a .yaml or .yml extension
are loaded by the YAML loader; all other files are loaded by the
RainerScript parser.
Note
Include ordering with mixed file types: within one include:
list, .yaml files are always loaded before .conf files,
regardless of their order in the list. This is an architectural
constraint — YAML sub-files are processed immediately and recursively,
while .conf files are deferred to the RainerScript flex-buffer
stack. If strict ordering between .yaml and .conf fragments
matters, use separate include: sections or consolidate to one
file type. Multiple .conf entries within the same list ARE
processed in document order.
Structured Filter Shortcut
For common routing patterns (match by severity or message property, then
write to one or more outputs) you do not need any RainerScript. Use
filter: and actions: directly on a ruleset:
filter:Optional string. Two forms are recognised:
Priority filter — standard syslog selector syntax (e.g.
*.info,kern.warn,auth,authpriv.*).Property filter — starts with
:(e.g.:msg, contains, "error").
If
filter:is absent, all messages match (unconditional routing).actions:YAML sequence. Each item maps directly to a
action()call; thetypekey names the output module and all remaining keys are module-specific parameters. Multiple actions are chained in order.
rulesets:
# Route *.info to syslog; *.err also to a dedicated error file
- name: main
filter: "*.info"
actions:
- type: omfile
file: "/var/log/syslog"
- name: errors
filter: "*.err"
actions:
- type: omfile
file: "/var/log/errors.log"
- type: omfwd
target: "logserver.example.com"
port: "514"
protocol: "tcp"
# Property filter
- name: myapp
filter: ":syslogtag, startswith, \"myapp\""
actions:
- type: omfile
file: "/var/log/myapp.log"
Note
filter: and actions: are mutually exclusive with script: and
statements:.
If you need conditionals, loops, set, call, or stop,
use statements: (recommended) or script: instead.
YAML-Native Statements
The statements: key is the recommended way to express conditional routing
and control flow for most YAML configs. Each item in the sequence is a YAML
mapping that represents one statement. Only the filter expression inside
if: remains as a RainerScript expression string. All structural elements
and action parameters are expressed as YAML.
statements: is mutually exclusive with script:, filter:, and
actions:.
If / action (single action shorthand)
rulesets:
- name: main
statements:
- if: '$msg contains "error"'
action:
type: omfile
file: "/var/log/errors.log"
else: # optional
- stop: true
If / then / else (multiple statements per branch)
rulesets:
- name: main
statements:
- if: '$syslogseverity <= 3'
then:
- type: omfile
file: "/var/log/critical.log"
- type: omfwd
target: "logserver.example.com"
port: "514"
protocol: "tcp"
else:
- type: omfile
file: "/var/log/messages"
Control flow: stop, continue, call
- stop: true # stop processing this message
- continue: true # continue (no-op, rarely needed)
- call: other_rs # call another ruleset by name
Variable assignment
- set:
var: "$.nbr"
expr: 'field($msg, 58, 2)'
Supported statement types
Type |
YAML form |
|---|---|
Action |
|
If/action |
|
If/then |
|
Stop |
|
Continue |
|
Call |
|
Set |
|
Unset |
|
call_indirect |
|
foreach |
|
reload_lookup_table |
|
foreach iterates over a JSON array. The do: value is a sequence of
statement items using the same syntax as statements:.
Complex routing and iteration example
This example demonstrates how to combine variable assignment, a foreach loop,
and a nested if/then/else statement to achieve complex routing without writing
raw RainerScript blocks.
rulesets:
- name: process_items
statements:
# Set a local variable based on message content
- set:
var: "$.is_audit"
expr: 're_match($msg, "AUDIT")'
# Parse the JSON message content into $! variables
- type: mmjsonparse
# Iterate over a JSON array in the message
- foreach:
var: "$.item"
in: "$!items"
do:
- if: '$.is_audit == 1'
then:
- type: omfile
file: /var/log/audit_items.log
template: outfmt
else:
- if: '$.item!type == "error"'
then:
- type: omfile
file: /var/log/error_items.log
template: outfmt
else:
- type: omfile
file: /var/log/standard_items.log
template: outfmt
Scripting
Use script: when a ruleset is better expressed directly in RainerScript,
or when you need advanced logic that you intentionally want to keep in
RainerScript form. For normal YAML configs, prefer statements: so the
structure stays visible to YAML tooling, review, and generation workflows.
RainerScript filter expressions and statement types (if/then/else,
set, unset, foreach, stop, call, legacy PRI-filters,
property-filters, action()) are all available inside a script:
block. The value is an ordinary YAML scalar (use a
YAML block scalar
for multi-line content):
rulesets:
- name: main
script: |
# Route by severity
if $syslogseverity <= 3 then {
action(type="omfile" file="/var/log/critical.log")
action(type="omfwd" target="logserver.example.com" port="514"
protocol="tcp")
}
# Discard noisy debug messages
if $syslogseverity == 7 then stop
# Default sink
action(type="omfile" file="/var/log/messages")
The script content is passed verbatim to the RainerScript lexer/parser,
so anything that is valid RainerScript in a ruleset() {} body is valid
here. Inline actions defined in the script: block do not need to
be listed separately under an inputs: or actions: section.
Tip
For simple routing (one filter, one or more actions, no branching)
use the filter: + actions: shortcut described in
Structured Filter Shortcut.
For conditional routing, variable assignments, call, foreach,
stop, and reload_lookup_table use the statements: block
described in YAML-Native Statements. Recommended for most YAML
configs.
Reserve script: for advanced logic that is better expressed directly in
RainerScript, such as complex nested legacy priority/property filters or
inline call_direct patterns.
Complete Example
The following is a near-complete rsyslog YAML configuration equivalent to
a typical /etc/rsyslog.conf:
version: 2
global:
workdirectory: "/var/spool/rsyslog"
maxmessagesize: 8192
privdrop.user.name: "syslog"
privdrop.group.name: "adm"
modules:
- load: imuxsock
- load: imklog
- load: imtcp
threads: 2
inputs:
- type: imtcp
port: "514"
ruleset: main
- type: imuxsock
templates:
- name: fileFormat
type: string
string: "%TIMESTAMP% %HOSTNAME% %syslogtag%%msg%\n"
mainqueue:
type: linkedlist
size: 100000
rulesets:
- name: main
filter: "auth,authpriv.*"
actions:
- type: omfile
file: "/var/log/auth.log"
- name: main_all
filter: "*.*;auth,authpriv.none"
actions:
- type: omfile
file: "/var/log/syslog"
- name: kern
filter: "kern.*"
actions:
- type: omfile
file: "/var/log/kern.log"
- name: emerg
filter: "*.emerg"
actions:
- type: omusrmsg
users: "*"
include:
- path: "/etc/rsyslog.d/*.yaml"
optional: "on"
- path: "/etc/rsyslog.d/*.conf"
optional: "on"
Relationship to RainerScript
YAML configuration is a thin translation front-end over the same internal
machinery that RainerScript uses. The YAML parser (runtime/yamlconf.c)
converts each YAML block into cnfobj + nvlst structures — the identical
intermediate representation that the RainerScript lex/bison grammar produces —
and hands them to the shared cnfDoObj() dispatcher. There is no independent
YAML runtime; the shared back-end handles all validation, module initialisation,
and execution.
That shared back-end is why RainerScript experience transfers directly. Whether you write YAML or RainerScript, you are still configuring the same rsyslog objects and execution model.
This approach deliberately minimises the change surface: the YAML-specific code is confined to one file with no runtime presence after configuration loading. It may be refactored in the future, but only when concrete requirements justify the additional maintenance surface.
In practical terms:
Parameter names are identical; all per-module parameter documentation applies without change.
Type coercion (integers, sizes, binary flags, UIDs, …) is performed by the same
nvlstGetParams()layer after YAML parsing.Unknown parameter names produce the same “unused parameter” error regardless of which format was used.
Template, ruleset, and lookup-table names are shared; a YAML-defined ruleset can be referenced from a RainerScript
action().
For a detailed description of the pipeline see yaml_config_architecture.
Limitations (current implementation)
Nested YAML mappings inside parameter values are not supported. Use a YAML scalar or sequence.
filter:+actions:support one flat filter level. For nestedif/then/elsechains usestatements:(recommended) orscript:.version:is accepted but not enforced; it is reserved for future schema evolution.Within a single
include:list,.yamlfiles are always processed before.conffiles regardless of document order (see Including Other Files).
See Also
Support: rsyslog Assistant | GitHub Discussions | GitHub Issues: rsyslog source project
Contributing: Source & docs: rsyslog source project
© 2008–2026 Rainer Gerhards and others. Licensed under the Apache License 2.0.