use std::sync::{Arc, Mutex};
use tracing::Level;
use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan};
#[derive(Debug, Clone, Default)]
pub struct FormTracing {
pub field: Option<Level>,
pub set_value: Option<Level>,
pub validate: Option<Level>,
pub render: Option<Level>,
pub finalize: Option<Level>,
}
impl FormTracing {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn field(mut self, level: Level) -> Self {
self.field = Some(level);
self
}
#[must_use]
pub fn set_value(mut self, level: Level) -> Self {
self.set_value = Some(level);
self
}
#[must_use]
pub fn validate(mut self, level: Level) -> Self {
self.validate = Some(level);
self
}
#[must_use]
pub fn render(mut self, level: Level) -> Self {
self.render = Some(level);
self
}
#[must_use]
pub fn finalize(mut self, level: Level) -> Self {
self.finalize = Some(level);
self
}
pub fn dev(self) -> Self {
self.field(Level::DEBUG)
.set_value(Level::DEBUG)
.validate(Level::DEBUG)
.render(Level::DEBUG)
.finalize(Level::DEBUG)
}
}
#[derive(Debug, Clone, Default)]
pub struct BuilderTracing {
pub templates: Option<Level>,
pub registry: Option<Level>,
pub middleware: Option<Level>,
pub statics: Option<Level>,
pub routes: Option<Level>,
}
impl BuilderTracing {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn templates(mut self, level: Level) -> Self {
self.templates = Some(level);
self
}
#[must_use]
pub fn registry(mut self, level: Level) -> Self {
self.registry = Some(level);
self
}
#[must_use]
pub fn middleware(mut self, level: Level) -> Self {
self.middleware = Some(level);
self
}
#[must_use]
pub fn statics(mut self, level: Level) -> Self {
self.statics = Some(level);
self
}
#[must_use]
pub fn routes(mut self, level: Level) -> Self {
self.routes = Some(level);
self
}
pub fn dev(self) -> Self {
self.templates(Level::DEBUG)
.registry(Level::DEBUG)
.middleware(Level::DEBUG)
.statics(Level::DEBUG)
.routes(Level::DEBUG)
}
}
#[derive(Debug, Clone, Default)]
pub struct AuthTracing {
pub login: Option<Level>,
pub reset: Option<Level>,
}
impl AuthTracing {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn login(mut self, level: Level) -> Self {
self.login = Some(level);
self
}
#[must_use]
pub fn reset(mut self, level: Level) -> Self {
self.reset = Some(level);
self
}
pub fn dev(self) -> Self {
self.login(Level::DEBUG).reset(Level::DEBUG)
}
}
#[derive(Debug, Clone, Default)]
pub struct MailerTracing {
pub send: Option<Level>,
}
impl MailerTracing {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn send(mut self, level: Level) -> Self {
self.send = Some(level);
self
}
pub fn dev(self) -> Self {
self.send(Level::DEBUG)
}
}
#[derive(Debug, Clone, Default)]
pub struct AdminTracing {
pub auth: Option<Level>,
pub crud: Option<Level>,
pub list: Option<Level>,
pub bulk: Option<Level>,
}
impl AdminTracing {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn auth(mut self, level: Level) -> Self {
self.auth = Some(level);
self
}
#[must_use]
pub fn crud(mut self, level: Level) -> Self {
self.crud = Some(level);
self
}
#[must_use]
pub fn list(mut self, level: Level) -> Self {
self.list = Some(level);
self
}
#[must_use]
pub fn bulk(mut self, level: Level) -> Self {
self.bulk = Some(level);
self
}
pub fn dev(self) -> Self {
self.auth(Level::DEBUG)
.crud(Level::DEBUG)
.list(Level::DEBUG)
.bulk(Level::DEBUG)
}
}
#[derive(Debug, Clone, Default)]
pub struct RuniqueLog {
subscriber_level: Option<String>,
pub csrf: Option<Level>,
pub exclusive_login: Option<Level>,
pub filter_fn: Option<Level>,
pub roles: Option<Level>,
pub password_init: Option<Level>,
pub session: Option<Level>,
pub db: Option<Level>,
pub host_validation: Option<Level>,
pub acme: Option<Level>,
pub forms: Option<FormTracing>,
pub admin: Option<AdminTracing>,
pub auth: Option<AuthTracing>,
pub mailer: Option<MailerTracing>,
pub builder: Option<BuilderTracing>,
pub rate_limit: Option<Level>,
}
impl RuniqueLog {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn subscriber_level(mut self, level: impl Into<String>) -> Self {
self.subscriber_level = Some(level.into());
self
}
pub fn init_subscriber(&self) {
let default = self.subscriber_level.as_deref().unwrap_or_else(|| {
if crate::utils::env::is_debug() {
"debug"
} else {
"warn"
}
});
let filter =
std::env::var("RUST_LOG").map_or_else(|_| EnvFilter::new(default), EnvFilter::new);
tracing_subscriber::fmt()
.with_env_filter(filter)
.with_span_events(FmtSpan::CLOSE)
.try_init()
.ok();
}
#[must_use]
pub fn csrf(mut self, level: Level) -> Self {
self.csrf = Some(level);
self
}
#[must_use]
pub fn exclusive_login(mut self, level: Level) -> Self {
self.exclusive_login = Some(level);
self
}
#[must_use]
pub fn filter_fn(mut self, level: Level) -> Self {
self.filter_fn = Some(level);
self
}
#[must_use]
pub fn roles(mut self, level: Level) -> Self {
self.roles = Some(level);
self
}
#[must_use]
pub fn password_init(mut self, level: Level) -> Self {
self.password_init = Some(level);
self
}
#[must_use]
pub fn session(mut self, level: Level) -> Self {
self.session = Some(level);
self
}
#[must_use]
pub fn db(mut self, level: Level) -> Self {
self.db = Some(level);
self
}
#[must_use]
pub fn host_validation(mut self, level: Level) -> Self {
self.host_validation = Some(level);
self
}
#[must_use]
pub fn acme(mut self, level: Level) -> Self {
self.acme = Some(level);
self
}
#[must_use]
pub fn forms(mut self, f: impl FnOnce(FormTracing) -> FormTracing) -> Self {
self.forms = Some(f(self.forms.take().unwrap_or_default()));
self
}
#[must_use]
pub fn admin(mut self, f: impl FnOnce(AdminTracing) -> AdminTracing) -> Self {
self.admin = Some(f(self.admin.take().unwrap_or_default()));
self
}
#[must_use]
pub fn auth(mut self, f: impl FnOnce(AuthTracing) -> AuthTracing) -> Self {
self.auth = Some(f(self.auth.take().unwrap_or_default()));
self
}
#[must_use]
pub fn mailer(mut self, f: impl FnOnce(MailerTracing) -> MailerTracing) -> Self {
self.mailer = Some(f(self.mailer.take().unwrap_or_default()));
self
}
#[must_use]
pub fn rate_limit(mut self, level: Level) -> Self {
self.rate_limit = Some(level);
self
}
#[must_use]
pub fn builder(mut self, f: impl FnOnce(BuilderTracing) -> BuilderTracing) -> Self {
self.builder = Some(f(self.builder.take().unwrap_or_default()));
self
}
#[must_use]
pub fn dev(self) -> Self {
if !crate::utils::env::is_debug() {
return self;
}
self.csrf(Level::DEBUG)
.exclusive_login(Level::DEBUG)
.filter_fn(Level::DEBUG)
.roles(Level::DEBUG)
.password_init(Level::DEBUG)
.session(Level::DEBUG)
.db(Level::DEBUG)
.host_validation(Level::DEBUG)
.acme(Level::DEBUG)
.rate_limit(Level::DEBUG)
.forms(|f| f.dev())
.admin(|a| a.dev())
.auth(|a| a.dev())
.mailer(|m| m.dev())
.builder(|b| b.dev())
}
}
static LOG_CONFIG: Mutex<Option<Arc<RuniqueLog>>> = Mutex::new(None);
pub fn log_init(config: RuniqueLog) {
if let Ok(mut guard) = LOG_CONFIG.lock()
&& guard.is_none()
{
*guard = Some(Arc::new(config));
}
}
pub fn get_log() -> Arc<RuniqueLog> {
LOG_CONFIG
.lock()
.ok()
.and_then(|g| g.as_ref().cloned())
.unwrap_or_default()
}
pub fn reset_log_for_test() {
if let Ok(mut guard) = LOG_CONFIG.lock() {
*guard = None;
}
}
#[macro_export]
macro_rules! runique_log {
($level:expr, $($args:tt)*) => {
match $level {
::tracing::Level::ERROR => ::tracing::error!($($args)*),
::tracing::Level::WARN => ::tracing::warn!($($args)*),
::tracing::Level::INFO => ::tracing::info!($($args)*),
::tracing::Level::DEBUG => ::tracing::debug!($($args)*),
_ => ::tracing::trace!($($args)*),
}
};
}