How Lifetrace Configures the Loguru Logging Framework for Production

Lifetrace uses the Loguru logging framework, configured at runtime via Dynaconf settings in lifetrace/util/logging_config.py to output structured console logs and daily-sequenced files with separate error tracking.

Lifetrace is an open-source life-tracking application that relies on a centralized, highly configurable logging subsystem. Instead of Python’s standard library logging, the codebase adopts Loguru to provide a singleton logger interface with automatic structured formatting and simplified configuration management.

Why Lifetrace Uses Loguru Instead of Standard Logging

Standard Python logging requires boilerplate setup for handlers, formatters, and filter chains. Loguru collapses this complexity into a single importable logger object while retaining full control over sinks (output targets). In Lifetrace, this choice enables dynamic reconfiguration at server startup without restarting the process, and provides built-in support for colorized console output and file rotation that the standard library lacks without third-party packages.

Core Logging Configuration Architecture

The LoggerManager Class in lifetrace/util/logging_config.py

The heart of the subsystem is the LoggerManager class, instantiated by the setup_logging() function. This class encapsulates all Loguru configuration logic:

  1. Clears existing handlers via logger.remove() to ensure no duplicate sinks.
  2. Builds a module filter that silences logs from packages listed in the quiet_modules configuration (e.g., uvicorn, sqlalchemy).
  3. Adds a console sink pointing to sys.stderr with a timestamp-rich format controlled by console_level.
  4. Creates daily-sequenced log files when log_path ends with a trailing slash, generating files like 2024-01-15-1.log and 2024-01-15-1.error.log.

Dynaconf Settings Schema in lifetrace/util/settings.py

Configuration defaults are declared using Dynaconf validators in lifetrace/util/settings.py:


# lifetrace/util/settings.py (excerpt)

Validator("logging.level", default="INFO")
Validator("logging.log_path", default="logs/")
Validator("logging.console_level", default="INFO")
Validator("logging.file_level", default="INFO")
Validator("logging.quiet_modules", default=[], is_type_of=list)

These keys allow users to override behavior via YAML configuration files or environment variables without touching source code.

How Logging Is Initialized at Runtime

Server Startup Sequence in lifetrace/server.py

When the Lifetrace backend starts, the entry point in lifetrace/server.py orchestrates the logging bootstrap:


# lifetrace/server.py

logging_config = settings.get("logging").copy()
logging_config["log_path"] = str(get_user_logs_dir()) + "/"
setup_logging(logging_config)          # ← applies Loguru configuration

logger = get_logger()

This pattern ensures the log directory is relocated to the user’s data folder (platform-specific) before sinks are created.

Dynamic Log Path Resolution

The _generate_log_file_path helper inside logging_config.py scans the target directory for existing files matching the current date pattern. It extracts the highest sequence number (the N in YYYY-MM-DD-N.log) and increments it, ensuring each process start writes to a fresh file rather than appending to an existing session.

Daily Log Rotation and Error Separation

Sequenced File Naming Convention

Unlike time-based rotation, Lifetrace uses launch-based sequencing. Each time the application starts, it creates a new pair of files:

  • 2024-01-15-1.log – All logs at file_level or higher
  • 2024-01-15-1.error.log – Only ERROR level and above

If the application restarts three times on the same day, you will see ...-1.log, ...-2.log, and ...-3.log, preventing log corruption and making debugging specific sessions trivial.

Separate Error Log Handling

The LoggerManager adds two distinct file sinks:

  1. Main sink: Captures everything from DEBUG (or configured file_level) up, retaining logs for 7 days.
  2. Error sink: Captures only ERROR and above, retaining logs for 30 days to ensure long-term visibility of critical issues.

Both sinks use a pipe-separated format (|) for easy parsing by log aggregation tools.

Usage Examples for Developers

Getting a Logger Instance

Any module within Lifetrace should import the configured logger via the utility function:


# Example: lifetrace/util/utils.py

from lifetrace.util.logging_config import get_logger

log = get_logger()
log.info("Utility module loaded")
log.debug("Configuration details: %s", config_data)

This ensures all modules share the same Loguru instance with consistent formatting and filtering.

Customizing Configuration via YAML

End users can override defaults by creating a config.yaml in their user configuration directory:


# ~/.config/lifetrace/config.yaml

logging:
  level: "DEBUG"
  console_level: "DEBUG"
  file_level: "INFO"
  log_path: "custom_logs/"
  quiet_modules:
    - "uvicorn"
    - "sqlalchemy"
    - "asyncio"

After restarting the server, Loguru will reinitialize with these settings, suppressing noisy third-party libraries and writing to the custom directory.

Summary

  • Lifetrace uses Loguru as its logging framework, wrapped by a custom LoggerManager in lifetrace/util/logging_config.py.
  • Configuration is driven by Dynaconf settings (logging.level, log_path, quiet_modules, etc.) defined in lifetrace/util/settings.py.
  • At runtime, lifetrace/server.py copies settings, resolves the user data directory, and calls setup_logging() to initialize sinks.
  • The system creates daily-sequenced log files (e.g., 2024-01-15-1.log) for each process start, plus a separate .error.log file for ERROR-level records.
  • Developers retrieve the logger via get_logger() to ensure consistent

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 →