Skip to content

feat(logger): port elastos-logger crate from PR #15 - #25

Open
irzhywau wants to merge 14 commits into
review/collaboration-candidatefrom
feat/elastos-logger
Open

irzhywau wants to merge 14 commits into
review/collaboration-candidatefrom
feat/elastos-logger

Conversation

@irzhywau

@irzhywau irzhywau commented Aug 21, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Ports the elastos-logger crate from the tip of PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15 (commit 27d85c6) as its own PR track, per review feedback that the logger is separate work from the protected-content extraction
  • elastos/crates/elastos-logger: Level (case-insensitive parse, aliases, env fallback), LogRecord + format_line(), LogSink trait (Send+Sync, non-panicking, drop-on-fail) with StderrSink/StdoutSink/FileSink/VecSink, Logger with OnceLock global and safe pre-init stderr fallback, resolve_level precedence (CLI > env chain > default), fp() SHA-256 privacy fingerprint, lazy log_trace!..log_critical! macros, and per-record component override (component: / emit_as)
  • Gateway adoption: elastos-server bootstraps the global logger with ELASTOS_LOG as the env root, all tracing call sites converted, daemon eprintln! diagnostics routed through the logger, tracing subscriber and dependencies removed; privacy fix so full VM provider payloads are no longer logged
  • Library-crate adoption (elastos/ workspace): elastos-crosvm, elastos-guest, elastos-identity, elastos-namespace, elastos-runtime, elastos-storage, elastos-tls, elastos-vz converted from tracing
  • Components follow a dotted vocabulary (gateway.*, cmd.*, vm.*, host.*)
  • AI-facing JsonRingSink: bounded per-component JSON ring files (enabled via ELASTOS_LOG_JSON_DIR), observe-only and secret-free by construction

Out of scope here (follow-up slices): provider capsule adoption, JS/browser mirror (pending product decision in the PR #15 thread), and any wiring inside the protected-content extraction branches.

Test plan

  • cd elastos && cargo test -p elastos-logger — 20 tests + doctest pass
  • cargo test -p elastos-server — 1419 pass, 2 pre-existing env-dependent room::direct failures
  • cargo clippy --workspace --all-targets zero warnings; cargo fmt --all -- --check clean

Port the elastos-logger crate authored in 27d85c6
(origin/feat/dkms-esp-port) onto the collaboration base as its own
track: Level (Trace<Info<Warn<Error<Critical, "debug" alias), LogRecord
+ format_line, the LogSink writer seam (Stderr/Stdout/File/Vec sinks),
the process-global Logger with pre-init stderr fallback, resolve_level
(CLI > env chain > default), the fp() privacy fingerprint, and the lazy
log_* macros. Registered as a workspace member in elastos/Cargo.toml.

Crate files are ported verbatim; the source commit's PR #15 wirings
(dkms-authority, dkms-carrier-node, providers) do not transfer to this
base and are deliberately out of scope for this slice. The plan doc the
source commit referenced (docs/superpowers/plans/2026-08-17-elastos-logger.md)
does not exist in any tree; the reference is dropped — it only ever
lived in the commit message, not in the ported files.

Verification (from elastos/):
- cargo test -p elastos-logger: 15 passed, 0 failed
- cargo clippy -p elastos-logger --all-targets -- -D warnings: clean
- cargo fmt --all -- --check: clean
- git diff --check: clean
@irzhywau irzhywau self-assigned this Aug 21, 2026
@irzhywau irzhywau added enhancement New feature or request good first issue Good for newcomers labels Aug 21, 2026
… macro arm)

The Logger holds one process-wide component; a multi-surface binary like
elastos-server needs per-surface names on a single global. Add
Logger::emit_as / global emit_as stamping a caller-supplied component,
factor the pre-init stderr fallback, and teach log_at! (and thus all
log_*! macros) an optional leading 'component: <expr>' argument.

Verification: (cd elastos && cargo test -p elastos-logger) — 16 pass;
clippy + fmt clean.
Install the process-global logger at startup: threshold resolves
CLI --log-level (new global clap arg) > ELASTOS_LOG > Info; sink is a
SuppressableStderrSink honoring the same interactive-TUI suppression
flag as the existing tracing ConditionalStderr. The tracing subscriber
stays in place until all call sites are converted (follow-up slices).

Verification: (cd elastos && cargo test -p elastos-server) — 1419 pass,
2 pre-existing env-dependent failures in room::direct (fail identically
on the parent commit); fmt + clippy clean.
Convert all ~305 tracing::error!/warn!/info!/debug!/trace! call sites
across elastos-server to log_error!/log_warn!/log_info!/log_trace!
(debug maps to Trace — the logger has no Debug level), each stamped with
a flat per-surface component via log_*!(component: LOG_COMPONENT, ...):
gw, auth, wallet, browser, home, effects, infra, bridge, carrier,
collab, runtime, vm, content, supervisor, serve, run, update, ipfs,
binaries, operator; main.rs logs under the default 'elastos' component.
Structured tracing fields are folded into the format strings with
message text preserved; sensitive values at INFO/TRACE (session token,
node/peer DIDs, principal id, browser exit-stream target) are
fingerprinted with fp().

The tracing_subscriber init in main.rs stays until the remaining
tracing-emitting crates are converted (later slices), so their events
are not silently dropped in the interim; tracing deps drop at the end
of the rollout.

Verification: (cd elastos && cargo test -p elastos-server) — 1419 pass,
2 pre-existing env-dependent room::direct failures (identical on parent
commits); clippy --all-targets and fmt clean; zero tracing:: call sites
remain outside the subscriber init.
The vm bridge logged the entire serialized resource request (including
write content) at INFO on connection reuse, and the full init config
JSON at INFO on connect. Payload content can carry user file data and
manifest-provided config values, which violates the secret-free logging
rule. Demote the reuse line to TRACE with op name + fp() of the payload
for correlation, and log the init config as fp() only.

Verification: (cd elastos && cargo clippy -p elastos-server && cargo
fmt --all -- --check) clean; behavior covered by existing vm bridge
tests in the suite run for the parent commit.
…ogger

Triage of the ~77 eprintln! sites in elastos-server: bracketed
daemon-style diagnostics convert to the logger, interactive CLI output
stays on stderr untouched.

Converted: gateway_cmd (14 sites -> gw), serve_cmd (6 -> serve),
supervisor (8 -> supervisor), run_cmd (4 -> run), chat cleanup warnings
(2 -> chat), share head-publish warnings (3 -> share), host_lock
supersession fatal (1 -> lock, log_critical). The '[prefix]' tags drop
from messages since the component now carries that context.

Kept as eprintln/println (user-facing): interactive chat UI output,
runtime_control notices (own runtime_notices_enabled() gate), channel
revocation warnings and shutdown notice in main.rs, CLI progress
formatting in setup/update/publish/node_cmd, share signing-key display,
cfg(test) smoke-skip notices, and all println! command output.

Verification: (cd elastos && cargo test -p elastos-server) — 1419 pass,
2 pre-existing env-dependent room::direct failures; clippy
--all-targets and fmt clean; git diff --check clean.
Convert all remaining tracing call sites in the workspace's library
crates to log_*! macros with flat component names, and drop each
crate's tracing dependency: elastos-runtime (54 sites -> runtime),
elastos-crosvm (28 -> crosvm), elastos-vz (8 + supervisor bin
eprintln -> vz), elastos-storage (22 -> storage), elastos-tls
(14 -> tls), elastos-namespace (7 -> ns), elastos-identity
(1 -> identity), elastos-guest (1 diagnostic -> guest, cfg-gated so
WASI capsule builds stay minimal), elastos-compute (unused tracing dep
dropped). Session tokens formerly logged as 8-char prefixes are now
fp() fingerprints (elastos-runtime session registry, crosvm provider).
The vz concurrent_launch test's tracing_subscriber capture Layer is
replaced by an elastos-logger VecSink capture keyed on the vm_console
message prefix. elastos-guest's exported log!/log_error! guest-SDK
macros and the vz supervisor's VZ_MEDIA_DIAGNOSTIC_SCHEMA JSON emitter
are deliberately untouched (public API / machine-readable contract).

Verification: (cd elastos && cargo test -p <each converted crate>) all
pass incl. elastos-vz concurrent_launch; cargo check/clippy
--workspace --all-targets zero warnings; fmt clean; grep shows zero
tracing references outside elastos-server's subscriber (removed next).
All tracing call sites across the workspace are converted, so remove
the tracing_subscriber init from main.rs along with the
ConditionalStderr MakeWriter it fed, and drop the tracing +
tracing-subscriber dependencies from elastos-server. The
SuppressableStderrSink and set_logging_suppressed() stay — the
interactive-TUI suppression flag now gates only the elastos-logger
sink. Remaining 'tracing' entries in Cargo.lock are transitive
(axum/tower internals), not direct dependencies.

Verification: (cd elastos && cargo test -p elastos-server) — 1419 pass,
2 pre-existing env-dependent room::direct failures; cargo clippy
--workspace --all-targets zero warnings; fmt clean.
Rename the elastos binary's surface components into hierarchy buckets:
gateway.{http,auth,browser,home,effects,content,bridge,infra,capsule},
cmd.{chat,ipfs,run,serve,share,update}, vm.{crosvm,vz,provider,
supervisor}, host.{binaries,lock,operator}. carrier, collab, and the
library crates (runtime, storage, tls, ns, identity, guest) stay
top-level components.

Verification: (cd elastos && cargo check --workspace --all-targets)
clean; fmt clean; elastos-vz + elastos-logger tests pass (component
strings do not participate in any test assertion except the vm_console
message prefix, which is unchanged).
One more impl LogSink, no Logger change (as the crate's sink NOTE
anticipated): JsonRingSink appends one JSON object per record — ts,
level, component, target, msg — to <component>.jsonl under a configured
directory, rotating to .jsonl.1 at 5MB so each component holds at most
~10MB across two generations. Component names are sanitized to
[A-Za-z0-9._-] with leading dots stripped, so hostile names cannot
escape the directory. Messages are the exact rendered text the stderr
sink sees (already fp()'d) — the sink adds no data of its own.

The elastos binary enables it observe-only via ELASTOS_LOG_JSON_DIR;
an unusable directory logs a WARN and falls back to stderr-only. Adds
serde_json to elastos-logger and a crate README documenting levels,
components, the fp() rule, and the JSON format contract for consumers.

Verification: (cd elastos && cargo test -p elastos-logger) — 20 pass
(4 new: shape, per-component split, rotation bound, hostile-name
sanitization); cargo test -p elastos-server — 1419 pass, 2 pre-existing
env-dependent room::direct failures; clippy --workspace --all-targets
zero warnings; fmt clean.
@irzhywau
irzhywau force-pushed the feat/elastos-logger branch from 8d05169 to 2e843e1 Compare August 25, 2026 07:53
…! macros

Add elastos_logger::component!("<name>") and component_mod!(vis name,
"<name>"): they generate per-component trace!/info!/warn!/error!/
critical! macros so call sites carry no component at all. Each crate
declares its logger once in src/logger.rs — library crates via
component! (files then 'use crate::logger;'), the elastos binary via
one component_mod! per surface (files 'use
crate::logger::gateway_auth as logger;') — and logs with
logger::warn!("...{}", x). The generated macros delegate to
log_*!(component: ...), keeping lazy formatting and the call site's
module_path!() target; the log_*! forms remain for the process-default
component (main.rs) and dynamic components.

Macro-hygiene notes baked into the design: the generated macros use
unique internal names re-exported 'as warn' etc. (a macro literally
named warn cannot be use'd — ambiguous with the built-in #[warn]
attribute), the re-export is pub(crate) (textual macros cannot be
re-exported across crates, E0364), and each target declares its own
logger module (main.rs 'mod logger;' reuses the same source file; the
vz supervisor bin declares an inline one).

Migrated all 59 per-file const LOG_COMPONENT sites plus main.rs; the
consts and per-file elastos_logger macro imports are gone (only fp
imports remain where messages fingerprint values). README documents the
new shape.

Verification: (cd elastos && cargo test -p elastos-logger) — 20 pass +
doctest (generated macros through the global, component! and
component_mod! forms); all converted library crate tests pass; cargo
test -p elastos-server — 1419 pass, 2 pre-existing env-dependent
room::direct failures; clippy --workspace --all-targets zero warnings;
fmt clean.
@irzhywau

Copy link
Copy Markdown
Collaborator Author

Status update (2026-08-25) — where this track stands.

Landed (pushed)

Crate (slice 1):

  • fb6a3022 port of elastos-logger from PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15's tip 27d85c6f — Level, LogRecord,
    LogSink (stderr/stdout/file/test), OnceLock global with safe pre-init fallback,
    resolve_level (CLI > env chain > default), fp() fingerprint, lazy log_*! macros
  • 02214e38 per-record component override (log_*!(component: …) / emit_as)

Gateway adoption (slice 2):

  • 2c8152d9 global bootstrap in elastos-server with ELASTOS_LOG as the env root
  • 5232911b tracing call sites converted to elastos-logger
  • 54220f62 privacy fix: full VM provider payloads no longer logged
  • 20ad4fee daemon eprintln! diagnostics routed through the logger
  • f737ca2b tracing subscriber and dependencies dropped

Library crates (slice 3, elastos/ workspace):

  • fe74edeb converted elastos-crosvm, elastos-guest, elastos-identity,
    elastos-namespace, elastos-runtime, elastos-storage, elastos-tls, elastos-vz

Component naming + AI sink:

  • 92714e4e components regrouped into dotted buckets
    (gateway.http/auth/browser/home/effects/infra/bridge/content/capsule,
    cmd.*, vm.provider/supervisor/crosvm/vz, host.*)
  • 2e843e16 AI-facing JsonRingSink: bounded per-component JSON ring files
    (level, component, target, ts, message), enabled via ELASTOS_LOG_JSON_DIR,
    observe-only and secret-free by construction (fp() at call sites)

Local, pending push

  • 3fe4fd4d per-component logger modules generated by component! /
    component_mod! macros: each crate/surface declares its dotted component once in
    src/logger.rs, call sites become bare logger::warn!(…); all 59 per-file
    LOG_COMPONENT consts migrated. This closes the component vocabulary at one
    declaration point per surface — which the per-component ring files key on.

Verification state

  • cargo test -p elastos-logger — 20 tests + doctest green
  • cargo test -p elastos-server — 1419 pass; 2 pre-existing env-dependent
    room::direct failures (unrelated to this track)
  • cargo clippy --workspace --all-targets — zero warnings; cargo fmt --check clean

Remaining scope (separate slices)

  • Provider capsule adoption (chain-provider, wallet-provider, key-provider, …) —
    no capsule references the logger yet; each capsule is its own workspace, so this lands
    as mechanical per-capsule conversions
  • JS/browser capsule mirror + gateway ingestion — parked pending the product decision
    raised in the PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15 thread; browser capsules stay untouched until then
  • Logger adoption inside the protected-content extraction stays out of scope here, per
    the review decision that the logger is separate work: those slices adopt the crate only
    after this PR lands

Add the logging contract to the places developers and agents actually
look: AGENTS.md gains a Logging Discipline section (logger modules at
call sites, component buckets, println reserved for CLI UX, secret-free
TRACE via fp()); DEBUG.md documents raising verbosity (--log-level,
ELASTOS_LOG), the line format, component grepping, and the
ELASTOS_LOG_JSON_DIR insight stream; docs/ARCHITECTURE.md gains a
Logging and observability section; docs/COMMAND_MATRIX.md records
--log-level as a global flag (rule 9); elastos/README.md and the
docs index link the crate README.

scripts/home-smoke.sh switches its quiet-run env from the now-inert
RUST_LOG to ELASTOS_LOG. The smoke's first check fails identically
before and after this change on this branch (the Home header renders
'Home CLI / Home', not the expected 'ElastOS Home') — pre-existing
drift, left untouched like the room::direct test failures.

Verification: git diff --check clean; docs-only plus one env var.
elastos-guest now (target-gated) depends on elastos-logger, so
home-cli's lockfile gains the logger's dependency entries (sha2, hex,
block-buffer, ...). Regenerated by cargo during the home-smoke run;
other capsule lockfiles will refresh the same way on their next build.

Verification: cargo build side-effect only; lockfile diff is additive
dependency entries.
…endencies

Added support for additional targets in rust-toolchain.toml. Updated Cargo.lock files across multiple capsules to include new dependencies such as 'deranged', 'elastos-logger', 'num-conv', 'powerfmt', and 'time' along with their respective transitive dependencies. This ensures compatibility with the latest changes in the project.
@irzhywau

Copy link
Copy Markdown
Collaborator Author

This PR is potentially set to be abandoned in favor to tracing library already is use on some components

@andersalm

Copy link
Copy Markdown
Contributor

@irzhywau retire this in favour of tracing, or rescope it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request good first issue Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants