rsyslog/tests/mmjsontransform-basic.sh
Rainer Gerhards 3935fc9575
mmjsontransform: add experimental JSON dotted-key (un)flatten
Real-world need: unflatten dotted JSON into nested objects, and optionally
flatten back for downstream tools. This introduces a general transformer
with a dedicated output tree. Interface is intentionally unstable.

Impact: New module behind --enable-mmjsontransform; no default behavior
changes. New tests and docs added. Parameters and behavior may change.

Add mmjsontransform, a message modification module that rewrites dotted
JSON keys. By default it "unflattens" an input object to nested containers
and stores the result in a configured output property. A mode parameter
also supports "flatten" to collapse nested trees into dotted keys. The
action refuses to overwrite an existing destination, validates that input
is a JSON object, and reports conflicts with precise key paths. Per-action
config is immutable; workers hold pointers only, so no extra locking. Docs
(Sphinx + parameter refs) and doxygen coverage included, plus a regression
test exercising nested arrays/objects. Build system and CI scripts gain
--enable-mmjsontransform and a basic test hook. An experimental companion
mmjsonrewrite module is wired similarly for dotted-key expansion.

Before/After: Previously no built-in JSON un/flatten; now an action can
unflatten (default) or flatten JSON into a separate message property.

With the help of AI Agents: ChatGPT codex, gemini
2025-10-03 17:35:36 +02:00

74 lines
1.9 KiB
Bash
Executable File

#!/bin/bash
# Validate mmjsontransform restructures dotted JSON keys into nested containers.
. ${srcdir:=.}/diag.sh init
generate_conf
add_conf '
module(load="../plugins/imtcp/.libs/imtcp")
module(load="../plugins/mmjsontransform/.libs/mmjsontransform")
input(type="imtcp" port="0" listenPortFileName="'$RSYSLOG_DYNNAME'.tcpflood_port")
template(name="outfmt" type="string" string="%$!output%\n%$!flattened%\n")
local4.* {
set $.ret = parse_json("{ \"a.b\": \"value\", \"a\": { \"existing\": 1 }, \"simple\": \"text\", \"nested.level.deep\": true, \"arr\": [ { \"inner.key\": 1 }, { \"plain\": 2 } ] }", "\$!input");
action(type="mmjsontransform" input="$!input" output="$!output")
action(type="mmjsontransform" mode="flatten" input="$!output" output="$!flattened")
action(type="omfile" file="'$RSYSLOG_OUT_LOG'" template="outfmt")
}
'
startup
tcpflood -m1
shutdown_when_empty
wait_shutdown
python3 - "$RSYSLOG_OUT_LOG" <<'PY'
import json
import sys
with open(sys.argv[1], "r", encoding="utf-8") as fh:
lines = [line.strip() for line in fh if line.strip()]
if len(lines) != 2:
print("expected 2 JSON lines, got", len(lines))
sys.exit(1)
unflattened = json.loads(lines[0])
flattened = json.loads(lines[1])
expected_unflattened = {
"a": {
"b": "value",
"existing": 1,
},
"simple": "text",
"nested": {"level": {"deep": True}},
"arr": [
{"inner": {"key": 1}},
{"plain": 2},
],
}
expected_flattened = {
"a.b": "value",
"a.existing": 1,
"simple": "text",
"nested.level.deep": True,
"arr": [
{"inner.key": 1},
{"plain": 2},
],
}
if unflattened != expected_unflattened:
print("unexpected unflattened output:", unflattened)
sys.exit(1)
if flattened != expected_flattened:
print("unexpected flattened output:", flattened)
sys.exit(1)
PY
exit_test