fix(host/log): drop the wasapi crate's once-a-second DEBUG device-poll from the logs
apple / swift (push) Successful in 1m18s
apple / screenshots (push) Successful in 5m16s
ci / web (push) Successful in 58s
ci / docs-site (push) Successful in 1m15s
arch / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / bench (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
windows-host / package (push) Has been cancelled
android / android (push) Successful in 16m4s
apple / swift (push) Successful in 1m18s
apple / screenshots (push) Successful in 5m16s
ci / web (push) Successful in 58s
ci / docs-site (push) Successful in 1m15s
arch / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / bench (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
windows-host / package (push) Has been cancelled
android / android (push) Successful in 16m4s
The `wasapi` audio crate polls the default output device ~1×/s and
`log::debug!`s it (`wasapi::api default device Ok(...)`), flooding host.log
even at RUST_LOG=info: those `log`-crate records reach tracing through the
tracing-log bridge, and at *filter* time they carry the bridge's "log" shim
target, so neither a bare-info EnvFilter nor a `wasapi=warn` directive on the
file layer matches them (the ring already drops them post-hoc via
normalized_metadata + NOISY_DEBUG_TARGETS — the fmt layer filters pre-event and
can't).
Fix at the source: a shared `log_capture::install_global` replaces
SubscriberInitExt::init in both init paths (service file log + interactive
stderr) and inits the tracing-log bridge with `ignore_crate("wasapi")`, so the
poll records are dropped before they ever become tracing events — both sinks go
quiet, while every other log-crate dependency still reaches the console ring
(bridge max-level stays DEBUG). `wasapi` also added to NOISY_DEBUG_TARGETS as
belt-and-suspenders, and `log` moved dev-dep -> dep for LevelFilter.
Validated: .21 clippy (host --features nvenc) clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,9 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|||||||
# back to the real module path, so the console's target column and the ring's noise gate see
|
# back to the real module path, so the console's target column and the ring's noise gate see
|
||||||
# `mdns_sd::…` instead of "log".
|
# `mdns_sd::…` instead of "log".
|
||||||
tracing-log = "0.2"
|
tracing-log = "0.2"
|
||||||
|
# `log::LevelFilter` for the bridge's max-level in `log_capture::install_global` (which inits the
|
||||||
|
# tracing-log bridge with `ignore_crate("wasapi")`). Already in the tree transitively.
|
||||||
|
log = "0.4"
|
||||||
axum = "0.8"
|
axum = "0.8"
|
||||||
mdns-sd = "0.20"
|
mdns-sd = "0.20"
|
||||||
# Wake-on-LAN: report the host's wake-capable NIC MAC(s) to clients via the mDNS `mac` TXT record.
|
# Wake-on-LAN: report the host's wake-capable NIC MAC(s) to clients via the mDNS `mac` TXT record.
|
||||||
@@ -114,8 +117,6 @@ tower = { version = "0.5", features = ["util"] }
|
|||||||
http-body-util = "0.1"
|
http-body-util = "0.1"
|
||||||
# Disposable directory fixtures for the Steam local-librarycache scan tests (library.rs).
|
# Disposable directory fixtures for the Steam local-librarycache scan tests (library.rs).
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
# Emit `log`-crate records through the tracing-log bridge in the log_capture tests.
|
|
||||||
log = "0.4"
|
|
||||||
|
|
||||||
# Opus encode for the host->client audio plane — stereo (`opus::Encoder`) AND 5.1/7.1 surround
|
# Opus encode for the host->client audio plane — stereo (`opus::Encoder`) AND 5.1/7.1 surround
|
||||||
# (`opus::MSEncoder`, the safe multistream API the crate exposes; no `audiopus_sys` needed). The
|
# (`opus::MSEncoder`, the safe multistream API the crate exposes; no `audiopus_sys` needed). The
|
||||||
|
|||||||
@@ -125,12 +125,13 @@ pub fn ring() -> &'static LogRing {
|
|||||||
RING.get_or_init(LogRing::new)
|
RING.get_or_init(LogRing::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Targets whose DEBUG/TRACE output is steady-state per-packet chatter, not diagnostics — left
|
/// Targets whose DEBUG/TRACE output is steady-state chatter, not diagnostics — left in, they evict
|
||||||
/// in, they evict the entire ring tail (mdns-sd DEBUG-logs every multicast packet it can't parse,
|
/// the entire ring tail: `mdns_sd` DEBUG-logs every multicast packet it can't parse (one chatty
|
||||||
/// so one chatty AirPlay/HomePod device on the LAN floods thousands of entries per hour). The
|
/// AirPlay/HomePod device on the LAN floods thousands of entries per hour), and `wasapi` DEBUG-logs
|
||||||
/// ring keeps their INFO-and-up; stderr under `RUST_LOG` is unaffected. Prefix-matched on module
|
/// the default audio device once a second (the device-watchdog poll). The ring keeps their
|
||||||
/// path boundaries.
|
/// INFO-and-up; the file/stderr filter caps them separately (see `main`'s EnvFilter directives).
|
||||||
const NOISY_DEBUG_TARGETS: &[&str] = &["mdns_sd"];
|
/// Prefix-matched on module path boundaries.
|
||||||
|
const NOISY_DEBUG_TARGETS: &[&str] = &["mdns_sd", "wasapi"];
|
||||||
|
|
||||||
fn is_noisy_debug(target: &str) -> bool {
|
fn is_noisy_debug(target: &str) -> bool {
|
||||||
NOISY_DEBUG_TARGETS.iter().any(|t| {
|
NOISY_DEBUG_TARGETS.iter().any(|t| {
|
||||||
@@ -140,6 +141,25 @@ fn is_noisy_debug(target: &str) -> bool {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Init the `log`→`tracing` bridge and install `subscriber` as the global default. Replaces
|
||||||
|
/// `SubscriberInitExt::init()` (which auto-inits the bridge with no crate filtering) so we can
|
||||||
|
/// **drop the `wasapi` crate's records at the bridge**: it polls the default audio device ~1×/s
|
||||||
|
/// and `log::debug!`s it, and those bridged events carry the bridge shim target at *filter* time,
|
||||||
|
/// so a downstream level/target filter on the file layer can't catch them (the ring can, in
|
||||||
|
/// `on_event`, via `normalized_metadata` — but the fmt layer filters pre-event). `ignore_crate`
|
||||||
|
/// stops them at the source, before they ever become tracing events, so neither sink sees them.
|
||||||
|
/// The bridge max-level stays DEBUG so every *other* `log`-crate dependency still reaches the ring.
|
||||||
|
pub fn install_global<S>(subscriber: S)
|
||||||
|
where
|
||||||
|
S: tracing::Subscriber + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
let _ = tracing_log::LogTracer::builder()
|
||||||
|
.with_max_level(log::LevelFilter::Debug)
|
||||||
|
.ignore_crate("wasapi")
|
||||||
|
.init();
|
||||||
|
let _ = tracing::subscriber::set_global_default(subscriber);
|
||||||
|
}
|
||||||
|
|
||||||
/// The tee: a `tracing_subscriber` layer pushing every event into [`ring`]. Install with a
|
/// The tee: a `tracing_subscriber` layer pushing every event into [`ring`]. Install with a
|
||||||
/// per-layer `LevelFilter::DEBUG` so the ring sees DEBUG even when `RUST_LOG` keeps stderr at
|
/// per-layer `LevelFilter::DEBUG` so the ring sees DEBUG even when `RUST_LOG` keeps stderr at
|
||||||
/// `info` (remote debugging must not require a restart with a different env).
|
/// `info` (remote debugging must not require a restart with a different env).
|
||||||
|
|||||||
@@ -117,18 +117,19 @@ fn main() {
|
|||||||
// A second layer tees DEBUG-and-up into the in-memory ring served by GET /api/v1/logs —
|
// A second layer tees DEBUG-and-up into the in-memory ring served by GET /api/v1/logs —
|
||||||
// deliberately not gated by RUST_LOG, so console-side debugging never needs a restart.
|
// deliberately not gated by RUST_LOG, so console-side debugging never needs a restart.
|
||||||
use tracing_subscriber::layer::SubscriberExt;
|
use tracing_subscriber::layer::SubscriberExt;
|
||||||
use tracing_subscriber::util::SubscriberInitExt;
|
|
||||||
use tracing_subscriber::Layer;
|
use tracing_subscriber::Layer;
|
||||||
tracing_subscriber::registry()
|
log_capture::install_global(
|
||||||
.with(
|
tracing_subscriber::registry()
|
||||||
log_capture::RingLayer.with_filter(tracing_subscriber::filter::LevelFilter::DEBUG),
|
.with(
|
||||||
)
|
log_capture::RingLayer
|
||||||
.with(
|
.with_filter(tracing_subscriber::filter::LevelFilter::DEBUG),
|
||||||
tracing_subscriber::fmt::layer()
|
)
|
||||||
.with_writer(std::io::stderr)
|
.with(
|
||||||
.with_filter(filter),
|
tracing_subscriber::fmt::layer()
|
||||||
)
|
.with_writer(std::io::stderr)
|
||||||
.init();
|
.with_filter(filter),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tee every panic through `tracing` BEFORE the default hook: a panicking thread otherwise
|
// Tee every panic through `tracing` BEFORE the default hook: a panicking thread otherwise
|
||||||
|
|||||||
@@ -153,37 +153,36 @@ fn rotate_if_large(path: &std::path::Path) {
|
|||||||
/// supervisor serves no mgmt API itself, but the layer is harmless and keeps both inits uniform.
|
/// supervisor serves no mgmt API itself, but the layer is harmless and keeps both inits uniform.
|
||||||
pub fn init_file_logging(filter: tracing_subscriber::EnvFilter) {
|
pub fn init_file_logging(filter: tracing_subscriber::EnvFilter) {
|
||||||
use tracing_subscriber::layer::SubscriberExt;
|
use tracing_subscriber::layer::SubscriberExt;
|
||||||
use tracing_subscriber::util::SubscriberInitExt;
|
|
||||||
use tracing_subscriber::Layer;
|
use tracing_subscriber::Layer;
|
||||||
let ring =
|
let ring =
|
||||||
crate::log_capture::RingLayer.with_filter(tracing_subscriber::filter::LevelFilter::DEBUG);
|
crate::log_capture::RingLayer.with_filter(tracing_subscriber::filter::LevelFilter::DEBUG);
|
||||||
let log_path = service_log_path();
|
let log_path = service_log_path();
|
||||||
rotate_if_large(&log_path);
|
rotate_if_large(&log_path);
|
||||||
|
// `install_global` inits the log bridge with `ignore_crate("wasapi")` (see its doc) and sets
|
||||||
|
// the subscriber global — replacing `SubscriberInitExt::init`, which would bridge every crate.
|
||||||
match std::fs::OpenOptions::new()
|
match std::fs::OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.append(true)
|
.append(true)
|
||||||
.open(log_path)
|
.open(log_path)
|
||||||
{
|
{
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
tracing_subscriber::registry()
|
crate::log_capture::install_global(
|
||||||
.with(ring)
|
tracing_subscriber::registry().with(ring).with(
|
||||||
.with(
|
|
||||||
tracing_subscriber::fmt::layer()
|
tracing_subscriber::fmt::layer()
|
||||||
.with_ansi(false)
|
.with_ansi(false)
|
||||||
.with_writer(move || file.try_clone().expect("clone service log handle"))
|
.with_writer(move || file.try_clone().expect("clone service log handle"))
|
||||||
.with_filter(filter),
|
.with_filter(filter),
|
||||||
)
|
),
|
||||||
.init();
|
);
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
tracing_subscriber::registry()
|
crate::log_capture::install_global(
|
||||||
.with(ring)
|
tracing_subscriber::registry().with(ring).with(
|
||||||
.with(
|
|
||||||
tracing_subscriber::fmt::layer()
|
tracing_subscriber::fmt::layer()
|
||||||
.with_writer(std::io::stderr)
|
.with_writer(std::io::stderr)
|
||||||
.with_filter(filter),
|
.with_filter(filter),
|
||||||
)
|
),
|
||||||
.init();
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user