Give each orchestrator child its own log as well as the parent's

Everything a child printed was interleaved into the parent's log with forty
other scripts, separated only by human headings that map to no script id — so
scoped_log could answer for ten orchestrators and nothing else. tee rather than
a redirect, so the parent keeps receiving exactly what it did before and this
only adds a destination; PIPESTATUS[0] preserves the child's exit code through
the pipe. Trimmed to 1000 lines like run_job.sh does, because LOG_DIR is tmpfs
and an untrimmed chatty script spends RAM. Falls back to the original unpiped
call when the log cannot be opened — a child must never be denied a run because
somewhere to write about it could not be created.
This commit is contained in:
Gmer4Lfe
2026-08-14 18:35:42 -04:00
parent 95050850d6
commit fa7af04418
+42 -3
View File
@@ -2115,6 +2115,19 @@ _orch_child_record() {
return 0
}
# Keeps a child's own log to the same ceiling run_job.sh keeps a job's: the last 1000 lines,
# replaced atomically. LOG_DIR is tmpfs, so an untrimmed chatty script spends RAM rather than disk,
# which is the worse of the two places to leak.
_orch_trim_log() {
local f="$1" n
[[ -f "$f" ]] || return 0
n=$(wc -l < "$f" 2>/dev/null) || return 0
(( n > 1000 )) || return 0
tail -n 1000 "$f" > "$f.tmp" 2>/dev/null && mv -f "$f.tmp" "$f" 2>/dev/null
rm -f "$f.tmp" 2>/dev/null
return 0
}
run_orch_child() {
local entry="$1"
local script_args script_path script_name label extra_args run_args
@@ -2137,17 +2150,43 @@ run_orch_child() {
[[ "$DRY_RUN" == true ]] && run_args+=("--dry-run")
[[ "$ENABLE_LOGGING" == true ]] && run_args+=("--log")
local _start _ec
local _start _ec _clog
_start=$(date +%s)
log "Running: $label"
_orch_child_record "${script_args[0]}" "$_start"
if bash "$script_path" "${run_args[@]}"; then
# The child's output goes to its own log as well as the orchestrator's, so a script can be
# read on its own terms. Until now everything a child printed was interleaved into the
# parent's log with forty other scripts, and the only marker separating them was a human
# heading like "━━━ Media Cleaner — anime ━━━" that maps to no script id — which is why
# scoped_log could answer for ten orchestrators and nothing else.
#
# tee, not a redirect: the parent's log must keep receiving everything exactly as before, so
# this adds a destination rather than moving one. PIPESTATUS[0] is what preserves the child's
# exit code through the pipe — $? would report tee's.
#
# The whole thing is conditional on the log being writable, and falls back to the original
# unpiped call when it is not. A child must never fail, or be denied a run, because somewhere
# to write about it could not be opened.
_clog="${LOG_DIR:-}/${script_args[0]%.sh}.log"
if [[ -n "${LOG_DIR:-}" ]] && mkdir -p "$(dirname "$_clog")" 2>/dev/null \
&& : >> "$_clog" 2>/dev/null; then
printf '\n── %s ────────────────────────────────────────────────\n' \
"$(date '+%Y-%m-%d %H:%M:%S')" >> "$_clog" 2>/dev/null
bash "$script_path" "${run_args[@]}" 2>&1 | tee -a "$_clog"
_ec=${PIPESTATUS[0]}
_orch_trim_log "$_clog"
else
bash "$script_path" "${run_args[@]}"
_ec=$?
fi
if (( _ec == 0 )); then
log "$script_name — done in $(format_duration $(( $(date +%s) - _start )))"
_orch_child_record "${script_args[0]}" "$_start" 0
JOB_PASS+=("$label")
return 0
else
_ec=$?
_orch_child_record "${script_args[0]}" "$_start" "$_ec"
# Match the severity ladder run_job.sh already records against: exit 1 is a warning,
# exit 2+ is an error. The status in the run record was always derived that way, so a