AkurAI Build
Menu

Public repository / master

AkurAI-Drive / desktop/src-tauri/src/logging.rs

Latest change 2d36cd6c72fc6a63a7edb87bb54a4020e50f2f8a - desktop: Tauri v2 tray + Google-Drive-style file browser app by olibuijr

//! Structured logging for screenshot-free diagnosis.
//!
//! Everything is logged to BOTH stdout and a file at
//! `$XDG_STATE_HOME/akurai-drive/desktop.log` (fallback
//! `~/.local/state/akurai-drive/desktop.log`). The verbosity comes from
//! `RUST_LOG`; when it is unset we default to `info,akurai_drive=debug` so the
//! app's own crates (`akurai_drive_desktop`, `akurai_drive_sync`) log at debug
//! while the noisy dependency tree stays at info.

use std::path::PathBuf;
use std::sync::OnceLock;

use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{fmt, EnvFilter};

// The non-blocking writer's worker guard must live for the whole process or logs
// are dropped on exit — park it in a process-lifetime cell.
static GUARD: OnceLock<WorkerGuard> = OnceLock::new();

/// `$XDG_STATE_HOME/akurai-drive` (or `~/.local/state/akurai-drive`).
pub fn log_dir() -> PathBuf {
    let base = std::env::var_os("XDG_STATE_HOME")
        .map(PathBuf::from)
        .filter(|p| !p.as_os_str().is_empty())
        .or_else(|| dirs::home_dir().map(|h| h.join(".local").join("state")))
        .unwrap_or_else(|| PathBuf::from("."));
    base.join("akurai-drive")
}

/// The full path of the desktop log file.
pub fn log_path() -> PathBuf {
    log_dir().join("desktop.log")
}

/// Install the global subscriber. Safe to call once at startup.
pub fn init() {
    let dir = log_dir();
    if let Err(e) = std::fs::create_dir_all(&dir) {
        eprintln!("akurai-drive: cannot create log dir {}: {e}", dir.display());
    }

    let file_appender = tracing_appender::rolling::never(&dir, "desktop.log");
    let (file_writer, guard) = tracing_appender::non_blocking(file_appender);
    let _ = GUARD.set(guard);

    let filter = EnvFilter::try_from_default_env()
        .unwrap_or_else(|_| EnvFilter::new("info,akurai_drive=debug"));

    let stdout_layer = fmt::layer().with_target(true).with_writer(std::io::stdout);
    let file_layer = fmt::layer()
        .with_ansi(false)
        .with_target(true)
        .with_writer(file_writer);

    if tracing_subscriber::registry()
        .with(filter)
        .with(stdout_layer)
        .with(file_layer)
        .try_init()
        .is_err()
    {
        eprintln!("akurai-drive: tracing subscriber already initialized");
    }
}