Logging Infrastructure and Log Rotation in Universal Android Debloater NG

The Universal Android Debloater NG uses the fern crate combined with log and chrono to write timestamped logs to both the console and a persistent file at CACHE_DIR/uadng.log, but does not implement any automatic log rotation or size-based truncation, requiring manual file management.

The Universal Android Debloater Next Generation (UAD-ng) implements its logging infrastructure through the fern crate to capture diagnostic information from the GUI application. Understanding this logging infrastructure is essential for developers debugging GUI issues and users managing disk space, particularly because the application handles log rotation manually rather than through automated mechanisms.

Logging Backend and Dependencies

The logging infrastructure relies on three primary crates from the Rust ecosystem:

  • fern: Provides the dispatch-based logging backend
  • log: Supplies the standard logging facade and macros
  • chrono: Handles timestamp formatting for log entries

These dependencies are declared in the workspace Cargo.toml, with fern configured to use the colored feature for terminal output.

Log Output Configuration

The setup_logger() function in crates/uad-gui/src/main.rs constructs two independent fern::Dispatch objects that process log records simultaneously.

Console Output (Stdout)

The stdout dispatcher handles colored terminal output for debugging purposes:

  • Default level: Warn
  • Module-specific level: Debug for the uad_gui module
  • Formatting: Colored level indicators using ColoredLevelConfig

File Persistence

The file dispatcher writes plain-text logs to the user's cache directory:

  • Location: CACHE_DIR.join("uadng.log") (e.g., ~/.cache/universal-android-debloater-ng/uadng.log on Linux)
  • Mode: Opened with create(true), append(true), and truncate(false)
  • Default level: Warn
  • Module-specific level: Debug for the uad_gui module

Each log entry follows the format: TIMESTAMP LEVEL [file.rs:line] message.

Log Rotation Behavior

No automatic log rotation is implemented. The logging infrastructure opens the file in append mode and writes indefinitely without size checks or file archiving. The log file continues to grow across application sessions until manually deleted or until the cache directory is cleared during reinstallation.

The codebase does not integrate third-party rotation crates such as log4rs or flexi_logger, nor does it contain logic to rotate, compress, or archive old log files based on age or size thresholds.

Implementation Examples

Setting Up the Logger

The setup_logger() function in crates/uad-gui/src/main.rs configures the dual-output pipeline:

fn setup_logger() -> Result<(), fern::InitError> {
    #[cfg(target_os = "windows")] { attach_windows_console(); }

    let colors = ColoredLevelConfig::new().info(Color::Green);

    // Formatter used for both stdout and file output
    let make_formatter = |use_colors: bool| {
        move |out: FormatCallback, message: &Arguments, record: &Record| {
            out.finish(format_args!(
                "{} {} [{}:{}] {}",
                chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                if use_colors {
                    format!("{:5}", colors.color(record.level()))
                } else {
                    format!("{:5}", record.level())
                },
                record.file().unwrap_or("?"),
                record.line().map(|l| l.to_string()).unwrap_or_default(),
                message
            ));
        }
    };

    let default_log_level = log::LevelFilter::Warn;
    let log_file = OpenOptions::new()
        .create(true)
        .append(true)
        .truncate(false)
        .open(CACHE_DIR.join("uadng.log"))?;

    // File dispatcher (plain text, no colors)
    let file_dispatcher = fern::Dispatch::new()
        .format(make_formatter(false))
        .level(default_log_level)
        .level_for("uad_gui", log::LevelFilter::Debug)
        .chain(log_file);

    // Stdout dispatcher (colored)
    let stdout_dispatcher = fern::Dispatch::new()
        .format(make_formatter(true))
        .level(default_log_level)
        .level_for("uad_gui", log::LevelFilter::Warn)
        .chain(std::io::stdout());

    // Combine both dispatchers
    fern::Dispatch::new()
        .chain(stdout_dispatcher)
        .chain(file_dispatcher)
        .apply()?;

    Ok(())
}

Emitting Log Entries

Any module can use standard log macros to write to the configured dispatchers:

use log::{debug, info, warn};

fn some_function() {
    info!("Starting operation");
    debug!("Detailed debug data: {:?}", some_data);
    warn!("Potential issue detected");
}

Locating the Log File at Runtime

The log file path resolves to the OS-specific cache directory:

let log_path = CACHE_DIR.join("uadng.log");
println!("Log file is stored at: {}", log_path.display());

CACHE_DIR is defined as a LazyLock<PathBuf> that resolves to platform-specific locations such as $XDG_CACHE_HOME/universal-android-debloater-ng on Linux or %LOCALAPPDATA%\universal-android-debloater-ng on Windows.

Summary

  • fern provides the underlying logging infrastructure for UAD-ng, dispatching records to multiple outputs simultaneously.
  • Logs write to both colored stdout (for debugging) and a plain-text file at CACHE_DIR/uadng.log (for persistence).
  • The file appender uses create(true) and append(true) with truncate(false) to preserve historical entries across sessions.
  • No automatic log rotation exists; the file grows indefinitely until manually deleted or the cache is cleared.
  • Users must manually manage the uadng.log file to prevent unbounded disk usage.

Frequently Asked Questions

Does Universal Android Debloater NG rotate logs automatically?

No. The application does not implement automatic log rotation, size-based truncation, or log archiving. The uadng.log file opens in append mode and accumulates entries indefinitely until manually removed.

Where are UAD-ng log files stored on different operating systems?

The log file location depends on the operating system's cache directory conventions. On Linux, it typically resides at ~/.cache/universal-android-debloater-ng/uadng.log. On Windows, it uses %LOCALAPPDATA%\universal-android-debloater-ng\uadng.log, and on macOS, it uses ~/Library/Caches/universal-android-debloater-ng/uadng.log. The CACHE_DIR variable in crates/uad-gui/src/main.rs resolves these paths at runtime.

What Rust crates handle the logging infrastructure?

The logging infrastructure uses the fern crate for the dispatch backend, the log crate for the standard logging facade and macros, and chrono for timestamp formatting. These are configured in the workspace Cargo.toml with fern's colored feature enabled for terminal output.

How can I manually clear or truncate the log file?

You can safely delete the uadng.log file while the application is not running, or truncate it using system commands like > ~/.cache/universal-android-debloater-ng/uadng.log on Linux. Since the application uses append mode with create(true), it will recreate the file on the next launch if deleted.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →