# Logging Infrastructure and Log Rotation in Universal Android Debloater NG

> Learn about the logging infrastructure and log rotation in Universal Android Debloater NG. This guide details its use of fern, log, and chrono for timestamped logs and explains its manual log management approach.

- Repository: [Universal-Debloater-Alliance/universal-android-debloater-next-generation](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation)
- Tags: internals
- Published: 2026-06-20

---

**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`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/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`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/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`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/crates/uad-gui/src/main.rs) configures the dual-output pipeline:

```rust
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:

```rust
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:

```rust
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`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/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`](https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/main/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.