Skip to main content

advlog

Python Version License Version

A Python logging library with colored terminal output, file management, progress tracking, and ML training utilities, built on top of Rich.

Personal project notice: This package was written for personal development use. Update frequency and feature scope may be limited. Contributions and suggestions are welcome.

Features

  • Rich Console Output — Colored terminal logging via the Rich library
  • Flexible Configuration — LoggerConfig dataclass for per-logger overrides; simple initialize() / get_logger() API for common cases
  • File Logging — Separate or merged file strategies with size-based rotation
  • Structured Output — Optional JSON Lines file with your own fields (extra=, bound context) for parsing and querying
  • Progress Tracking — Integrated progress bars via ProgressTracker
  • Multi-Module Coordination — LoggerManager for consistent logging across modules
  • ML/Training Utilities — TrainingLogger plugin for experiment logging
  • Smart File Naming — Timestamped, daily, and incremental log file naming

Installation

pip install advlog-core

With all optional features:

pip install "advlog-core[all]"

The PyPI package name is advlog-core; import as import advlog.

Quick Start

One-liner

from advlog import get_logger

log = get_logger(__name__)
log.info("Application started")
log.warning("High memory usage detected")
log.error("Database connection failed")

Initialize once, use everywhere

from advlog import initialize, get_logger, get_progress

initialize(
    output_dir="./logs",
    session_name="myapp",
    log_level="DEBUG",
    show_location=True,
)

log = get_logger(__name__)
log.info("Initialized")

progress = get_progress()
with progress:
    task = progress.add_task("Processing", total=100)
    for i in range(100):
        progress.update(task, advance=1)

Things worth knowing:

  • Loggers obtained before initialize() are console-only; they pick up the log file as soon as initialize() runs.
  • Calling initialize() again applies the new settings in full to every existing logger. In particular, enable_file_logging=False detaches and closes the current log file.
  • use_color=False turns color off for everything drawn on the shared console, progress bars included.
  • get_logger(name, log_level="ERROR") sets the level even if that logger already exists.

Per-logger configuration with LoggerConfig

from advlog import LoggerManager, LoggerConfig

manager = LoggerManager(shared_console=True, shared_file="logs/app.log")

# Default registration
api_logger = manager.register_logger("api")

# Override with LoggerConfig
db_logger = manager.register_logger(config=LoggerConfig(
    name="database",
    log_level="DEBUG",
    log_file="logs/db.log",
    show_location=True,
))

api_logger.info("API server started")
db_logger.debug("Executing query: SELECT ...")

LoggerConfig fields and where they apply:

Field Applies to
name, log_level, propagate, console_output, show_location The logger itself
log_file, file_mode, file_format, max_file_size, backup_count, log_format, date_format, encoding The logger's own file (log_file). file_format, max_file_size and backup_count fall back to the manager's values when left as None
use_color, enable_rich_tracebacks The logger's own console handler, i.e. only with LoggerManager(shared_console=False)
use_accelerate Drops this logger's records on non-main processes of a Hugging Face accelerate run, once Accelerator() has been created

Register a group of loggers at once

from advlog import create_logger_group

loggers = create_logger_group(
    ["api", "database", "auth"],
    shared_console=True,
    file_strategy="merged",
)

loggers["api"].info("Request received")
loggers["database"].debug("Query executed")
loggers["auth"].warning("Invalid login attempt")

Formatters

Four formatters are available:

Class Description
RichColorFormatter Wraps messages in Rich color markup by log level
PlainFormatter Plain text, no color codes
IndentedFormatter Indents continuation lines of multi-line messages
JSONFormatter Outputs each record as a JSON object, with extra= fields under "extra"
from advlog import JSONFormatter
import logging

handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logging.getLogger("myapp").addHandler(handler)

File Logging

from advlog import create_file_handler

handler = create_file_handler(
    log_file="logs/app.log",
    mode="a",
    show_location=True,
)

Files hold plain text: paired Rich tags such as [bold red]alert[/bold red] color the console but are removed from file output. Brackets that are not a closed style pair (arr[i], [1/3], [epoch 1]) are left as written. Pass strip_markup=False to create_file_handler() to keep the tags.

Rotation

For long runs, cap the file size. When the file reaches max_file_size bytes it is renamed to app.log.1 (older ones shift to .2, .3, ...) and a fresh file is started; backup_count old files are kept.

from advlog import initialize

initialize(
    output_dir="./logs",
    session_name="train",
    max_file_size=50 * 1024 * 1024,  # 50 MB
    backup_count=3,
)

max_file_size / backup_count are also accepted by LoggerManager, LoggerConfig, create_file_handler() and create_file_handlers(), and apply to the .jsonl file too. A rotating file is always appended to, so file_mode="w" has no effect on it.

Structured (JSON Lines) output

Set file_format to get a machine-readable log next to (or instead of) the text log:

file_format Files written
"text" (default) app.log
"json" app.jsonl
"both" app.log and app.jsonl
from advlog import initialize, get_logger

initialize(output_dir="./logs", session_name="train", file_format="both")

log = get_logger(__name__)
log.info("Run started", extra={"lr": 1e-3, "batch_size": 32})

The .jsonl file holds one JSON object per line. Anything passed via extra= is stored under the "extra" key:

{"timestamp": "2026-03-06T14:30:22.123456+08:00", "level": "INFO", "logger": "__main__", "message": "Run started", "module": "train", "function": "<module>", "line": 6, "extra": {"lr": 0.001, "batch_size": 32}}

Values JSON cannot represent (paths, sets, NumPy arrays, tensors, arbitrary objects) are converted rather than dropped, and NaN/Infinity are written as null so every line stays valid JSON. file_format is also accepted by LoggerManager, LoggerConfig, and create_logger_group; create_file_handlers() builds the handlers directly.

import pandas as pd

df = pd.read_json("logs/train.jsonl", lines=True)
errors = df[df["level"] == "ERROR"]

Lines meant only for human eyes (separators, banners) can be kept out of the .jsonl file:

log.info("=" * 60, extra={"text_only": True})  # console and text log only

Context fields on every record

Bind fields once and they are attached to every record from every logger, as if passed via extra= each time. This is what lets you tell runs apart after merging their logs.

from advlog import initialize, bind_context, unbind_context, clear_context

initialize(session_name="train", file_format="both", context={"run_id": "exp-42", "git_sha": "ab6e876"})

bind_context(epoch=3)     # add or update fields later
unbind_context("epoch")   # remove some
clear_context()           # remove all
{"timestamp": "...", "level": "INFO", "logger": "train", "message": "step done", "module": "train", "function": "fit", "line": 88, "extra": {"run_id": "exp-42", "git_sha": "ab6e876", "epoch": 3}}

An explicit extra= on a call wins over a bound field of the same name. Bound fields are also available to custom text formats, e.g. LoggerConfig(log_format="%(asctime)s %(run_id)s %(message)s"). Names of built-in record attributes (message, name, levelname, ...) are rejected.

Smart log file naming

from advlog import LogNamingStrategy

# Timestamp-based:  logs/2026-03-06/20260306_143022_app_prod.log
log_file = LogNamingStrategy.timestamped("app", suffix="prod")

# Daily directory:  logs/2026-03-06/myapp_errors.log
log_file = LogNamingStrategy.daily("myapp", suffix="errors")

# Incremental (no conflicts):  logs/backup_data.log  →  backup_data_1.log ...
log_file = LogNamingStrategy.incremental("backup", suffix="data")

Progress Tracking

from advlog import ProgressTracker

with ProgressTracker() as progress:
    download = progress.add_task("Downloading", total=100)
    process  = progress.add_task("Processing",  total=50)

    for _ in range(100):
        progress.update(download, advance=1)

    for _ in range(50):
        progress.update(process, advance=1)

ML Training Utilities

from advlog import TrainingLogger, get_logger

logger = get_logger(__name__)
trainer = TrainingLogger(logger)

trainer.log_train_step(
    epoch=1,
    total_epochs=10,
    batch=100,
    total_batches=1000,
    loss_dict={"loss": 0.4231, "accuracy": 0.872},
    time_elapsed=45.2,
    additional_metrics={"lr": 1e-3},
)

log_configuration, log_train_step, and log_evaluation_results attach their data as extra fields, so with file_format="json" or "both" each one becomes a queryable record (extra.event is "config", "train_step", or "evaluation"). Their separator and per-key lines are marked text_only, so the .jsonl file gets one record per call rather than one per printed line.

Records logged through TrainingLogger report the file and line of your call (visible with show_location=True and in the JSON module / function / line fields), not a location inside the helper.

Exception Logging

from advlog import setup_exception_logging

# Install a sys.excepthook that logs all uncaught exceptions
setup_exception_logging()

The traceback goes wherever your other logs go: the console and the log file(s) configured by initialize(), including the .jsonl file (as an ERROR record with an exception field). Pass your own logger to route it elsewhere. KeyboardInterrupt is left to Python's default handling.

Real-World Example

See examples/real_world_demo/ for a complete multi-module application demonstrating global initialization, cross-module loggers, progress tracking, error handling, and organized file output.

python -m examples.real_world_demo.main
python -m examples.real_world_demo.structured_demo   # JSON Lines output and querying it

Dependencies

Required

  • Rich — Terminal formatting and colored output

Optional

Extra tag Package Feature
config omegaconf Advanced config file parsing
torch torchinfo Model structure visualization
distributed accelerate Main-process-only logging in multi-GPU runs (LoggerConfig(use_accelerate=True))
pip install "advlog-core[config]"
pip install "advlog-core[torch]"
pip install "advlog-core[distributed]"

Contributing

Contributions are welcome — please feel free to open an issue or submit a pull request.

License

Apache License 2.0 — see LICENSE for details.

Acknowledgments

Metadata

Release files for advlog-core 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for advlog-core 0.3.1
File Size Uploaded Provenance
advlog_core-0.3.1.tar.gz 37.2 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for advlog-core 0.3.1
File Interpreter ABI Platform
advlog_core-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 88.1 kB

Release files / advlog_core-0.3.1.tar.gz

Download URL advlog_core-0.3.1.tar.gz
Size 37.2 kB
Tags Source
SHA-256 checksum
How to use checksums
bfad3d39f71285177f212673a842ea04f74a350b93a89d9c9aa52803a3aac489
BLAKE2b-256 checksum
How to use checksums
93a1e54e2b3bdb7826281d643812d1ca9dbb6cd7292cd95275469a68971e4ba6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / advlog_core-0.3.1-py3-none-any.whl

Download URL advlog_core-0.3.1-py3-none-any.whl
Size 50.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9299036376e6abd8df4c7579726eb099a2be17cec20ca6690f0c59f2694b998e
BLAKE2b-256 checksum
How to use checksums
3aaf19ae5147d09d3ba550cea1637db6d3a1c10aca2f0047ef3f9d8d3c4ae6cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Security for advlog-core 0.3.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for advlog_core-0.3.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page