Skip to content

chore(deps): adopt dig-logging 0.2.0 - #237

Draft
MichaelTaylor3d wants to merge 3 commits into
mainfrom
loop/dig-logging-0.2.0
Draft

chore(deps): adopt dig-logging 0.2.0#237
MichaelTaylor3d wants to merge 3 commits into
mainfrom
loop/dig-logging-0.2.0

Conversation

@MichaelTaylor3d

@MichaelTaylor3d MichaelTaylor3d commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

DO NOT MERGE — gate round not yet run

What

Adopts dig-logging 0.2.0 in dig-node and uses the signal it adds.

Under 0.1.4 dig_logging::init was all-or-nothing: when the file appender could not be built it
returned Err and the stderr layer was never installed either, so the process ran with no
tracing subscriber at all. On this user's machine an interactive dig-node run, on a host where
C:\ProgramData\DigNetwork\logs\dig-node belongs to the service account, was therefore completely
silent — which made a broken profile-sync subsystem read as dead rather than broken.

0.2.0 degrades to console-only logging and reports the reason via LogGuard::file_error().

  • crates/dig-node-service/Cargo.toml: dig-logging = "0.2"; Cargo.lock moves exactly one entry
    (dig-logging 0.1.4 -> 0.2.0, cargo update -p dig-logging; no other pin moved).
  • logging.rs: new file_error(), log_dir(), initialized(), and a pure health().
  • control.rs: control.status gains a logging object (initialized, dir, file_logging,
    file_error). This is the surface where the node reports its own health, so it is where a
    degraded sink is reported; no new control method, so no CLI-parity drift.
  • SPEC.md §20.1 + the control.status result row updated in the same unit of work.

The fatal branch at logging.rs:71 — kept, deliberately

The Err arm was NOT removed. Its unwritable-dir case is now dead, but the arm is still reachable
for AlreadyInitialized (a second subscriber in one process), which is a real condition in tests and
in any future embed. Deleting it would swap a warning for a silent no-op. It is retained with its
doc-comment rewritten to say exactly which conditions still reach it, and the message corrected from
"continuing without a log file" (which is now wrong — the failure costs the whole subscriber, not
the file) to "continuing without a subscriber".

Verification

crates/dig-node-service/tests/logging_degraded.rs — an integration test owning its own process
(the subscriber and the OnceLock guard are process-global, so the degraded state can be
established exactly once). It points DIG_LOG_DIR at a path whose parent is a regular file, so
create_dir_all cannot succeed on any platform — the fixture does not depend on being unprivileged,
on ACLs, or on a read-only mount, the three things that make a permission fixture pass for the wrong
reason (or, under an elevated runner, not fail at all).

It asserts both halves of the load-bearing property: LevelFilter::current() != OFF (a subscriber IS
installed, i.e. stderr logging is live) and file_error().is_some() (the node knows the file sink is
off), plus that health() reports file_logging: false.

Revert-proof: with logging::init patched to mimic 0.1.x's all-or-nothing failure, the test FAILS at
init must succeed and hold a guard even when the file sink cannot be opened. Pinning the dep back
to =0.1.4 instead fails to compile (no method named file_error), which is why the behavioural
simulation was used for the proof. Needle presence was asserted before each patch and the file
restored from git afterwards.

Unit tests cover both health() arms plus the never-initialised arm, so neither a true nor a
false constant survives.

Blast radius

gitnexus is per-worktree and was not indexed for this lane (a fresh analyze here exceeds the 10-min
stop for a change this size), so blast radius was established by ripgrep + direct read, per §2.0
bound 2:

  • dig_logging::init has exactly one caller in this repo: logging::init
    (crates/dig-node-service/src/logging.rs), itself called only from the serve entrypoints
    (entrypoint.rs:866, the unix daemon, the Windows service body).
  • No code in the repo matched Error::LogDir / Error::Appender, the two removed variants — grep
    returns nothing — so the removal breaks no caller.
  • status() is the only changed control handler; its result is additive. CONTROL_METHODS /
    OWNED_CONTROL_METHODS are untouched, and control_contract_conformance passes (5/5).

Risk: LOW. No custody, crypto, wire-format or peer-facing surface is touched.

Not watched working on a real machine

The silent-node scenario itself has only been reproduced in-process via DIG_LOG_DIR. Nobody has run
an installed dig-node on a host whose machine log dir is service-account-owned and watched it narrate
on the console; and no one has read the new logging block out of a live control.status.

Tests

cargo test -p dig-node-service: all targets green (355 lib + every integration target).
cargo fmt --all, cargo clippy -p dig-node-service --all-targets -- -D warnings: clean.

Version: workspace 0.124.1 -> 0.125.0 (minor — additive control.status field + new public
logging API).

MichaelTaylor3d and others added 3 commits August 17, 2026 13:45
An unwritable log directory no longer costs the whole subscriber: dig-logging
0.2.0 degrades to console-only logging and reports the reason via
LogGuard::file_error(). Surface that on control.status so an operator can tell a
node that is logging to disk from one that is only speaking on the console.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant