Skip to main content

dig_logging/
lib.rs

1//! # dig-logging
2//!
3//! The shared logging + log-collection building block for the DIG service binaries (`dig-node`,
4//! `dig-dns`, `dig-updater`; later `dig-relay`, `digstore`). It is the ONE place those binaries get
5//! their logging from, so the sink layout, directory convention, JSONL schema, rotation policy,
6//! level control, correlation ids, redaction rules, and `logs` CLI verbs are byte-identical across
7//! every binary. `SPEC.md` is the normative contract.
8//!
9//! It is a thin composition over [`tracing`], [`tracing_subscriber`], and [`tracing_appender`] — it
10//! builds ON `tracing`, it does not replace it.
11//!
12//! ## Quick start
13//!
14//! ```no_run
15//! let _guard = dig_logging::init(dig_logging::Service {
16//!     name: "dig-node",
17//!     version: env!("CARGO_PKG_VERSION"),
18//!     run_context: dig_logging::RunContext::Service,
19//! })?;
20//! tracing::info!(peer = "203.0.113.7", "serving");
21//! # Ok::<(), dig_logging::Error>(())
22//! ```
23//!
24//! `init` installs a dual sink — a structured JSONL file (rolling daily, byte-capped, non-blocking
25//! and lossy under backpressure) plus compact human text on `stderr` — behind one reloadable level
26//! filter, and stamps a per-run `run_id` (+ `op_id`/`parent_op_id` correlation). Hold the returned
27//! [`LogGuard`] for the process lifetime.
28//!
29//! If the log directory cannot be opened, `init` does NOT fail — it installs the `stderr` sink
30//! alone, warns there naming the path, and reports the condition via [`LogGuard::file_error`], so a
31//! filesystem problem never leaves a binary with no logging at all.
32//!
33//! ## Collection
34//!
35//! Consumers mount the reusable [`logs`] verbs (`path`/`tail`/`level`/`bundle`) and the [`redact`]
36//! engine gives a `logs bundle` a safe, secret-scrubbed zip for a bug report.
37
38#![forbid(unsafe_code)]
39#![warn(missing_docs)]
40
41mod bundle;
42mod correlation;
43mod dirs;
44mod error;
45mod filter;
46mod init;
47mod janitor;
48mod layer;
49mod schema;
50mod writer;
51
52pub mod logs;
53pub mod redact;
54
55pub use error::{Error, Result};
56pub use init::{init, LogGuard};
57
58// The pure building blocks worth exposing for consumers + conformance tests (SPEC §9).
59pub use correlation::{new_run_id, parent_op_id, ENV_DIG_OP_ID, OP_ID_FIELD};
60pub use dirs::{
61    log_dir, resolve_log_dir, resolve_log_dir_detailed, windows_operator_read_args, LogDirSource,
62    ResolvedLogDir, ENV_LOG_DIR,
63};
64pub use filter::{resolve_filter, DEFAULT_DIRECTIVE, ENV_DIG_LOG, ENV_RUST_LOG};
65pub use janitor::{ENV_MAX_BYTES, ENV_RETENTION_DAYS};
66
67/// A binary's identity, passed to [`init`] and the [`logs`] verbs.
68#[derive(Debug, Clone, Copy)]
69pub struct Service {
70    /// The service name — one of `dig-node`, `dig-dns`, `dig-updater`, … . Names the log subdir.
71    pub name: &'static str,
72    /// The binary's semver, stamped on every record (typically `env!("CARGO_PKG_VERSION")`).
73    pub version: &'static str,
74    /// Whether this is an OS-service run or an interactive CLI run.
75    pub run_context: RunContext,
76}
77
78/// How the binary is running — stamped as the `run_context` field (SPEC §2).
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub enum RunContext {
81    /// An OS-service / daemon run (Windows service, systemd, launchd).
82    Service,
83    /// An interactive or CLI invocation.
84    Cli,
85}
86
87impl RunContext {
88    /// The wire string for the `run_context` field (SPEC §2).
89    pub fn as_str(self) -> &'static str {
90        match self {
91            RunContext::Service => "service",
92            RunContext::Cli => "cli",
93        }
94    }
95}