rsyslog/tests/template-jsonf-nested.sh
Rainer Gerhards e9d485757f
template: add jsonftree option for nested jsonf output
We want easy nested JSON to match common schemas (e.g., Elastic ECS)
without external processors. This introduces an opt-in mode so existing
jsonf users keep exact behavior while enabling structured output when
requested.

Impact: No change unless option.jsonftree is enabled. With jsonftree,
dotted outnames render as nested objects; empty containers are skipped.
On name collisions (object vs value), we fall back to flat rendering.

Before: jsonf always emitted flat name/value pairs, even for dotted
outnames. After: jsonf remains flat by default; enabling jsonftree makes
"host.hostname" and "host.ip" render as {"host":{"hostname":...,"ip":...}}.

Technically, we add option.jsonftree to templates. When set, we lazily
build a per-template JSON tree (tplJsonNode) from dotted segments and
render it in one pass, reusing existing jsonf formatting for leaves.
The tree state is tracked on the template and freed on template delete.
Config parsing enforces mutual exclusivity among sql, stdsql, json,
jsonf, and jsonftree. Constants record bJSONf to reuse serialized
fragments. Tests cover nested output and pure-json cases using
option.jsonftree.
2025-09-24 18:12:00 +02:00

41 lines
1.3 KiB
Bash
Executable File

#!/bin/bash
# added by AI agent to verify nested jsonf output; Released under ASL 2.0
. ${srcdir:=.}/diag.sh init
generate_conf
add_conf '
template(name="nested" type="list" option.jsonftree="on") {
constant(outname="host.hostname" value="testhost" format="jsonf")
constant(outname="host.ip" value="127.0.0.1" format="jsonf")
constant(outname="event.dataset.name" value="syslog" format="jsonf")
property(outname="event.original" name="msg" format="jsonf")
}
local4.* action(type="omfile" file=`echo $RSYSLOG_OUT_LOG` template="nested")
'
startup
injectmsg 0 1
shutdown_when_empty
wait_shutdown
export EXPECTED_JSON='{"host": {"hostname": "testhost", "ip": "127.0.0.1"}, "event": {"dataset": {"name": "syslog"}, "original":" msgnum:00000000:"}}'
python3 - "$RSYSLOG_OUT_LOG" <<'PY'
import json
import os
import sys
expected = json.loads(os.environ['EXPECTED_JSON'])
with open(sys.argv[1], 'r', encoding='utf-8') as fh:
actual = json.loads(fh.read())
if actual != expected:
print('invalid response generated')
print('################# actual JSON is:')
print(json.dumps(actual, indent=2, sort_keys=True))
print('################# expected JSON was:')
print(json.dumps(expected, indent=2, sort_keys=True))
sys.exit(1)
PY
exit_test