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);
    }
}