darkwing/logger.rs
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
//! Logging configuration and initialization module.
//!
//! This module provides functionality to set up application-wide logging using
//! the tracing framework, with support for different environments and panic
//! handling.
use std::{panic, thread};
use tracing::{error, level_filters::LevelFilter};
use tracing_appender::non_blocking::WorkerGuard;
use crate::config::CargoEnv;
/// Logger initialization and configuration struct.
///
/// Provides functionality to initialize the logging system with appropriate
/// settings based on the environment (development, test, or production).
pub struct Logger {}
impl Logger {
/// Initializes the logging system with environment-specific configuration.
///
/// # Arguments
///
/// * `cargo_env` - The environment configuration (Development, Test, or
/// Production)
/// * `with_panic_hook` - Whether to install a custom panic hook that logs
/// panics
///
/// # Returns
///
/// Returns a `WorkerGuard` that must be held for the duration of the program
/// to ensure log messages are fully written.
///
/// # Features
///
/// * Configures different log levels based on environment
/// * Development: Logs to console at DEBUG level
/// * Test/Production: Logs to daily rotating files at DEBUG/INFO level
/// * Optional panic hook installation for improved error reporting
/// * Integration with Sentry for error tracking
///
/// # Examples
///
/// ```
/// use darkwing::{Logger, CargoEnv};
///
/// let _guard = Logger::init(CargoEnv::Development, true);
/// // Keep guard in scope while application runs
/// ```
pub fn init(cargo_env: CargoEnv, with_panic_hook: bool) -> WorkerGuard {
let file_logger = tracing_appender::rolling::daily("logs", "daily.log");
let console_logger = std::io::stdout();
let max_level = match cargo_env {
CargoEnv::Development => LevelFilter::DEBUG,
CargoEnv::Test => LevelFilter::DEBUG,
CargoEnv::Production => LevelFilter::INFO,
};
let (non_blocking, guard) = match cargo_env {
CargoEnv::Development => tracing_appender::non_blocking(console_logger),
CargoEnv::Test => tracing_appender::non_blocking(file_logger),
CargoEnv::Production => tracing_appender::non_blocking(file_logger),
};
tracing_subscriber::fmt()
.with_writer(non_blocking)
.with_max_level(max_level)
.init();
// Install custom panic hook for improved error reporting
if with_panic_hook {
panic::set_hook(Box::new(|info| {
let thread = thread::current();
let thread = thread.name().unwrap_or("unknown");
let msg = match info.payload().downcast_ref::<&'static str>() {
Some(s) => *s,
None => match info.payload().downcast_ref::<String>() {
Some(s) => &**s,
None => "Box<Any>",
},
};
let backtrace = backtrace::Backtrace::new();
match info.location() {
Some(location) => {
// Log without backtrace if message starts with "notrace - "
if msg.starts_with("notrace - ") {
error!(
target: "panic", "thread '{}' panicked at '{}': {}:{}",
thread,
msg.replace("notrace - ", ""),
location.file(),
location.line()
);
} else {
// Log with backtrace
error!(
target: "panic", "thread '{}' panicked at '{}': {}:{}\n{:?}",
thread,
msg,
location.file(),
location.line(),
backtrace
);
}
}
None => {
// Log without backtrace if message starts with "notrace - "
if msg.starts_with("notrace - ") {
error!(
target: "panic", "thread '{}' panicked at '{}'",
thread,
msg.replace("notrace - ", ""),
);
} else {
// Log with backtrace
error!(
target: "panic", "thread '{}' panicked at '{}'\n{:?}",
thread,
msg,
backtrace
);
}
}
}
// Forward panic to Sentry
sentry::integrations::panic::panic_handler(info);
}));
}
guard
}
}