Skip to main content

LoggerPlusPlus

ALIGNED, READABLE LOGGING

Enhanced logging for Python, built on Loguru — keep Loguru's simple, powerful API and add auto-aligned identifier columns, width-aware truncation, ready-made colorized formats, and convenience decorators. A small, dependency-light library meant to be shared across every service in a stack.

PyPI Python CI CodeQL License

Configure a sink with an auto-width format, bind an identifier, and log. Identifier columns align themselves to the longest value seen, overflow is truncated where you ask, and the whole API stays a transparent, drop-in proxy over Loguru.


Why LoggerPlusPlus

  • Columns that align themselves. Write {identifier:<auto} in a format and every identifier is padded to the widest one seen so far — no manual widths, no jitter between lines.
  • Truncation you control. Cap a field with [width] and choose the side: left, right, or middle, each with an ellipsis.
  • Ready-made formats, resolved by name. Five colorized layouts (Classic, Short, Ops, Debug, Minimal) that a service can select from configuration.
  • A transparent Loguru proxy. Everything Loguru exposes (sinks, levels, filters, backtraces, bind, contextualize, ...) remains available; a few names are enhanced, none are hidden.
  • Convenience decorators. catch, opt, log_timing, and log_io, each accepting an identifier or a pre-bound logger.
  • Small and safe to depend on. Runtime deps are just loguru and colorama; the package configures no sinks at import time and never prints.

Installation

pip install loggerplusplus
# or
poetry add loggerplusplus

Requires Python 3.9+. Big ASCII-art banners (Banner.figlet) need the optional extra:

pip install 'loggerplusplus[banners]'   # adds pyfiglet; box/rule banners work without it

Quickstart

import sys

from loggerplusplus import add, remove, logger

remove()  # drop Loguru's default handler first
add(
    sink=sys.stderr,
    level="DEBUG",
    format=(
        "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
        "<level>{level.name:<8}</level> | "
        "[<blue>{identifier:<auto[18~middle]}</blue>] | "
        "<level>{message}</level>"
    ),
)

logger.bind(identifier="MAIN").info("Hello from main")
2025-09-25 14:03:12.345 | INFO     | [MAIN] | Hello from main

logger is the enhanced, ready-to-use singleton (a drop-in for Loguru's logger). The same API is also available on the loggerplusplus singleton and as the top-level functions add / remove / catch / opt / log_timing / log_io.


Auto-width alignment

{identifier:<auto} is not valid Loguru syntax on its own — LoggerPlusPlus rewrites it. The auto width tracks the longest value observed for that field over the process lifetime and pads every line to it, so a column never shrinks and never jitters. LoggerClass (below) pre-registers its identifier so alignment is correct from the very first line.

[MAIN]           | starting
[WORKER]         | working
[LONG-SERVICE-A] | columns grew, and stay aligned

The token grammar is {field:<align><width>[cap~trunc]}:

Part Values Meaning
align < > ^ left / right / center (default <)
width auto or an integer grow-to-fit, or a fixed width
cap integer, in [...] maximum width
trunc left right middle which side to cut when overflowing, with …

field may be a record attribute (level.name), a dotted path, or extra[key].


Truncation

"{identifier:<auto[18~middle]}"   # grow to fit, but never wider than 18, cut in the middle
"{name:<20~right}"                 # fixed width 20, cut the tail
"{extra[service]:>auto[12~left]}"  # right-aligned, capped at 12, cut the head

VeryLongServiceName capped at 12 with ~middle renders as VeryL…Name.


Ready-made formats

Each format is a subclass of str, so an instance is a format string and can be passed straight to add(format=...). Formats are resolved by name, which is convenient for configuration:

import sys

from loggerplusplus import loggerplusplus, formats

loggerplusplus.remove()
loggerplusplus.add(sink=sys.stdout, level="DEBUG", format=formats.ShortFormat())

# Select one by name (e.g. from an env var), with a safe fallback:
chosen = "OpsFormat"
loggerplusplus.add(sink=sys.stdout, format=getattr(formats, chosen, formats.DebugFormat)())
Format Contents
ClassicFormat time, level, identifier, source name:line, message
ShortFormat time, level, identifier, message
OpsFormat time, level, identifier, process/thread, message
DebugFormat time, level, identifier, process/thread, source name:line, message
MinimalFormat identifier, message
PlainFormat Short layout, uncolored by default — for file sinks
FileFormat Classic layout with name:line, uncolored by default — for file sinks

Every format accepts overrides such as colorized=False (plain output for file sinks) and per-field widths (level_width=, identifier_width=, ...). See docs/FORMATS.md.


LoggerClass

Any class can get a bound self.logger whose identifier defaults to the class name:

from loggerplusplus import LoggerClass

class Service(LoggerClass):
    def run(self):
        self.logger.info("Service is running")

Service().run()
Service(identifier="Custom").run()   # explicit identifier

Decorators

from loggerplusplus import catch, log_timing, log_io

@catch(identifier="WORKER", level="ERROR")
def risky():
    raise RuntimeError("Boom!")

@log_timing(identifier="TASK", exit_message="Finished {func} in {duration:.2f}s")
@log_io(identifier="CALC", log_args=True, log_return=True)
def compute(a, b):
    return a + b

catch also works as a context manager; opt accepts either an identifier or a pre-bound logger. See docs/USAGE.md.


Banners & message transforms

Every level method takes an optional transform (any str -> str) applied to the message before it is emitted, and an optional raw (emit without the timestamp/level prefix). Banner bundles ready-made transforms — big ASCII art, Unicode boxes, rules — and transforms exposes the general concept.

from loggerplusplus import logger, Banner, transforms

logger.info("Config loaded", transform=Banner.box())          # zero-dependency Unicode box
logger.info("SECTION", transform=Banner.rule())               # ──────── SECTION ────────
logger.info("DEPLOY", transform=Banner.figlet(font="slant"), raw=True)   # big art (extra)
logger.info("{user} in", user="alice", transform=str.upper)   # ALICE IN — any str->str works
logger.warning("done", transform=transforms.chain(str.upper, Banner.box(double=True)))

Banner.figlet needs the banners extra; Banner.box/Banner.rule and the transform mechanism itself are dependency-free. The keywords work on the singleton, on bind() loggers and on LoggerClass.logger alike. See docs/USAGE.md.


Architecture

add(format=str)
   ├─ parser.prepare_auto_format()   rewrite {identifier:<auto} into {extra[__lp_auto_N__]}
   ├─ runtime.compose_filter()       loguru calls this once per record, before formatting —
   │                                 the injection point for the padded/truncated value
   ├─ registry (_AUTO)               thread-safe max-observed width per field (monotonic)
   └─ loguru formatting

A fuller explanation is in docs/REFERENCE.md.


Public API

from loggerplusplus import (
    loggerplusplus,   # enhanced singleton (drop-in for loguru's logger)
    logger,           # alias of the singleton
    LoggerPlusPlus,   # the proxy class
    LoggerClass,      # mixin providing self.logger
    formats,          # ClassicFormat, ShortFormat, OpsFormat, DebugFormat, MinimalFormat, PlainFormat, FileFormat
    add, remove,      # sink management
    catch, opt,       # loguru helpers with identifier binding
    log_timing, log_io,  # timing / I/O decorators
    Banner,           # banner transform factories: figlet / box / rule / preset
    transforms,       # message-transform toolkit (Transform, chain, indent, upper, lower)
    __version__,
)

Level methods also accept transform= (a str -> str) and raw= keywords — see Banners & message transforms.

The public surface is a stability contract: names are added, never renamed or removed without a major version bump. Full signatures in docs/REFERENCE.md.


Documentation

Document Contents
docs/INSTALL.md Installation, requirements, and version support
docs/USAGE.md Task-oriented guide: sinks, formats, decorators
docs/FORMATS.md The five formats and the auto-width token grammar
docs/REFERENCE.md API reference and the auto-width pipeline internals
CHANGELOG.md Release history (maintained by release-please)
CONTRIBUTING.md Development workflow, the CI gate, and releasing

Project layout

src/loggerplusplus/
├── __init__.py        public API
├── proxy.py           LoggerPlusPlus — transparent proxy over loguru.logger
├── api.py             add() — wires the format parser into loguru.add
├── parser.py          auto-width token grammar
├── runtime.py         per-record width / truncation computation
├── registry.py        thread-safe max-observed width
├── logger_class.py    LoggerClass mixin
├── decorators.py      catch · opt · log_timing · log_io
├── transform_proxy.py transform=/raw= keyword on level methods · TransformProxy
├── transforms.py      Transform concept · chain/indent/upper/lower · re-exports Banner
├── banners.py         Banner — figlet / box / rule / preset transform factories
├── context.py         bind_context · new_id · otel_context (correlation, optional OTel)
├── structured.py      add_json — structured/JSON sink
├── intercept.py       intercept_std_logging · InterceptHandler (stdlib bridge)
├── bootstrap.py       setup · configure_from_env
├── width.py           registry controls · testing.py — capture helper
└── formats/           BaseFormat + Classic · Short · Ops · Debug · Minimal · Plain · File; Theme

Development

poetry install
poetry run black src tests test_module
poetry run ruff check src tests test_module
poetry run mypy src
poetry run pytest            # 100% coverage; the CI gate is 95%

The CI matrix runs the suite on Python 3.9–3.13 across Linux, macOS, and Windows. See CONTRIBUTING.md.


License

LoggerPlusPlus is licensed under the GNU General Public License v3.0 — see LICENSE. It builds on top of Loguru (MIT).

Author

Created and maintained by Florian BARRE. Website · LinkedIn · GitHub

Metadata

Release files for loggerplusplus 1.2.0

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

Source distribution (sdist)

Source distribution for loggerplusplus 1.2.0
File Size Uploaded
loggerplusplus-1.2.0.tar.gz 58.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for loggerplusplus 1.2.0
File Interpreter ABI Platform
loggerplusplus-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 126.0 kB

Release files / loggerplusplus-1.2.0.tar.gz

Download URL loggerplusplus-1.2.0.tar.gz
Size 58.1 kB
Tags Source
SHA-256 checksum
How to use checksums
1ff7f65eba6cb09645dcac796b8f8e786b14aecc297f2b55ddb01429495c7ce2
BLAKE2b-256 checksum
How to use checksums
ce275c19d41dfa74c738faf9c9218831feb7b478584a9b254f3dac81a2042582
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 Sep 16, 2026.

Transparency log

Release files / loggerplusplus-1.2.0-py3-none-any.whl

Download URL loggerplusplus-1.2.0-py3-none-any.whl
Size 67.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
592dfffa4afeae0a52fcf6e8c5b9a51481e2d1114ea4384a570a7b5007e78cd3
BLAKE2b-256 checksum
How to use checksums
e3e06c538dc6540d78a848b34f1ad6c6dd4d25f98dda0b382fe6aafae855e116
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 Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.2.0 This release

2 release files

1.1.0

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

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