mirror of
https://github.com/rsyslog/rsyslog.git
synced 2026-05-10 22:00:48 +02:00
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
74 lines
1.9 KiB
Bash
Executable File
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
|