Commit graph

37 commits

Author SHA1 Message Date
Lukas Zapletal
3e37ad3b92 monitor: add duration to JSON logger
Some checks are pending
Checks / Spelling (push) Waiting to run
Checks / Python Linters (push) Waiting to run
Checks / Shell Linters (push) Waiting to run
Checks / 📦 Packit config lint (push) Waiting to run
Checks / 🔍 Check for valid snapshot urls (push) Waiting to run
Checks / 🔍 Check JSON files for formatting consistency (push) Waiting to run
Generate / Documentation (push) Waiting to run
Generate / Test Data (push) Waiting to run
Tests / Unittest (push) Waiting to run
Tests / Assembler test (legacy) (push) Waiting to run
Tests / Smoke run: unittest as normal user on default runner (push) Waiting to run
Although duration of each stage could be calculated from the start and
end timestamps, it is more convenient to have it directly in the log
entry. This way we can avoid calculating it in the client code.
2025-08-22 09:26:50 +02:00
Lukas Zapletal
5088c0ee69 monitor: fix duration calculation
When fully cached manifest is used, the duration used to print an
incorrect value of 55 years:

    python3 -m osbuild --libdir . ./test/data/manifests/fedora-boot.json
    ⏱  Duration: 1753191578s

This patch fixes the duration calculation to use the correct timestamp
from the manifest by using monotonic timer instead. Additionally, it
prints nothing when there was no module executed. Finally, it improves
the formatting of the duration output.
2025-08-22 09:26:50 +02:00
Michael Vogt
b22cbd3298 monitor: limit the amount of data sent in JSONSeqMontior.result()
This commit limits the output in the json pipeline to a "reasonable"
length. We ran into issues (e.g. [0]) from a combination of a stage
that produce tons of output (dracut, ~256 kb, see issue#1976) and
the consumer ("images" osbuild/monitor.go) that used a golang scanner
with a max default buffer of 64kb before erroring. So limit it
here.

The stage result from via json is mostly for information and any error
will most likely at the end. Plus consumers can collect the individual
log lines on their own if desired via the "log()" messages that are
stream in "real-time" with the added benefit that e.g. timestamps
can be added to the logs etc.

[0] https://issues.redhat.com/browse/RHEL-77988
2025-02-18 10:36:59 +01:00
Michael Vogt
035781ea1c osbuild: add a mutex to the _jsonseq() writer
This commit fixes a race/threading issue with the way the monitor
works. The osbuild monitor can be called from multiple threads,
e.g. in buildroot.py:run() monitor.log() is called but also
in host.py:_stdout_ready(). This can lead to out-of-order writes
when many messages need to be processed.

We did not notice this so far because we were lucky and also
log was just used for information. But now it is used to transmit
the jsonseq data which means out-of-order communication results
in broken json.

Closes: https://github.com/osbuild/image-builder-cli/issues/110
2025-01-30 20:08:53 +01:00
Michael Vogt
c27c32be0e osbuild: add result error reporting for sources
This commit adds error reporting from source download errors
to the monitor. It reuses the `BuildResult` for symmetry but
we probably want to refactor this a bit to make source handling
a bit more similar to stages.
2025-01-14 14:33:28 +01:00
Michael Vogt
5ba7cadd8b monitor: include build_result in jsonseq monitor streaming
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.
2025-01-14 14:33:28 +01:00
Michael Vogt
7b16313ce2 main,monitor: fix total steps in progress reporting
The existing code to record progress was a bit too naive. Instead
of just counting the number os pipelines in a manifest to get the
total steps we need to look at the resolved pipelines.

with this fix `bib` will report the correct number of steps left
when doing e.g. a qcow2 image build. Right now the number of
steps is incorrect because the osbuild manifest contains pipelines
for qcow2,vdmk,raw,ami and all are currently considered steps
that need to be completed. With this commit this is fixed.
2024-07-31 23:00:33 +02:00
Florian Schüller
41f528eeb2 osbuild/monitor.py: improve naming of progress 2024-06-18 16:00:55 +02:00
Michael Vogt
dd575465db monitor: make origin a setter 2024-03-12 16:44:12 +01:00
Michael Vogt
27ac6dd544 osbuild: use sort_keys=True when calculating the Context.id
Since we support python3.6 we cannot assume that dicts are ordered
in any way. To ensure the `id` is still always valid we pass
sort_keys=True to json.dump().

Thanks to Simon!
2024-03-12 16:44:12 +01:00
Michael Vogt
87015318d3 osbuild: tweak "origin=" values, thanks to Simon! 2024-03-12 16:44:12 +01:00
Michael Vogt
66468a3c58 osbuild: resolve TODOs
When an alternative monitor like JSONSeqMonitor is used there is
still non json output printed to stdout. This was a TODO but
this commit removes it because it's okay, there is the
"--monitor-fd" that should be used when using the json-seq monitor.
2024-03-12 16:44:12 +01:00
Michael Vogt
f214c69a98 osbuild: add workaround to integrate sources into progress reporting
This commit is somewhat poor, sorry for that. It mostly adds
workaround so that the osbuild sources can emit some progress
reporting as well. Without that the user experience is rather poor
and there is a long delay before any sort of progress can be
reported (even before the normal stages run).

With it the user experience is still not good but slightly better,
i.e. the progress monitor will report that the sources have
started downloading and curl will generated some log output. No
real progress unfortunately (sources subprogress will jump from
zero to 100%).
2024-03-12 16:44:12 +01:00
Michael Vogt
861f48a7e1 test,monitor: fix pep8/pylint issues 2024-03-12 16:44:12 +01:00
Michael Vogt
83e66839bc monitor: log start/stop of stages and pipelines too
Generate log messages with origin "org.osbuild.main" when
pipelines/stages start and finish. This way a higher level
frontend can display high level progress coming from this
origin and filter out e.g. stages based log messages (that
are usually quite technical as they are just stdout/stderr
from the stages).
2024-03-12 16:44:12 +01:00
Michael Vogt
fd61bcdcab monitor: introduce Context.with_origin()
The existing JSONSeqMonitor was saving/restoring the "origin"
when generating a new log-entry. This allows logging from
different origins (e.g. "org.osbuild.main") in a kind of
"out-of-band" fashion.

But this save/restore feels slightly inelegant because
JSONSeqMonitor feels like the wrong layer to deal with this.
This is why a new `with_origin()` helper is introduced that
will either reuse the existing context or create a new one
with the requested origin.
2024-03-12 16:44:12 +01:00
Michael Vogt
3fbd0b2a73 monitor: tweak/simplify Progress
Tweak the Progress class to be simpler. Given that progress does
not need to support arbitrary depth but only has a single level
the class now just exposes "sub_progress" to the caller.

When the main progress is advanced the sub_progress is now fully
deleted instead of just reset. The rational is that when the main
progress is done and advances a step it is very likely that a
new sub_progress is required and it's most likely an error if
the same sub_progress will get re-used.

This means that `reset()` can be removed as it's not used anymore
(and YAGNI). We can add it back when we have a use-case.

It also change the code so that "total" starts with 0 instead
of `None` (principle of least surprise). This means that now
`progress.incr()` is called in the JSONSeqMonitor() for
`finish()` and `result()` to indicate that the pipeline/stage
is finished.
2024-03-12 16:44:12 +01:00
Michael Vogt
de9ead53a2 montior: remove "unit" from Progress (YAGNI)
Removing "unit" from progress as it is currently unused and we
can always add it back when we have a real use-case.
2024-03-12 16:44:12 +01:00
Michael Vogt
1fa0472a8c monitor: tweak Context() to auto recalculate id, rename methods
This commit tweaks Context a bit so that any write will automatically
reset the `_id`. This ensures that we do not forget to reset `_id`
when the code changes.

It also tweaks the naming a bit, before there was a "setter" for
origin and functions to set "pipeline" and "stage". They are all
functions now with a "set_" prefix for symetry mostly.
2024-03-12 16:44:12 +01:00
Michael Vogt
ac16590838 monitor: refactor class LogLine to log_entry()
The class LogLine() is purely used as a dataclass with no state
and the only function on it is `as_dict()`. This got refactored
into a new function `log_entry()` because there is no need for
this to be a class. The function that takes the same inputs.
2024-03-12 16:44:12 +01:00
Michael Vogt
16c1768780 osbuild: make jsonseq montior creation more uniform
This changes the way monitors are initialized to always include
a `manifest` and now they will always log a `start` message.

This makes creation of a monitor symetric accross all monitors
again and no special cases for JSONSeqMonitor are required.

It means one needs to run the json-seq monitor with:
```
$ python3 -m osbuild --monitor=JSONSeqMonitor
```

Fwiw, I'm not 100% confident this is a win but it feels slightly
more right then the special cases in `main_cli.py` that is
replaces.
2024-03-12 16:44:12 +01:00
Michael Vogt
9bb42459aa monitor: use "omitempty" helper to remove None/"" values from json-seq output 2024-03-12 16:44:12 +01:00
Michael Vogt
c6eaac278d 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
2024-03-12 16:44:12 +01:00
Achilleas Koutsou
5510d0c42e monitor: add origin to log for all monitor classes
Adding the origin argument to the log() methods for all monitor classes.

Signed-off-by: Achilleas Koutsou <achilleas@koutsou.net>
2024-03-12 16:44:12 +01:00
Achilleas Koutsou
da4044bc7b monitor: JSONProgressMonitor class
New monitor type that emits a JSON object for each log message.

Unlike other monitors:
- The constructor takes a build manifest as argument to initialise the
  Pipeline and Stage counts for the Progress part of the report.
- It doesn't print a 'result' at the end of the build.
- The log() method that prints a log message supports specifying an
  origin to override the default that's set by the constructor.

Although the Logline supports reporting errors separately, this isn't
used yet.

Signed-off-by: Achilleas Koutsou <achilleas@koutsou.net>
2024-03-12 16:44:12 +01:00
Achilleas Koutsou
512933ddd4 monitor: classes for new progress monitor
Foundation for new monitor type that will emit a JSON object for each
log message. The following classes are defined:
- LogLine: The top-level object that can be serialised into a single
  object containing a message and associated metadata.
- Context: Contextual information for a log line message. Describes the
  origin of the message and the current pipeline and stage.
  Automatically deduplicates this information using a hash/ID: keeps a
  history of IDs and omits the context when the context is not new.
- Progress: Information on the progress of the build. The object is
  recursive: can contain a sub-progress for nested progress reporting
  (pipelines > stages > ...).

Signed-off-by: Achilleas Koutsou <achilleas@koutsou.net>
2024-03-12 16:44:12 +01:00
Michael Vogt
b3c6366135 osbuild: improve monitor docstrings/signatures
This is a split out from the work around json
progress in [1].

[1] https://github.com/osbuild/osbuild/compare/main...mvo5:osbuild:json-progress-mvo?expand=1
2023-11-28 09:56:56 +01:00
Christian Kellner
3cc26444c9 monitor: show pipeline's source epoch
If set, print the source epoch of the pipeline.
2022-12-15 13:10:35 +00:00
Christian Kellner
1c81d1e966 monitor/log: show build root and runner
In the `LogMonitor`, print the build root and its runner for each
pipelie. That could help identifying issues with runners.
2022-10-11 12:49:16 +02:00
Simon de Vlieger
ea6085fae6 osbuild: run isort on all files 2022-09-12 13:32:51 +02:00
Simon de Vlieger
873a071d43 osbuild: share terminal formats between files 2022-09-09 21:43:56 +02:00
Christian Kellner
b94b90b8e2 monitor: small whites pace fix
Extra line between class comment and `__init__`.
2022-05-06 17:33:23 +02:00
Christian Kellner
1bcbf3a2d2 monitor: properly initialize timer_start
It is set in `module()` which must be called before `result` so the
actual usage was fine, but it was not initialized in `__init__`.
2022-05-06 17:33:23 +02:00
Christian Kellner
34186daa4e monitor/log: print pipeline information
At the start of a pipeline, print its name and id so that it is
easier to follow along.
2021-02-12 15:55:43 +01:00
Christian Kellner
6c02002cbd pipeline: remove Assembler class
Now that assemblers are represented via the `Stage` class, the
Assembler class is not needed anymore. Adjust the monitor method
to take an `pipeline.Stage` for the `assembler` method as well.
2021-01-19 10:42:26 +01:00
Major Hayden
c0d71c3fa1 monitor: add assembler/stage duration
Allow a user to see the duration for each step in the osbuild pipeline.

This allows a user to optimize the build system for the best performance
and identify performance bottlenecks.

Signed-off-by: Major Hayden <major@redhat.com>
2020-08-06 16:19:47 +02:00
Christian Kellner
3e18d8118c api: introduce pipeline monitoring
Introduce the concept of pipeline monitoring: A new monitor class is
passed to the pipeline.run() function. The main idea is to separate
the monitoring from the code that builds pipeline. Through the build
process various methods will be called on that object, representing
the different steps and their targets during the build process. This
can be used to fully stream the output of the various stages or just
indicate the start and finish of the individual stages.

This replaces the 'interactive' argument throughout the pipeline
code. The old interactive behavior is replicated via the new
`LogMonitor` class that logs the beginning of stages/assembler,
but also streams all the output of them to stdout.
The non-interactive behavior of not reporting anything is done by
using the `NullMonitor` class, which in turn outputs nothing.
2020-07-21 13:25:04 +02:00