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.
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, ormiddle, 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, andlog_io, each accepting anidentifieror a pre-bound logger. - Small and safe to depend on. Runtime deps are just
loguruandcolorama; the package configures no sinks at import time and never prints.
Installation
pip install loggerplusplus
# or
poetry add loggerplusplus
Requires Python 3.9+.
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 |
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.
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
add, remove, # sink management
catch, opt, # loguru helpers with identifier binding
log_timing, log_io, # timing / I/O decorators
__version__,
)
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
└── formats/ BaseFormat + Classic · Short · Ops · Debug · Minimal
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
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loggerplusplus-1.1.0.tar.gz.
File metadata
- Download URL: loggerplusplus-1.1.0.tar.gz
- Upload date:
- Size: 51.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c091bf1487b96ce87560a9751326993b461f7704912545405a5bb366dd77f530
|
|
| MD5 |
60ef85f7590f630d2ab9bbb3a3c2e42c
|
|
| BLAKE2b-256 |
84a4888ce6ef6df6f0e206c68c4c321124419ffd3d415402ac3573561dd6f276
|
Provenance
The following attestation bundles were made for loggerplusplus-1.1.0.tar.gz:
Publisher:
publish.yml on Florian-BARRE/LoggerPlusPlus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loggerplusplus-1.1.0.tar.gz -
Subject digest:
c091bf1487b96ce87560a9751326993b461f7704912545405a5bb366dd77f530 - Sigstore transparency entry: 2701347398
- Sigstore integration time:
-
Permalink:
Florian-BARRE/LoggerPlusPlus@f942384eb5c7b621bd6fd63066c4670abdc416bb -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/Florian-BARRE
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f942384eb5c7b621bd6fd63066c4670abdc416bb -
Trigger Event:
push
-
Statement type:
File details
Details for the file loggerplusplus-1.1.0-py3-none-any.whl.
File metadata
- Download URL: loggerplusplus-1.1.0-py3-none-any.whl
- Upload date:
- Size: 60.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e957eb8218860ae0f149574b06d35c85dac4a3a18529b85ae3eeb6e6d0b992c6
|
|
| MD5 |
e51e3064f4e946961624d9073fcf7202
|
|
| BLAKE2b-256 |
5be5d03631e5a2d300425d77d50aad694956932e9e23cba1267752994c5555b4
|
Provenance
The following attestation bundles were made for loggerplusplus-1.1.0-py3-none-any.whl:
Publisher:
publish.yml on Florian-BARRE/LoggerPlusPlus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loggerplusplus-1.1.0-py3-none-any.whl -
Subject digest:
e957eb8218860ae0f149574b06d35c85dac4a3a18529b85ae3eeb6e6d0b992c6 - Sigstore transparency entry: 2701347641
- Sigstore integration time:
-
Permalink:
Florian-BARRE/LoggerPlusPlus@f942384eb5c7b621bd6fd63066c4670abdc416bb -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/Florian-BARRE
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f942384eb5c7b621bd6fd63066c4670abdc416bb -
Trigger Event:
push
-
Statement type: