Log workflow output - #14301
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #14301 +/- ##
==========================================
+ Coverage 91.17% 91.20% +0.03%
==========================================
Files 495 496 +1
Lines 36095 36244 +149
==========================================
+ Hits 32908 33055 +147
- Misses 3187 3189 +2
Flags with carried forward coverage won't be shown. Click here to find out more.
|
| @contextlib.contextmanager | ||
| def capture(self) -> Iterator[io.StringIO]: | ||
| """Record what the calling thread writes for the duration of the block.""" | ||
| buffer = io.StringIO() |
There was a problem hiding this comment.
shouldn't all of this be in the try block rather than only the yield?
There was a problem hiding this comment.
I meant more like if this fails buffers = self._buffers, but I guess then we don't want to remove it from the list.
So it might be good 👍
| CANCELLED = "cancelled" | ||
|
|
||
|
|
||
| def _job_description( |
There was a problem hiding this comment.
This can't be a WorkflowJobResult member / function?
xjules
left a comment
There was a problem hiding this comment.
It looks already very good!
Had only a smaller comments.
Also, there are way to many articles in the test names: remove the, a and an
33034fb to
6b7bf43
Compare
Workflow carried no name of its own, so anything reporting on a workflow had to fall back to the source file path. LOAD_WORKFLOW lets a workflow be given a name, and that is the name users recognise. Store the name on Workflow, defaulting to the file name when none is given, so it can be reported alongside the jobs that were run. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
WorkflowJobRunner.run() set the running flag before validating its arguments but only cleared it on the success path, so a job rejected for too few or too many arguments kept reporting that it was still running. workflowReport() is also keyed by job name, so a workflow running the same job more than once kept only the output of the last invocation. Add WorkflowJobResult, recording name, index, arguments, output, status and timestamp per invocation, and expose the ordered list through workflow_job_results(). Status is modelled as a WorkflowJobStatus enum rather than a failed/cancelled boolean pair, since the booleans could express states that do not exist; a job interrupted mid-run is now reported as cancelled instead of failed. Jobs skipped because the workflow was cancelled are recorded too, so a cancelled workflow can be told apart from one that never ran. A job that stops the workflow is recorded before the error is raised, so its output is not lost. workflowReport() is left as it is, since the run workflow tool and the CLI still use it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Internal python workflow jobs wrote straight to sys.stdout/sys.stderr, so their output was visible in the terminal but not available to ERT itself, and was lost once that terminal was gone. External jobs captured their subprocess output but did not pass stdout on to the terminal. Replace sys.stdout/sys.stderr with a proxy while a job runs, recording what the calling thread writes while still forwarding it to the real stream. Capture is per-thread, so concurrently running jobs do not pick up each other's output. The proxy and its context manager live in their own module, since they are self-contained and have nothing to do with ErtScript beyond the single call that uses them. Write one log entry per job invocation to the ERT log, naming the hook, the workflow and the job, and quoting the arguments, stdout and stderr, built on WorkflowRunner so the starting and result lines share one format. This covers hooked workflows, 'ert workflow' and the GUI Run workflow tool, since all three go through WorkflowRunner. Also stop reporting a failing external job with an ERT stack trace: the new ExternalScriptError carries the exit code, since the traceback would only show ERT internals. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
6b7bf43 to
da83710
Compare
Test names introduced in this PR used "a", "an" and "the", which does not follow this repo's naming convention and was flagged repeatedly on the sibling PR #14301. Rename them to read as plain behaviour specifications. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>


Issue
Part of #13320
Closes #14308
Approach
First of two PRs splitting the original "Store workflow output" work. This one
covers capturing workflow job output and writing it to the ERT log; the
follow-up (#14062) adds the
WorkflowEventand persists events to experiment storage.Workflow job output previously only reached the terminal ERT was started from,
so it was lost once that terminal was gone, and a job run outside a terminal
left no record at all.
sys.stdout/sys.stderrwith a thread-aware_CaptureProxywhile ajob runs, recording what the calling thread writes while still forwarding it
to the real stream. Concurrently running jobs do not pick up each other's
output.
WorkflowJobResult, recording name, index, arguments, output, status andtimestamp per invocation.
workflowReport()is keyed by job name, so aworkflow running the same job twice previously kept only the last invocation's
output.
LOAD_WORKFLOWalias, so reporting can use thename users recognise rather than the source file path.
Covers hooked workflows,
ert workflowand the GUI Run workflow tool, sinceall three go through
WorkflowRunner.Also fixes two latent bugs found along the way: the running flag was not cleared
when a job was rejected for bad arguments, and a job that stopped the workflow
had its output dropped before it could be recorded.
git rebase -i main --exec 'just rapid-tests')When applicable
merge screenshot-PR in ert-testdata before merging this PR.