Skip to main content

📜 simplibs-logger

PyPI Python Licence tests

A logger that works the moment you create it.

A ready-to-use logger built on the standard logging module, not instead of it: one constructor gives you a colored console, an optional rotating file, optional JSON output and a short way to write — logger.log_info("text %s", value). A wrong level, format or stream fails when you give it, not when the first record is written, and a record always points at the line of your code.

from simplibs.logger import SimpleLogger

logger = SimpleLogger(name="my_app", file_path="logs/app.log")

logger.log_info("Application started")
logger.log_success("Import finished: %d rows", 120)       # SUCCESS, level 25 — between INFO and WARNING
logger("Disk almost full", level="warning")               # the logger is callable

Works with simplibs-cli: resolve_verbosity(quiet=…, verbose=…) returns a level that SimpleLogger(level=…) accepts as it is.


🧭 The Core Philosophy

The standard logging module is powerful and starts empty: a logger with no handler, a default level that swallows info, a format that fails with a bare ValueError on the first record, a file that grows until the disk is full. Every program configures the same things by hand — and every copy forgets one. simplibs-logger is that configuration, written once and checked.

  • It works at once. The default level is INFO, the console is colored, and nothing needs configuring before log_info writes a line.
  • On top of logging, never beside it. A SimpleLogger wraps a real logging.Logger (logger.logger), and the handlers and formatters are standard classes you can attach to any logger yourself.
  • A wrong value fails early. Levels, names, formats, output kinds and streams are validated when they are given — with the very function the standard library will call later.
  • Build first, swap after. Every handler is built, and the file opened, before the existing logger is touched. A bad path leaves the previous setup in place, and handlers are closed, never leaked.
  • The right place in the traceback. File, line and function are those of the code that called the logger, for log_info, for logger("text") and for everything between.
  • Text for people, JSON for machines. A readable console and a JSON Lines file are one call.
  • Layers that only look left. definitions and annotations ← levels ← formatting ← handlers ← lifecycle ← SimpleLogger — every layer imports only from those before it.
SimpleLogger(level="loud")                       # -> raises: unknown level name
SimpleLogger(message_format="%(asctime)s %")     # -> raises: not a valid message format
SimpleLogger(max_bytes=0)                        # -> raises: zero would mean "never rotate"

📦 Installation

pip install simplibs-logger

Requires Python 3.11+. The runtime dependencies (installed automatically) are other simplibs libraries: simplibs-exception for the error card of a log file that cannot be opened, simplibs-object for the validated atoms, simplibs-validate for @validate_call and the validated types, simplibs-path for the log file's path, simplibs-style for the colors, and simplibs-file for the type of the encoding.


🚀 Quick Start in 60 Seconds

Level 1: A logger with no setup

from simplibs.logger import SimpleLogger

logger = SimpleLogger()

logger.log_debug("Not shown — the default level is INFO")
logger.log_info("Application started")
logger.log_success("Import finished: %d rows", 120)
logger.log_warning("Disk almost full")
logger.log_error("Request failed")
2026-10-24 12:00:00 | INFO     | simplibs | Application started
2026-10-24 12:00:00 | SUCCESS  | simplibs | Import finished: 120 rows
2026-10-24 12:00:00 | WARNING  | simplibs | Disk almost full
2026-10-24 12:00:00 | ERROR    | simplibs | Request failed

The records go to standard error, and the level names are colored in a terminal. The columns stay straight, because the padding counts the visible name, not the color codes.

Level 2: A file that rotates, closed properly

from simplibs.logger import SimpleLogger

with SimpleLogger(name="my_app", level="debug", file_path="logs/app.log",
                  max_bytes=1_000_000, backup_count=5) as logger:
    logger.log_debug("Connecting to %s", "db.local")
    logger.log_info("Ready")

logs/ and the file are created when missing. The file is plain text, never colored, and at 1 MB it becomes app.log.1 while five older files are kept. Leaving the with block closes the file.

Level 3: JSON for the machines

from simplibs.logger import SimpleLogger

logger = SimpleLogger(name="api", file_path="logs/api.jsonl", file_output="json", utc=True)

logger.log_info("request done", extra={"request_id": "r-7", "status": 200})

The console stays readable text; the file gets one JSON object per line:

{"time":"2026-10-24T12:34:56.789Z","level":"INFO","logger":"api","message":"request done","function":"<module>","file":"app.py","line":5,"request_id":"r-7","status":200}

Level 4: Exceptions, the switch and your own wiring

import logging
from simplibs.logger import SimpleLogger, build_console_handler

logger = SimpleLogger(name="importer", level="debug")

def import_rows():
    raise ValueError("row 3 is broken")

try:
    import_rows()
except ValueError:
    logger.log_exception("Import failed")           # ERROR + the traceback

if logger.is_enabled_for("debug"):                  # worth asking before an expensive message
    logger.log_debug("state: %s", {"rows": 3})

logger.enabled = False                              # silence it, whatever the level
logger.log_error("not written")

# the pieces work on any standard logger
third_party = logging.getLogger("third_party")
third_party.addHandler(build_console_handler(level="warning"))

🛠️ Architecture & Package Structure

src/simplibs/logger/
├── annotations/    ◄── Validated types for signatures (BackupCount, MaxBytes, LogStream)
├── definitions/    ◄── Validated atoms and fixed values (LoggerLevel, LoggerName, ... SUCCESS_LEVEL)
├── levels/         ◄── A name to a number, and the name SUCCESS (resolve_level, register_success_level)
├── formatting/     ◄── How a record looks (build_formatter, ColoredFormatter, JsonFormatter)
├── handlers/       ◄── Where records go (build_console_handler, build_file_handler)
├── lifecycle/      ◄── Create and release (create_logger, close_logger)
└── SimpleLogger.py ◄── The ready-to-use logger class

The root of the package exports everything — the logger, the building blocks, the atoms, the constants and the annotations — so one import line is all a program needs. The folders are plain packages for the code's own organization; nothing has to be imported from them. The internal _helpers and _validations of each folder are not exported.

from simplibs.logger import SimpleLogger, create_logger, close_logger
from simplibs.logger import build_console_handler, build_file_handler, build_formatter, JsonFormatter

📒 SimpleLogger — The Ready-to-Use Logger

The class most programs need: a configured logging.Logger behind a small calling interface. The constructor builds the console, the file, the colors and the JSON output; log_info, log_success, log_warning, … write the records, logger("text") writes at the default level, and log_exception adds the traceback. It has an enabled switch, is_enabled_for(level), set_level, close() and works as a context manager.

logger = SimpleLogger(file_path="logs/app.log")
logger.log_info("user %s logged in", name)

➡️ README_LOGGER_SIMPLELOGGER


🔄 Lifecycle — Create and Release

Two functions underneath SimpleLogger, for a program that wants a plain logging.Logger: create_logger builds one, validated, with no duplicate handlers however often it is called, and close_logger detaches and closes every handler so the log file is released.

logger = create_logger(name="my_app", level="debug", file_path="logs/app.log", propagate=True)
close_logger(logger)

➡️ README_LOGGER_LIFECYCLE


📮 Handlers — Where Records Go

Two builders of standard handlers: build_console_handler (standard error by default, any object with write as a stream) and build_file_handler (creates its folder and file, rotates with max_bytes, and turns a failed open into a structured card). A handler has no level of its own unless one is asked for, so the logger decides.

console = build_console_handler(level="warning", output="json")
file = build_file_handler("logs/app.log", max_bytes=1_000_000)

➡️ README_LOGGER_HANDLERS


🎨 Formatting — How a Record Looks

build_formatter is the one place a formatter is made and validated. ColoredFormatter colors the level name and keeps the columns straight; JsonFormatter writes each record as one line of valid JSON, with the fields of extra= as flat keys.

Output Formatter For
text logging.Formatter A file read by a person.
text, colored ColoredFormatter The console.
json JsonFormatter A log collector, jq, a container's stderr.

➡️ README_LOGGER_FORMATTING


📶 Levels — Numbers and Names

resolve_level turns a level written as a number or a name ("debug", "SUCCESS", 35) into the number, and register_success_level gives the number 25 the name SUCCESS in logging, once, without overwriting a name another library chose.

resolve_level("debug")        # -> 10
resolve_level(None)           # -> 20

➡️ README_LOGGER_LEVELS


🧬 Definitions — Validated Atoms and Fixed Values

The vocabulary of the library. Five validated atoms say what a value may be and what it is when nobody chose; three constants hold the fixed values behind them.

Name What it is
LoggerLevel A positive number or a level name; default INFO.
LoggerName A name that cannot reach the root logger; default "simplibs".
DateFormat A time.strftime format; default "%Y-%m-%d %H:%M:%S".
MessageFormat A %-style line format, syntax checked, field names free.
OutputFormat "text" (default) or "json".
SUCCESS_LEVEL, LEVEL_NAMES, OUTPUT_FORMATS The level 25, the six level names, the two output formats.

➡️ README_LOGGER_DEFINITIONS


🔖 Annotations — Types for Your Signatures

Three validated types that this library's signatures use and a caller can use in theirs, with @validate_call:

Type Accepts
BackupCount An int of at least one.
MaxBytes An int greater than zero, or None — never rotate.
LogStream Any object with write, or None — standard error.

➡️ README_LOGGER_ANNOTATIONS


📖 Quick Reference

📒 SimpleLogger — The Ready-to-Use Logger

Member Description / Parameters
SimpleLogger(...) Builds the logger (enabled, name, level, default_level, file_path, encoding, console, colored, console_level, file_level, stream, message_format, date_format, utc, max_bytes, backup_count, console_output, file_output, json_default).
log, logger(...) Writes at level or at default_level (message, *args, level=None, **kwargs).
log_debug … log_critical One method per level, incl. log_success (message, *args, **kwargs).
log_exception ERROR with the traceback (message, *args, **kwargs).
is_enabled_for Would a record of this level be written now (level=None).
set_level Changes the level of the logger (level).
enabled The switch; assignable.
logger, name, level The underlying logger, its name and level. Read-only.
close, with Closes every handler and stops writing.

➡️ README_LOGGER_SIMPLELOGGER


🔄 lifecycle/ — Create and Release

Function Description / Parameters
create_logger Builds a validated logging.Logger (the arguments of SimpleLogger without enabled and default_level, plus propagate=False).
close_logger Detaches and closes every handler of a logger (logger).

➡️ README_LOGGER_LIFECYCLE


📮 handlers/ — Where Records Go

Function Description / Parameters
build_console_handler A stream handler (level, stream, message_format, date_format, colored=True, utc, output, json_default).
build_file_handler A file handler, optionally rotating (file_path, level, encoding, message_format, date_format, utc, max_bytes, backup_count=3, output, json_default).

➡️ README_LOGGER_HANDLERS


🎨 formatting/ — How a Record Looks

Name Description / Parameters
build_formatter A validated formatter (message_format, date_format, colored=False, utc, output, json_default).
ColoredFormatter Colors the level name, padding included (fmt, datefmt).
JsonFormatter One JSON object per line (utc=False, default=None).

➡️ README_LOGGER_FORMATTING


📶 levels/ — Numbers and Names

Function Description / Parameters
resolve_level A level as a number (level=None).
register_success_level Names the number 25 SUCCESS, once.

➡️ README_LOGGER_LEVELS


🧬 definitions/ — Validated Atoms and Fixed Values

Name Description
LoggerLevel, LoggerName A level (default INFO); a logger name (default "simplibs").
DateFormat, MessageFormat A strftime format; a %-style line format.
OutputFormat "text" or "json".
SUCCESS_LEVEL, LEVEL_NAMES, OUTPUT_FORMATS 25; the six level names; ("text", "json").

➡️ README_LOGGER_DEFINITIONS


🔖 annotations/ — Types for Your Signatures

Type Description
BackupCount How many rotated files to keep; at least one.
MaxBytes A size limit in bytes, or None for no rotation.
LogStream A stream with write, or None for standard error.

➡️ README_LOGGER_ANNOTATIONS


🔌 Streams, Colors and Files

How the logger behaves where the output goes somewhere other than a terminal:

  • The console is standard error. Diagnostics belong there. A program that prints its log next to its own output passes stream=sys.stdout; any object with write works.
  • The color follows the style switch, not the stream. simplibs-style decides — from NO_COLOR, FORCE_COLOR, TERM=dumb and from whether standard output is a terminal. A program that redirects only one of the two passes colored=False, or calls set_styles_enabled(False).
  • Files and JSON are never colored. ANSI codes do not belong in a file.
  • The default level is INFO (the standard library starts at WARNING), and SUCCESS is the number 25.
  • One name, one logger. SimpleLogger(name="x") twice gives the same underlying logger and the second reconfigures the first. The default name "simplibs" is the parent of every simplibs.* logger, so the default logger also receives what other simplibs libraries log through plain logging. A SimpleLogger or create_logger logger does not pass its records up unless propagate=True.
  • Close what you open. close() and with release the log file — on Windows an open handler blocks deleting or rotating it. On Windows, rotation also needs the file to be open in one process only.

⚠️ Exceptions

The library defines one error of its own: a structured AccessError card, with a name that starts with LOGGER_. Everything else is refused by the libraries it is built on, each with its own structured card: an invalid level, name or format by the atoms (simplibs-object), a wrong argument type by @validate_call (simplibs-validate), and a path that cannot be prepared by ensure_file (simplibs-path).

Error name Card Wraps Raised when
LOGGER_FILE_OPEN_FAILED AccessError the caught OSError (its own type) The OS refuses to open the log file.

Because the card keeps the original exception type, except PermissionError still works.


  • simplibs-exception — the structured card of a log file that cannot be opened.
  • simplibs-object — SimpleConstant, the base of the validated atoms.
  • simplibs-validate — @validate_call and the validated types behind the annotations.
  • simplibs-path — ensure_file and PathLike for the log file.
  • simplibs-style — the colors of the level names and the switch that turns them off.
  • simplibs-file — EncodingName, the type of the file's encoding.
  • simplibs-cli — resolve_verbosity turns --quiet and -v into a level for this logger.

☯️ About simplibs

All libraries in the simplibs (Simple Libraries) ecosystem share a common engineering philosophy:

  • Dyslexia-friendly: We actively minimize cognitive load. Code is atomized into small, self-contained units, files are named directly after the logical task they perform, and explanations describe why something is designed, not just what it is.
  • Programmer's Zen: Nothing should be missing, and nothing should be superfluous. We value clean execution paths and robust, understandable code architectures over rushed, messy feature sets.
  • Defensive Style: We actively anticipate edge cases and failure modes so that only safe operational paths remain. Our code is built to degrade gracefully rather than crash unexpectedly.
  • Minimalism: Find the most direct path to the goal in as few operational steps as possible without taking shortcuts on safety, readability, or completeness.
  • Code as Craft: Code should be pleasant to look at, readable at a glance, and evoke structural harmony. We treat software engineering as a precision trade.

🤝 Contributing & Community

This is an open-source project built with love and care. We strongly believe in community collaboration and welcome any feedback, bug reports, or feature ideas!

  • Want to contribute? Feel free to open an Issue or submit a Pull Request.
  • Want to get in touch? If you'd like to discuss the project further, collaborate, or just say hello, feel free to open a GitHub Issue or start a Discussion.

📝 License

This library is released under the MIT License. Build great things!


Metadata

Release files for simplibs-logger 0.1.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 simplibs-logger 0.1.0
File Size Uploaded Provenance Actions
simplibs_logger-0.1.0.tar.gz 52.2 kB Without provenance Details for simplibs_logger-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for simplibs-logger 0.1.0
File Interpreter ABI Platform Actions
simplibs_logger-0.1.0-py3-none-any.whl Python 3 none any Details for simplibs_logger-0.1.0-py3-none-any.whl

Total release size: 111.8 kB

Release files / simplibs_logger-0.1.0.tar.gz

Download URL simplibs_logger-0.1.0.tar.gz
Size 52.2 kB
Tags Source
SHA-256 checksum
How to use checksums
821be5b122ee28c29e9fc8b7cb38e3ddeaea8523f95ce7f972e20b49ef108b73
BLAKE2b-256 checksum
How to use checksums
b947fe8885b672a2cffccef27f85f3047417a0290ce30f9a7dfcf939ff686378
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / simplibs_logger-0.1.0-py3-none-any.whl

Download URL simplibs_logger-0.1.0-py3-none-any.whl
Size 59.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
29b346b453e86f7551d4a37c1a6c824ed20c5de8f6bca6a08b6f6dd2017522a7
BLAKE2b-256 checksum
How to use checksums
1230e1489f291170cc47e6d9177e4d50e9ef2aac63553f31a9d789a35f95e3d3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Security for simplibs-logger 0.1.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

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