# How Debug Mode and Logging Work in Superfile: A Complete Technical Guide

> Understand how debug mode and logging work in Superfile. Learn how the boolean debug flag controls the slog logger for detailed diagnostics and clean operation.

- Repository: [Yorukot/superfile](https://github.com/yorukot/superfile)
- Tags: deep-dive
- Published: 2026-07-28

---

**Debug mode and logging in superfile are controlled by a boolean `debug` configuration flag that switches the global slog logger between Info and Debug levels, exposing detailed diagnostic output while maintaining clean normal operation.**

Superfile, the modern terminal file manager written in Go, implements a unified debugging and logging system built on the standard library's `slog` package. Understanding how debug mode and logging in superfile work is essential for troubleshooting file operations and understanding internal state transitions. The system propagates a single configuration value from user settings through CLI arguments to the root logger initializer, ensuring consistent log levels across the entire application lifecycle.

## Configuring Debug Mode in Superfile

Superfile offers two mechanisms for enabling debug output: persistent configuration via the config file, or temporary activation through command-line flags.

### Persistent Configuration via config.toml

The debug setting lives in the `ConfigType` struct defined in [`src/internal/common/config_type.go`](https://github.com/yorukot/superfile/blob/main/src/internal/common/config_type.go). This struct includes a `debug` boolean field marked with the comment "Whether to enable debug mode." Users can persistently enable debugging by setting `debug = true` in their `~/.config/superfile/config.toml` file:

```toml

# ~/.config/superfile/config.toml

debug = true

```

When the application loads its configuration, this value determines the initial logging behavior before any CLI flags are processed.

### Temporary Override with CLI Flags

For one-off debugging sessions, Superfile exposes a `--debug` (or `-d`) flag in [`src/cmd/main.go`](https://github.com/yorukot/superfile/blob/main/src/cmd/main.go). This flag overrides the configuration file setting for the current execution:

```bash

# Enable debug mode for a single session

superfile --debug

# Or use the short form

superfile -d

```

The CLI parser stores this value and passes it to `configure_logging()`, which forwards the boolean to the logger initialization logic.

## How the Logging System Initializes

The core logging infrastructure resides in [`src/pkg/utils/log_utils.go`](https://github.com/yorukot/superfile/blob/main/src/pkg/utils/log_utils.go), where the function `SetRootLoggerToStdout(debug bool)` creates and configures the global logger instance.

### Root Logger Setup in log_utils.go

When Superfile starts, it calls `utils.SetRootLoggerToStdout(debug)` to establish the logging infrastructure. This function creates a new `slog` logger using a text handler attached to `os.Stdout`:

```go
// src/pkg/utils/log_utils.go
func SetRootLoggerToStdout(debug bool) {
    level := slog.LevelInfo
    if debug {
        level = slog.LevelDebug          // ← Debug mode boosts log level
    }
    slog.SetDefault(slog.New(
        slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level}),
    ))
}

```

The function immediately sets this logger as the default via `slog.SetDefault()`, ensuring all subsequent logging calls throughout the codebase use this configured handler.

### Log Level Switching (Info vs Debug)

The critical mechanism lies in the `HandlerOptions.Level` assignment. When the `debug` parameter is `false`, the logger uses `slog.LevelInfo`, filtering out Debug-level messages. When `debug` is `true`, the level shifts to `slog.LevelDebug`, causing all `logger.Debug()` calls to become visible.

This design allows developers to sprinkle detailed diagnostic calls throughout the codebase without impacting performance or cluttering output during normal usage:

```go
// Example usage inside Superfile code
logger := slog.Default()
logger.Debug("Opening file panel", "panel", panelID)   // Visible only with debug mode
logger.Info("File saved", "path", filePath)           // Always visible

```

## Where Log Output Goes

Superfile implements a dual-phase logging strategy that captures bootstrap information differently from runtime logs.

### Startup Logging to Stdout

During application initialization—before the configuration file is fully parsed and the log file is opened—the logger writes to `os.Stdout` as configured in `SetRootLoggerToStdout`. This ensures that early-stage errors and configuration parsing issues are visible immediately, even if the eventual log file destination is unavailable or misconfigured.

### File Destination Configuration

After the initial bootstrap, the logging destination transitions based on the `log_file` entry in [`config.toml`](https://github.com/yorukot/superfile/blob/main/config.toml). The application updates `slog.SetDefault()` to redirect output to the specified file path, ensuring that detailed logs persist across sessions for post-mortem analysis. This architecture guarantees that both interactive debugging (via stdout) and background logging (via file) operate through the same unified pipeline.

## Writing Debug Messages in the Codebase

Throughout Superfile's source code, developers access the logger via `slog.Default()` (often aliased to `logger`). The codebase uses structured logging with key-value pairs:

```go
logger.Debug("Navigation event", "from", currentPath, "to", targetPath)
logger.Debug("Render operation", "panel_count", len(panels), "duration_ms", elapsed)

```

When debug mode is disabled, these calls return immediately with minimal overhead because the `slog` handler filters them before processing. When enabled, the text handler formats these as structured key-value pairs to the output destination.

## The debug-info Diagnostic Command

Beyond the standard logging system, Superfile provides a separate diagnostic tool via the `debug-info` command implemented in [`src/cmd/debug_info.go`](https://github.com/yorukot/superfile/blob/main/src/cmd/debug_info.go). Running `superfile --debug-info` prints internal state including environment variables, dependency versions, and configuration values.

This command operates independently of the standard logger initialization but respects the same `debug` flag semantics, offering a snapshot of system state useful for bug reports and environment troubleshooting.

```bash

# Print diagnostic information

superfile --debug-info

```

## Summary

- **Configuration**: The `debug` field in `ConfigType` ([`src/internal/common/config_type.go`](https://github.com/yorukot/superfile/blob/main/src/internal/common/config_type.go)) controls logging behavior, settable via [`config.toml`](https://github.com/yorukot/superfile/blob/main/config.toml) or the `-d/--debug` CLI flag.
- **Initialization**: `SetRootLoggerToStdout()` in [`src/pkg/utils/log_utils.go`](https://github.com/yorukot/superfile/blob/main/src/pkg/utils/log_utils.go) creates the root logger with either `slog.LevelInfo` or `slog.LevelDebug`.
- **Output**: Logs write to stdout during startup, then transition to the file specified by `log_file` in configuration.
- **Usage**: Code calls `slog.Default().Debug()` for diagnostic data, which only appears when debug mode is active.
- **Diagnostics**: The `--debug-info` flag provides instant system state reporting without entering the full TUI.

## Frequently Asked Questions

### How do I enable debug mode temporarily without editing config files?

Use the `-d` or `--debug` command-line flag when launching Superfile. This passes `true` to `configure_logging` in [`src/cmd/main.go`](https://github.com/yorukot/superfile/blob/main/src/cmd/main.go), overriding the config file setting for that session only. This is ideal for troubleshooting specific operations without persisting verbose logs to disk.

### What is the difference between `--debug` and `--debug-info`?

The `--debug` flag enables the debug logging level, causing `logger.Debug()` calls throughout the codebase to print to your log destination. The `--debug-info` command (implemented in [`src/cmd/debug_info.go`](https://github.com/yorukot/superfile/blob/main/src/cmd/debug_info.go)) is a standalone diagnostic tool that prints system information and exits immediately, without launching the file manager interface.

### Where are log files stored when debug mode is enabled?

Superfile initially logs to stdout during bootstrap. Once configuration loads, logs write to the path specified by the `log_file` entry in your [`config.toml`](https://github.com/yorukot/superfile/blob/main/config.toml). If no log file is configured, output may remain on stdout depending on your specific build and initialization sequence.

### Why don't I see Debug level messages even with debug enabled?

Ensure the `SetRootLoggerToStdout` function in [`src/pkg/utils/log_utils.go`](https://github.com/yorukot/superfile/blob/main/src/pkg/utils/log_utils.go) is receiving `true` for its `debug` parameter. Debug messages only appear when the `slog.HandlerOptions.Level` is set to `slog.LevelDebug`. If using the CLI flag, verify it is being parsed correctly in [`src/cmd/main.go`](https://github.com/yorukot/superfile/blob/main/src/cmd/main.go) and passed through to the logging configuration function.