Skip to content

Commit

Permalink
monitor: include build_result in jsonseq monitor streaming
Browse files Browse the repository at this point in the history
In order to avoid having to rely on the output of `osbuild --json`
when using `--progress=JSONSeqMonitor` the monitor needs to include
the `osbuild.pipeline.BuildResult` for each individual stage.

This commit adds those to the montior.
  • Loading branch information
mvo5 committed Aug 5, 2024
1 parent ab9a199 commit b5eac92
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
32 changes: 24 additions & 8 deletions osbuild/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,12 @@ def as_dict(self):
return d


def log_entry(message: Optional[str] = None,
context: Optional[Context] = None,
progress: Optional[Progress] = None) -> dict:
def log_entry(
message: Optional[str] = None,
context: Optional[Context] = None,
progress: Optional[Progress] = None,
build_result: Optional[osbuild.pipeline.BuildResult] = None,
) -> dict:
"""
Create a single log entry dict with a given message, context, and progress objects.
All arguments are optional. A timestamp is added to the message.
Expand All @@ -174,6 +177,7 @@ def log_entry(message: Optional[str] = None,
# monitors support that
return omitempty({
"message": message,
"build_result": build_result.as_dict() if build_result else None,
"context": context.as_dict() if context else None,
"progress": progress.as_dict() if progress else None,
"timestamp": time.time(),
Expand Down Expand Up @@ -254,7 +258,7 @@ def __init__(self, fd: int, total_steps: int = 0):
super().__init__(fd, total_steps)
self.timer_start = 0

def result(self, result):
def result(self, result: osbuild.pipeline.BuildResult):
duration = int(time.time() - self.timer_start)
self.out.write(f"\n⏱ Duration: {duration}s\n")

Expand Down Expand Up @@ -339,13 +343,25 @@ def result(self, result: osbuild.pipeline.BuildResult):
# we may need to check pipeline ids here in the future
if self._progress.sub_progress:
self._progress.sub_progress.incr()
self.log(f"Finished module {result.name}", origin="osbuild.monitor")

self._jsonseq(log_entry(
f"Finished module {result.name}",
context=self._context.with_origin("osbuild.monitor"),
progress=self._progress,
# We should probably remove the "output" key from the result
# as it is redundant, each output already generates a "log()"
# message that is streamed to the client.
build_result=result,
))

def log(self, message, origin: Optional[str] = None):
entry = log_entry(message, self._context.with_origin(origin), self._progress)
self._jsonseq(entry)
self._jsonseq(log_entry(
message,
context=self._context.with_origin(origin),
progress=self._progress,
))

def _jsonseq(self, entry):
def _jsonseq(self, entry: dict) -> None:
# follow rfc7464 (application/json-seq)
self.out.write("\x1e")
json.dump(entry, self.out)
Expand Down
8 changes: 7 additions & 1 deletion test/mod/test_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def test_json_progress_monitor():
mon.log("pipeline 1 message 2")
mon.log("pipeline 1 finished", origin="org.osbuild")
mon.result(osbuild.pipeline.BuildResult(
fake_noop_stage, returncode=0, output="output", error=None))
fake_noop_stage, returncode=0, output="some output", error=None))
mon.finish({"success": True, "name": "test-pipeline-first"})
mon.begin(manifest.pipelines["test-pipeline-second"])
mon.log("pipeline 2 starting", origin="org.osbuild")
Expand Down Expand Up @@ -268,6 +268,12 @@ def test_json_progress_monitor():
logitem = json.loads(log[i])
assert logitem["message"] == "Finished module org.osbuild.noop"
assert logitem["context"]["id"] == id_start_module
assert logitem["build_result"] == {
"id": fake_noop_stage.id,
"name": "org.osbuild.noop",
"output": "some output",
"success": True,
}
i += 1

logitem = json.loads(log[i])
Expand Down

0 comments on commit b5eac92

Please sign in to comment.