1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
//! Text logging (nothing to do with rerun logging) for use in rerun libraries.
//!
//! Provides helpers for adding multiple loggers,
//! and for setting up logging on native and on web.
//!
//! * `trace`: spammy things
//! * `debug`: things that might be useful when debugging
//! * `info`: things that we want to show to users
//! * `warn`: problems that we can recover from
//! * `error`: problems that lead to loss of functionality or data
//!
//! The `warn_once` etc macros are for when you want to suppress repeated
//! logging of the exact same message.
mod channel_logger;
mod result_extensions;
#[cfg(feature = "setup")]
mod multi_logger;
#[cfg(feature = "setup")]
mod setup;
#[cfg(all(feature = "setup", target_arch = "wasm32"))]
mod web_logger;
pub use log::{Level, LevelFilter};
pub use result_extensions::ResultExt;
// The tracing macros support more syntax features than the log, that's why we use them:
pub use tracing::{debug, error, info, trace, warn};
// The `re_log::info_once!(…)` etc are nice helpers, but the `log-once` crate is a bit lacking.
// In the future we should implement our own macros to de-duplicate based on the callsite,
// similar to how the log console in a browser will automatically suppress duplicates.
pub use log_once::{debug_once, error_once, info_once, log_once, trace_once, warn_once};
pub use channel_logger::*;
#[cfg(feature = "setup")]
pub use multi_logger::{add_boxed_logger, add_logger, MultiLoggerNotSetupError};
#[cfg(feature = "setup")]
pub use setup::setup_logging;
/// Re-exports of other crates.
pub mod external {
pub use log;
}
/// Never log anything less serious than a `ERROR` from these crates.
const CRATES_AT_ERROR_LEVEL: &[&str] = &[
// silence rustls in release mode: https://github.com/rerun-io/rerun/issues/3104
#[cfg(not(debug_assertions))]
"rustls",
];
/// Never log anything less serious than a `WARN` from these crates.
const CRATES_AT_WARN_LEVEL: &[&str] = &[
// wgpu crates spam a lot on info level, which is really annoying
// TODO(emilk): remove once https://github.com/gfx-rs/wgpu/issues/3206 is fixed
"naga",
"tracing",
"wgpu_core",
"wgpu_hal",
"zbus",
];
/// Never log anything less serious than a `INFO` from these crates.
const CRATES_AT_INFO_LEVEL: &[&str] = &[
// These are quite spammy on debug, drowning out what we care about:
"h2",
"hyper",
"prost_build",
"ureq",
// only let rustls log in debug mode: https://github.com/rerun-io/rerun/issues/3104
#[cfg(debug_assertions)]
"rustls",
// walkers generates noise around tile download, see https://github.com/podusowski/walkers/issues/199
"walkers",
// winit 0.30.5 spams about `set_cursor_visible` calls. It's gone on winit master, so hopefully gone in next winit release.
"winit",
];
/// Get `RUST_LOG` environment variable or `info`, if not set.
///
/// Also sets some other log levels on crates that are too loud.
#[cfg(not(target_arch = "wasm32"))]
pub fn default_log_filter() -> String {
let mut rust_log = std::env::var("RUST_LOG").unwrap_or_else(|_| {
if cfg!(debug_assertions) {
"debug".to_owned()
} else {
"info".to_owned()
}
});
for crate_name in crate::CRATES_AT_ERROR_LEVEL {
if !rust_log.contains(&format!("{crate_name}=")) {
rust_log += &format!(",{crate_name}=error");
}
}
for crate_name in crate::CRATES_AT_WARN_LEVEL {
if !rust_log.contains(&format!("{crate_name}=")) {
rust_log += &format!(",{crate_name}=warn");
}
}
for crate_name in crate::CRATES_AT_INFO_LEVEL {
if !rust_log.contains(&format!("{crate_name}=")) {
rust_log += &format!(",{crate_name}=info");
}
}
//TODO(#8077): should be removed as soon as the upstream issue is resolved
rust_log += ",walkers::download=off";
rust_log
}
/// Should we log this message given the filter?
fn is_log_enabled(filter: log::LevelFilter, metadata: &log::Metadata<'_>) -> bool {
if CRATES_AT_ERROR_LEVEL
.iter()
.any(|crate_name| metadata.target().starts_with(crate_name))
{
return metadata.level() <= log::LevelFilter::Error;
}
if CRATES_AT_WARN_LEVEL
.iter()
.any(|crate_name| metadata.target().starts_with(crate_name))
{
return metadata.level() <= log::LevelFilter::Warn;
}
if CRATES_AT_INFO_LEVEL
.iter()
.any(|crate_name| metadata.target().starts_with(crate_name))
{
return metadata.level() <= log::LevelFilter::Info;
}
metadata.level() <= filter
}
/// Shorten a path to a Rust source file.
///
/// Example input:
/// * `/Users/emilk/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.24.1/src/runtime/runtime.rs`
/// * `crates/rerun/src/main.rs`
/// * `/rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/ops/function.rs`
///
/// Example output:
/// * `tokio-1.24.1/src/runtime/runtime.rs`
/// * `rerun/src/main.rs`
/// * `core/src/ops/function.rs`
#[allow(dead_code)] // only used on web and in tests
fn shorten_file_path(file_path: &str) -> &str {
if let Some(i) = file_path.rfind("/src/") {
if let Some(prev_slash) = file_path[..i].rfind('/') {
&file_path[prev_slash + 1..]
} else {
file_path
}
} else {
file_path
}
}
#[test]
fn test_shorten_file_path() {
for (before, after) in [
("/Users/emilk/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.24.1/src/runtime/runtime.rs", "tokio-1.24.1/src/runtime/runtime.rs"),
("crates/rerun/src/main.rs", "rerun/src/main.rs"),
("/rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/ops/function.rs", "core/src/ops/function.rs"),
("/weird/path/file.rs", "/weird/path/file.rs"),
]
{
assert_eq!(shorten_file_path(before), after);
}
}