feat: report daemon uptime in status

This commit is contained in:
Eric Wendland 2026-07-05 18:14:52 +02:00
commit 2d314e85bf
7 changed files with 50 additions and 8 deletions

View file

@ -26,6 +26,9 @@ The daemon owns local identity, the Iroh endpoint, trust state, resource
registry, module router, local metadata store, and synchronized data structures.
Most non-daemon commands talk to the daemon through a local Unix socket at
`$GETH_HOME/run/geth.sock`.
`geth status` and `geth status --json` report daemon uptime, store schema and
durability settings, Iroh endpoint/relay/discovery state, and native backend
health for automation.
`geth init --admin-key <public-key> --signing-key <private-key> --node-name
<name>` records an owner/admin keychain, the local user/device/node binding, and

View file

@ -2210,6 +2210,7 @@ fn print_response(response: ControlResponse, json: bool) -> Result<()> {
println!("socket: {}", status.socket.display());
println!("agent: {}", status.agent_id);
println!("node: {}", status.node_id);
println!("uptime seconds: {}", status.daemon_uptime_seconds);
println!(
"store schema: {}/{}",
status.store_schema_version, status.store_current_schema_version

View file

@ -1156,6 +1156,8 @@ pub struct StatusResponse {
pub socket: PathBuf,
pub agent_id: String,
pub node_id: String,
pub daemon_started_at_ms: i64,
pub daemon_uptime_seconds: u64,
pub store_schema_version: i64,
pub store_current_schema_version: i64,
pub store_journal_mode: String,

View file

@ -68,7 +68,7 @@ use runtime::{
use std::collections::{BTreeMap, BTreeSet};
use std::path::{Component, Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use sync::{
KvDocsState, load_live_sync_cursor, store_live_sync_cursor, sync_now, sync_status_local,
};
@ -185,6 +185,7 @@ pub struct LocalNode {
pub paths: GethPaths,
pub agent_id: String,
pub node_id: String,
pub daemon_started_at_ms: i64,
pub iroh_status: EndpointStatus,
iroh_endpoint: Arc<Mutex<Option<GethIrohEndpoint>>>,
iroh_blob_store: Arc<Mutex<Option<iroh_blobs::store::fs::FsStore>>>,
@ -262,6 +263,7 @@ pub fn init_node(paths: &GethPaths) -> Result<LocalNode, NodeError> {
paths: paths.clone(),
agent_id,
node_id,
daemon_started_at_ms: current_unix_ms(),
iroh_status: EndpointStatus::scaffolded(),
iroh_endpoint: Arc::new(Mutex::new(None)),
iroh_blob_store: Arc::new(Mutex::new(None)),
@ -275,6 +277,14 @@ pub fn init_node(paths: &GethPaths) -> Result<LocalNode, NodeError> {
})
}
fn current_unix_ms() -> i64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis()
.min(i64::MAX as u128) as i64
}
pub fn init_owned_node(
paths: &GethPaths,
options: InitOwnerOptions,
@ -5880,6 +5890,11 @@ pub fn handle_request(
socket: node.paths.socket_path(),
agent_id: node.agent_id.clone(),
node_id: node.node_id.clone(),
daemon_started_at_ms: node.daemon_started_at_ms,
daemon_uptime_seconds: current_unix_ms()
.saturating_sub(node.daemon_started_at_ms)
.max(0) as u64
/ 1000,
store_schema_version,
store_current_schema_version: geth_store::CURRENT_SCHEMA_VERSION,
store_journal_mode,

View file

@ -257,6 +257,7 @@ fn geth_status_against_running_daemon() {
wait_for_socket(&home.path().join("run/geth.sock"));
let output = run_geth(home.path(), &["status"]);
let json_output = run_geth(home.path(), &["--json", "status"]);
let _ = daemon.kill();
let _ = daemon.wait();
@ -268,6 +269,7 @@ fn geth_status_against_running_daemon() {
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("geth daemon: running"));
assert!(stdout.contains("agent:"));
assert!(stdout.contains("uptime seconds:"));
assert!(stdout.contains("store schema:"));
assert!(stdout.contains("store journal: wal"));
assert!(stdout.contains("store synchronous: normal"));
@ -284,6 +286,25 @@ fn geth_status_against_running_daemon() {
assert!(stdout.contains(
"native backend pubsub: shared-iroh-endpoint-ready target iroh-gossip 0.101.0 (wired)"
));
let status_json = command_json(&json_output);
assert_eq!(status_json["type"], "status");
assert!(
status_json["daemon_started_at_ms"]
.as_i64()
.expect("daemon started at ms")
> 0
);
assert!(
status_json["daemon_uptime_seconds"]
.as_u64()
.expect("daemon uptime seconds")
< 60
);
assert_eq!(status_json["store_journal_mode"], "wal");
assert_eq!(status_json["store_synchronous"], "normal");
assert_eq!(status_json["store_status"], "ok");
assert!(status_json["native_backends"].is_array());
}
#[test]

View file

@ -14,8 +14,8 @@ SQLite transaction where SQLite supports it. File-backed stores deliberately use
SQLite WAL mode with `synchronous=NORMAL`: committed transactions remain
consistent after process crashes, while the most recent transaction can be lost
on an OS crash or power loss before the WAL is durable. `geth status` reports
the observed schema version, journal mode, synchronous mode, and whether those
values match the expected store policy.
daemon uptime, the observed schema version, journal mode, synchronous mode, and
whether those values match the expected store policy.
Service management is also exposed through the single binary. `geth daemon
service ...` installs and controls a user-level service definition for the local

View file

@ -275,12 +275,12 @@ Goal: make production failures diagnosable from the CLI and logs.
stream, cursor, and stable error code where applicable.
- `[ ]` Sensitive bearer tokens and private material are not logged.
- `[ ]` Expand health status.
- `[x]` Expand health status.
Acceptance criteria:
- `[ ]` `geth status --json` reports daemon uptime.
- `[ ]` Store schema version is visible.
- `[ ]` Native backend health is visible.
- `[ ]` Iroh relay/local-discovery state is visible without exposing
- `[x]` `geth status --json` reports daemon uptime.
- `[x]` Store schema version is visible.
- `[x]` Native backend health is visible.
- `[x]` Iroh relay/local-discovery state is visible without exposing
unrelated config secrets.
- `[ ]` Add `geth doctor`.