Skip to main content

shell_tunnel/
logging.rs

1//! Logging initialization and configuration.
2
3use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
4
5/// Initialize the logging system.
6///
7/// Uses the `RUST_LOG` environment variable for filtering. If not set,
8/// defaults to `shell_tunnel=info`.
9///
10/// Diagnostics go to stderr, which leaves stdout for the things a caller wants
11/// to read: the public URL, the API key, the command to try. Sharing one stream
12/// means `shell-tunnel --tunnel | grep "Public URL"` picks up log lines instead.
13///
14/// # Panics
15///
16/// Panics if called more than once, or if another tracing subscriber
17/// has already been set.
18pub fn init() {
19    let filter =
20        EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("shell_tunnel=info"));
21
22    tracing_subscriber::registry()
23        .with(filter)
24        .with(
25            tracing_subscriber::fmt::layer()
26                .compact()
27                .with_writer(std::io::stderr),
28        )
29        .init();
30}
31
32/// Try to initialize the logging system.
33///
34/// Returns `Ok(())` if successful, or `Err` if logging has already been
35/// initialized.
36pub fn try_init() -> Result<(), tracing_subscriber::util::TryInitError> {
37    let filter =
38        EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("shell_tunnel=info"));
39
40    tracing_subscriber::registry()
41        .with(filter)
42        .with(
43            tracing_subscriber::fmt::layer()
44                .compact()
45                .with_writer(std::io::stderr),
46        )
47        .try_init()
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn test_try_init_idempotent() {
56        // First call may or may not succeed depending on test order
57        let _ = try_init();
58        // Second call should return error (already initialized)
59        // or succeed if this is the first test to run
60        let _ = try_init();
61        // Either way, we shouldn't panic
62    }
63
64    #[test]
65    fn test_logging_works() {
66        // Ensure we can emit log messages without panicking
67        let _ = try_init();
68
69        tracing::info!("test info message");
70        tracing::debug!("test debug message");
71        tracing::warn!("test warn message");
72        tracing::error!("test error message");
73        // If we get here without panicking, the test passes
74    }
75}