monitor: convert to json-seq

Tweak the existing json progress to follow the `application/json-seq`
media type as outlined in rfc7464 [0],[1].

[0] https://datatracker.ietf.org/doc/html/rfc7464
[1] https://en.wikipedia.org/wiki/JSON_streaming#Record_separator-delimited_JSON:wqu
This commit is contained in:
Michael Vogt 2023-11-15 17:36:52 +01:00 committed by Ondřej Budai
parent 83dc625fc3
commit c6eaac278d
3 changed files with 10 additions and 8 deletions

View file

@ -90,7 +90,7 @@ def parse_arguments(sys_argv: List[str]) -> argparse.Namespace:
parser.add_argument("--json-mode", metavar="MODE", type=str, default="batch",
help=("output mode for JSON format; "
"'batch' (default if unspecified) mode prints all the results when the build ends "
"'progress' prints status updates while building with each line being a JSON object"))
"'jsonseq' prints status updates while building with each line being a JSON object"))
parser.add_argument("--output-directory", metavar="DIRECTORY", type=os.path.abspath,
help="directory where result objects are stored")
parser.add_argument("--inspect", action="store_true",
@ -170,8 +170,8 @@ def osbuild_cli() -> int:
outfd = sys.stdout.fileno()
if args.json:
if args.json_mode == "progress":
monitor = osbuild.monitor.JSONProgressMonitor(outfd, manifest)
if args.json_mode == "jsonseq":
monitor = osbuild.monitor.JSONSeqMonitor(outfd, manifest)
monitor.log("start", origin="org.osbuild.main")
elif args.json_mode == "batch":
monitor = osbuild.monitor.NullMonitor(outfd)

View file

@ -289,8 +289,8 @@ class LogMonitor(BaseMonitor):
self.out.write(message)
class JSONProgressMonitor(BaseMonitor):
"""Monitor that prints the log output of modules wrapped in a JSON object with context and progress metadata"""
class JSONSeqMonitor(BaseMonitor):
"""Monitor that prints the log output of modules wrapped in json-seq objects with context and progress metadata"""
def __init__(self, fd: int, manifest: osbuild.Manifest):
super().__init__(fd)
@ -321,6 +321,8 @@ class JSONProgressMonitor(BaseMonitor):
if origin is not None:
self._context.origin = origin
line = LogLine(message=message, context=self._context, progress=self._progress)
# follow rfc7464 (application/json-seq)
self.out.write(u"\x1e")
json.dump(line.as_dict(), self.out)
self.out.write("\n")
self._context.origin = oo

View file

@ -13,7 +13,7 @@ from collections import defaultdict
import osbuild
import osbuild.meta
from osbuild.monitor import LogMonitor
from osbuild.monitor import JSONProgressMonitor, Context, Progress, LogLine
from osbuild.monitor import JSONSeqMonitor, Context, Progress, LogLine
from osbuild.objectstore import ObjectStore
from osbuild.pipeline import Runner
@ -195,7 +195,7 @@ def test_json_progress_monitor():
manifest.add_pipeline(pl2, "", "")
with tempfile.TemporaryFile() as tf:
mon = JSONProgressMonitor(tf.fileno(), manifest)
mon = JSONSeqMonitor(tf.fileno(), manifest)
mon.log("test-message-1")
mon.log("test-message-2", origin="test.origin.override")
mon.begin(manifest.pipelines["test-pipeline-first"])
@ -208,7 +208,7 @@ def test_json_progress_monitor():
mon.log("pipeline 2 message 2")
tf.seek(0)
log = tf.read().decode().strip().split("\n")
log = tf.read().decode().strip().split(u"\x1e")
assert len(log) == 7
logitem = json.loads(log[0])