diff --git a/.config/jp/tools/src/debug_jp/trace.rs b/.config/jp/tools/src/debug_jp/trace.rs index 990766544..1ec203139 100644 --- a/.config/jp/tools/src/debug_jp/trace.rs +++ b/.config/jp/tools/src/debug_jp/trace.rs @@ -1,11 +1,15 @@ //! `debug_jp_trace` — capture and render `JP_DEBUG=1` trace logs. //! -//! Launches `jp` inside the sandbox with `JP_DEBUG=1` set. -//! `jp_cli` persists its tracing-subscriber output to a system temp file and -//! prints `Full trace log written to: ` on stderr at exit. -//! We parse that line, copy the file out to the real workspace so it survives -//! sandbox cleanup, filter the events by level/target/grep, and render the -//! result in a compact logfmt-like format. +//! Launches `jp` inside the sandbox with `JP_DEBUG=1` set and `--log-file` +//! pointing at a path in the real workspace, so the trace log lands at a known +//! location that survives sandbox cleanup — even when jp is force-killed, +//! since the file layer writes events as they happen. +//! When the file is missing (jp exited before logging was configured), we fall +//! back to the path jp announces on stderr at exit: a `Full trace log written +//! to: ` line (text output) or a `{"trace_log": ""}` object (JSON +//! output). +//! The events are then filtered by level/target/grep and rendered in a compact +//! logfmt-like format. use std::{ fs, @@ -22,17 +26,13 @@ use crate::{ build::{self, BuildSpec}, launch::{LaunchResult, LaunchSpec, Launcher, RealLauncher, Timeouts}, sandbox::{Sandbox, SandboxOpts}, - trace_parse::{self, Level, TraceEvent}, + trace_parse::{self, Level, TRACE_PATH_PREFIX, TraceEvent}, trace_render::{self, CommandRun, OutputPaths}, with_termination_note, }, util::{ToolResult, error, runner::DuctProcessRunner}, }; -/// Marker line `jp_cli::run` writes to stderr when `JP_DEBUG=1` and the output -/// format is text (we never pass `--format=json`, so this is what we get). -const TRACE_PATH_PREFIX: &str = "Full trace log written to: "; - /// Tool entrypoint. /// Dispatches between the format-args preview and the live execution. #[allow(clippy::unused_async, reason = "awaited by the debug_jp dispatcher")] @@ -109,14 +109,17 @@ fn format_preview( out.push_str("cargo build --profile profiling -p jp_cli --bin jp\n"); if let [command] = commands { out.push_str(&format!( - "JP_DEBUG=1 target/profiling/jp {} # invoked by absolute path\n", + "JP_DEBUG=1 target/profiling/jp --log-file tmp/profiling/trace-.jsonl {} # \ + invoked by absolute path\n", command.join(" ") )); } else { out.push_str("# commands run in sequence in one sandbox (state persists between them):\n"); for (i, command) in commands.iter().enumerate() { out.push_str(&format!( - "JP_DEBUG=1 target/profiling/jp {} # command {}\n", + "JP_DEBUG=1 target/profiling/jp --log-file tmp/profiling/trace--cmd{}.jsonl \ + {} # command {}\n", + i + 1, command.join(" "), i + 1 )); @@ -363,12 +366,13 @@ struct CommandArtifacts { stderr_dst: Utf8PathBuf, } -/// Launch jp via `launcher`, copy its trace log and streams into `out_dir` +/// Launch jp via `launcher`, collect its trace log and streams into `out_dir` /// (keyed by `