diff --git a/app/igneum-app/src/engine.rs b/app/igneum-app/src/engine.rs index 3b6f1d90..e0144038 100644 --- a/app/igneum-app/src/engine.rs +++ b/app/igneum-app/src/engine.rs @@ -73,11 +73,13 @@ pub struct Shared { cmd_tx: Mutex>, pub started: Instant, engine_log: Mutex>, + /// the app log's path: the one the uploader sends (main.rs names it; the engine must not guess the stamp) + pub log_path: PathBuf, port: std::sync::atomic::AtomicU16, } impl Shared { - pub fn new(token: String, runtime: Runtime, packaged: Packaged, settings: Settings, cmd_tx: Sender, engine_log: Option) -> Shared { + pub fn new(token: String, runtime: Runtime, packaged: Packaged, settings: Settings, cmd_tx: Sender, engine_log: Option, log_path: PathBuf) -> Shared { let settings_path = runtime.app_dir.join("settings.json"); let wallet_path = runtime.app_dir.join("wallet.json"); let mut st = State { version: VERSION.into(), ..Default::default() }; @@ -113,10 +115,19 @@ impl Shared { cmd_tx: Mutex::new(cmd_tx), started: Instant::now(), engine_log: Mutex::new(engine_log), + log_path, port: std::sync::atomic::AtomicU16::new(0), } } + /// The first line of every upload, so the console's Machines tab parses it without guessing: + /// IGNEUM-APP version= machine= platform= node=. Logged at every engine start too, + /// so the restart after an OTA apply carries it again. + pub fn upload_header(&self) -> String { + let node = self.state.lock().unwrap().node.version.clone(); + format!("IGNEUM-APP version={} machine={} platform={} node={}", VERSION, self.runtime.id8(), crate::manifest::platform_name(), if node.is_empty() { "unknown".to_string() } else { node.replace(' ', "_") }) + } + pub fn set_port(&self, p: u16) { self.port.store(p, std::sync::atomic::Ordering::Relaxed); } @@ -504,6 +515,7 @@ impl Engine { )); let v = crate::detect::node_version(&self.bins.node); self.st().node.version = v.clone(); + self.shared.log(&self.shared.upload_header()); // the prover service (proving v0): its own thread, idle until the setting is on crate::prover::start(self.shared.clone(), self.bins.dir.clone()); self.shared.log(&format!("node binary: {} ({v})", self.bins.node.display())); @@ -2106,7 +2118,7 @@ impl Engine { } } let mut files: Vec<(String, PathBuf)> = Vec::new(); - files.push((self.label_base.clone(), self.shared.runtime.log_dir.join(format!("app-{}.log", self.stamp)))); + files.push((self.label_base.clone(), self.shared.log_path.clone())); if let Some(n) = &self.node_log { files.push((format!("nodelog-{}", self.label_base), n.clone())); } @@ -2117,9 +2129,10 @@ impl Engine { } // machine = "-": readable in tools/logs.mjs and distinct for cloned PCs let (url, key, machine, run_id) = (p.log_intake_url.clone(), p.log_intake_key.clone(), format!("{}-{}", self.shared.runtime.host, self.shared.runtime.id8()), format!("{}-{}", self.label_base, self.stamp)); + let header = self.shared.upload_header(); let t = std::thread::spawn(move || { for (label, path) in files { - crate::update::upload_log(&url, &key, &label, &machine, &run_id, &path); + crate::update::upload_log(&url, &key, &label, &machine, &run_id, &path, &header); } }); if wait { diff --git a/app/igneum-app/src/jobrun.rs b/app/igneum-app/src/jobrun.rs index deb20c02..d4417fbf 100644 --- a/app/igneum-app/src/jobrun.rs +++ b/app/igneum-app/src/jobrun.rs @@ -533,7 +533,7 @@ fn report(shared: &Arc, job: &Job, sink: &Sink, status: &str, exit: i64, return false; } let machine = format!("{}-{}", shared.runtime.host, shared.runtime.id8()); - crate::update::upload_log(&p.log_intake_url, &p.log_intake_key, &format!("job-{}", job.kind), &machine, &job.run_id(&shared.runtime.machine_id), &path) + crate::update::upload_log(&p.log_intake_url, &p.log_intake_key, &format!("job-{}", job.kind), &machine, &job.run_id(&shared.runtime.machine_id), &path, &shared.upload_header()) } /// One file to the intake under the job's run id, labelled file-. The intake keeps the last 256 KB. @@ -545,7 +545,7 @@ fn upload_file(shared: &Arc, job: &Job, path: &Path, label_prefix: &str) let name = path.file_name().map(|n| n.to_string_lossy().into_owned()).unwrap_or_default(); let label: String = format!("{label_prefix}-{name}").chars().take(80).collect(); let machine = format!("{}-{}", shared.runtime.host, shared.runtime.id8()); - crate::update::upload_log(&p.log_intake_url, &p.log_intake_key, &label, &machine, &job.run_id(&shared.runtime.machine_id), path) + crate::update::upload_log(&p.log_intake_url, &p.log_intake_key, &label, &machine, &job.run_id(&shared.runtime.machine_id), path, &shared.upload_header()) } // ---- fetching the jobs file and probing requirements ----------------------------------------------------------------- diff --git a/app/igneum-app/src/main.rs b/app/igneum-app/src/main.rs index 583f5733..48c74998 100644 --- a/app/igneum-app/src/main.rs +++ b/app/igneum-app/src/main.rs @@ -87,7 +87,7 @@ fn main() { let stamp_file = runtime.log_dir.join(format!("app-{}.log", stamp_now())); let engine_log = std::fs::File::create(&stamp_file).ok(); let (tx, rx) = channel(); - let shared = Arc::new(engine::Shared::new(token.clone(), runtime, packaged, settings, tx, engine_log)); + let shared = Arc::new(engine::Shared::new(token.clone(), runtime, packaged, settings, tx, engine_log, stamp_file.clone())); let port = match server::start(shared.clone()) { Ok(p) => p, Err(e) => { diff --git a/app/igneum-app/src/update.rs b/app/igneum-app/src/update.rs index 29165632..16fdb0f5 100644 --- a/app/igneum-app/src/update.rs +++ b/app/igneum-app/src/update.rs @@ -64,7 +64,7 @@ mod tests { } /// Posts the last 256 KB of a log file as {label, machine, run_id, lines}, as site/api/log.mjs expects. -pub fn upload_log(url: &str, key: &str, label: &str, machine: &str, run_id: &str, path: &std::path::Path) -> bool { +pub fn upload_log(url: &str, key: &str, label: &str, machine: &str, run_id: &str, path: &std::path::Path, header: &str) -> bool { if url.is_empty() || key.is_empty() { return false; } @@ -76,7 +76,9 @@ pub fn upload_log(url: &str, key: &str, label: &str, machine: &str, run_id: &str data = data.split_off(data.len() - 262_144); } // second guard (R4.3.8): no line that carries a dashboard token leaves the machine - let text: String = String::from_utf8_lossy(&data).lines().filter(|l| !crate::platform::carries_token(l)).map(|l| crate::platform::redact(l)).collect::>().join("\n"); + let tail: String = String::from_utf8_lossy(&data).lines().filter(|l| !crate::platform::carries_token(l)).map(|l| crate::platform::redact(l)).collect::>().join("\n"); + // the first line of every upload names the app, the machine and the node (the console parses it) + let text = format!("{header}\n{tail}"); let body = serde_json::json!({ "label": label, "machine": machine, "run_id": run_id, "lines": text }); let tmp = std::env::temp_dir().join(format!("igneum-upload-{}-{}.json", std::process::id(), label)); if std::fs::write(&tmp, body.to_string()).is_err() {