()
| 19 | |
| 20 | #[tokio::main] |
| 21 | async fn main() -> anyhow::Result<()> { |
| 22 | // Operator subcommand dispatch (L.4): handled before config load |
| 23 | // + tracing init so `nodedb regen-certs`, `nodedb rotate-ca`, |
| 24 | // `nodedb join-token` exit cleanly without spinning up the |
| 25 | // server's global allocator arenas or file locks. A first arg |
| 26 | // that doesn't match a known subcommand is treated as a config |
| 27 | // file path and falls through to the normal server bootstrap. |
| 28 | let cli_args: Vec<String> = std::env::args().skip(1).collect(); |
| 29 | match nodedb::ctl::parse_subcommand(&cli_args) { |
| 30 | Ok(Some(cmd)) => std::process::exit(nodedb::ctl::run_subcommand(cmd)), |
| 31 | Ok(None) => {} |
| 32 | Err(e) => { |
| 33 | eprintln!("error: {e}"); |
| 34 | std::process::exit(2); |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | // Resolve config file path. |
| 39 | // Priority: CLI arg (highest) > NODEDB_CONFIG env var > default. |
| 40 | let config_path: Option<PathBuf> = cli_args |
| 41 | .iter() |
| 42 | .find(|a| !a.starts_with("--")) |
| 43 | .map(PathBuf::from) |
| 44 | .or_else(|| std::env::var("NODEDB_CONFIG").ok().map(PathBuf::from)); |
| 45 | |
| 46 | // Load config first (needed for log format). |
| 47 | // Environment variable overrides are applied after tracing is initialised |
| 48 | // (see below) so that info!/warn! messages are actually emitted. |
| 49 | let mut config = match config_path { |
| 50 | Some(ref path) => ServerConfig::from_file(path)?, |
| 51 | None => ServerConfig::default(), |
| 52 | }; |
| 53 | |
| 54 | // Apply env overrides once now (before tracing) so that log_format is |
| 55 | // correct in case NODEDB_DATA_DIR / NODEDB_MEMORY_LIMIT also affect it. |
| 56 | // The overrides are re-applied silently here; the real log messages |
| 57 | // will be emitted by the second call after the subscriber is registered. |
| 58 | apply_env_overrides(&mut config); |
| 59 | |
| 60 | // Initialize tracing subscriber (format + filter from config / RUST_LOG). |
| 61 | bootstrap::tracing_init::init_tracing(&config); |
| 62 | |
| 63 | // Root span: entered for the lifetime of the process. Provides structured |
| 64 | // context fields (service name, version, host, pid, node_id) on every log |
| 65 | // event. node_id starts at 0 for single-node; cluster wiring records the |
| 66 | // real value below once the cluster handle is resolved. |
| 67 | let root_span = tracing::info_span!( |
| 68 | "service", |
| 69 | service.name = "nodedb", |
| 70 | service.version = nodedb::version::VERSION, |
| 71 | host = %nodedb::version::hostname(), |
| 72 | pid = std::process::id(), |
| 73 | node_id = 0u64, |
| 74 | ); |
| 75 | // Use enter() (borrows) rather than entered() (consumes) so that root_span |
| 76 | // remains accessible for the late record() call after cluster wiring. |
| 77 | let _root_guard = root_span.enter(); |
| 78 |
nothing calls this directly
no test coverage detected