events : instrumentation start/stop/run/install/update/uninstall/doctor/repl/shell (issue #3) - un evenement JSONL par action reelle, dry-run sans evenement, session id sur start, duree et exit code sur stop/run
This commit is contained in:
+65
-2
@@ -2,6 +2,7 @@
|
||||
|
||||
use super::*;
|
||||
use crate::cli::StartArgs;
|
||||
use crate::events::{self, Event, EventKind};
|
||||
use crate::process;
|
||||
use anyhow::{bail, Context, Result};
|
||||
use std::collections::BTreeMap;
|
||||
@@ -51,6 +52,15 @@ fn start_one(
|
||||
agent.name
|
||||
));
|
||||
}
|
||||
app.emit(
|
||||
&Event::now(EventKind::Start)
|
||||
.with_agent(agent.name.clone())
|
||||
.with_pid(pid)
|
||||
.with_session(crate::repl::session_id())
|
||||
.with_cwd(cwd_string())
|
||||
.with_args(exec.args.clone())
|
||||
.with_env_keys(events::env_keys(&exec.env)),
|
||||
);
|
||||
let log = process::agent_log_path(app, &agent.name);
|
||||
app.log.success(&format!(
|
||||
"{} started (pid {pid}); log: {}",
|
||||
@@ -70,6 +80,7 @@ fn start_one(
|
||||
));
|
||||
return Ok(0);
|
||||
}
|
||||
let started = std::time::Instant::now();
|
||||
let (prog, prefix) = crate::runner::resolve_program(&exec.program);
|
||||
let mut full_args = prefix;
|
||||
full_args.extend(exec.args.iter().cloned());
|
||||
@@ -78,7 +89,17 @@ fn start_one(
|
||||
.envs(&exec.env)
|
||||
.status()
|
||||
.with_context(|| format!("failed to run {}", exec.program))?;
|
||||
Ok(status.code().unwrap_or(1))
|
||||
let code = status.code().unwrap_or(1);
|
||||
app.emit(
|
||||
&Event::now(EventKind::Run)
|
||||
.with_agent(agent.name.clone())
|
||||
.with_cwd(cwd_string())
|
||||
.with_args(exec.args.clone())
|
||||
.with_env_keys(events::env_keys(&exec.env))
|
||||
.with_exit_code(code)
|
||||
.with_duration(started.elapsed().as_secs()),
|
||||
);
|
||||
Ok(code)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,11 +144,27 @@ fn stop_one(app: &App, agent: &AgentDef, force: bool, timeout: u64) -> Result<i3
|
||||
"stale PID {pid} for '{}' (process no longer running); cleaning up",
|
||||
agent.name
|
||||
));
|
||||
app.emit(
|
||||
&Event::now(EventKind::Stop)
|
||||
.with_agent(agent.name.clone())
|
||||
.with_pid(pid)
|
||||
.with_reason("stale"),
|
||||
);
|
||||
app.state.update_pid(&agent.name, None, None)?;
|
||||
return Ok(0);
|
||||
}
|
||||
app.log.info(&format!("stopping '{}' (pid {pid})", agent.name));
|
||||
let stopped = process::stop_pid(pid, force, timeout);
|
||||
let duration = seconds_since(entry.started_at.as_deref());
|
||||
let mut ev = Event::now(EventKind::Stop)
|
||||
.with_agent(agent.name.clone())
|
||||
.with_pid(pid)
|
||||
.with_reason(if force { "force" } else { "signal" })
|
||||
.with_exit_code(if stopped { 0 } else { 1 });
|
||||
if let Some(d) = duration {
|
||||
ev = ev.with_duration(d);
|
||||
}
|
||||
app.emit(&ev);
|
||||
app.state.update_pid(&agent.name, None, None)?;
|
||||
if stopped {
|
||||
app.log.success(&format!("{} stopped", agent.title()));
|
||||
@@ -175,6 +212,7 @@ pub fn run(app: &App, target: &str, extra: &[OsString]) -> Result<i32> {
|
||||
));
|
||||
return Ok(0);
|
||||
}
|
||||
let started = std::time::Instant::now();
|
||||
let (prog, prefix) = crate::runner::resolve_program(&exec.program);
|
||||
let mut full_args = prefix;
|
||||
full_args.extend(exec.args.iter().cloned());
|
||||
@@ -183,5 +221,30 @@ pub fn run(app: &App, target: &str, extra: &[OsString]) -> Result<i32> {
|
||||
.envs(&exec.env)
|
||||
.status()
|
||||
.with_context(|| format!("failed to run {}", exec.program))?;
|
||||
Ok(status.code().unwrap_or(1))
|
||||
let code = status.code().unwrap_or(1);
|
||||
app.emit(
|
||||
&Event::now(EventKind::Run)
|
||||
.with_agent(agent.name.clone())
|
||||
.with_cwd(cwd_string())
|
||||
.with_args(exec.args.clone())
|
||||
.with_env_keys(events::env_keys(&exec.env))
|
||||
.with_exit_code(code)
|
||||
.with_duration(started.elapsed().as_secs()),
|
||||
);
|
||||
Ok(code)
|
||||
}
|
||||
|
||||
/// Current directory as a string (None when unavailable).
|
||||
fn cwd_string() -> Option<String> {
|
||||
std::env::current_dir().ok().map(|p| p.display().to_string())
|
||||
}
|
||||
|
||||
/// Seconds elapsed since an RFC 3339 timestamp (None when unparsable).
|
||||
fn seconds_since(ts: Option<&str>) -> Option<u64> {
|
||||
let t = chrono::DateTime::parse_from_rfc3339(ts?).ok()?;
|
||||
let now = chrono::Utc::now();
|
||||
let secs = now
|
||||
.signed_duration_since(t.with_timezone(&chrono::Utc))
|
||||
.num_seconds();
|
||||
Some(secs.max(0) as u64)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user