🧪 logger-lab
Logging, reimagined as a system.
logger-lab is a composable Python logging toolkit built around a simple idea:
logging should be modular, readable, and adaptable — for both humans and machines.
Instead of writing repetitive logging setup, you select from experiments, apply profiles, or compose your own logger by assembling them like a system.
🚀 Installation
pip install logger-lab
⚡ Quick Start
from logger_lab import get_logger
logger = get_logger(__name__, profile="INVESTIGATOR")
logger.info("System online")
logger.debug("Inspecting state")
logger.error("Something broke")
Summary of usage
Both enums and strings can be used as parameters for both get_logger() and lab():
import logging
from logger_lab import lab, get_logger, ExperimentType
# Profiles (prebuilt combinations):
profile_logger = get_logger(name="profile_test", profile="conspiracy_theorist")
# Experiments (single handler factories):
experiment_logger = get_logger(name="experiment_test", experiment=ExperimentType.MINIMALIST)
# Fluent builder (custom composition):
built_logger = (
lab()
.with_experiment('STANDARD')
.with_experiment(ExperimentType.FILE)
.with_level(logging.DEBUG)
.build(__name__)
)
🧪 Experiments
Experiments are atomic logging behaviours — pure functions that return a list of configured handlers.
Each experiment controls exactly one thing: how logs are formatted and where they go.
| Experiment | Handler | Description |
|---|---|---|
standard |
RichHandler |
Colourised console output with traceback support |
minimalist |
StreamHandler |
Plain LEVEL: message — warnings only by default |
verbose |
StreamHandler |
Full context: timestamp, module, function, line |
file |
FileHandler |
Persistent plain-text log at logs/app.log |
rotating_file |
RotatingFileHandler |
Auto-rotates at 5 MiB, keeps 3 backups |
ai |
StreamHandler (stderr) |
Structured JSON — Mosquito Lab Standard v1 |
Using a single experiment
from logger_lab import get_logger
logger = get_logger(__name__, experiment="minimalist")
logger.info("Ready")
🧫 Profiles
Profiles are prebuilt combinations of experiments tuned for common use cases.
| Profile | Experiments | Use case |
|---|---|---|
observer |
minimalist |
Production — warnings and above only |
investigator |
standard + file |
Development — Rich console + disk |
conspiracy_theorist |
verbose + file + rotating_file |
Deep archival — nothing missed |
ai_agent |
ai |
Structured JSON for pipelines |
from logger_lab import get_logger, ProfileType
payload = "super dangerous and malicious payload!"
logger = get_logger(__name__, profile=ProfileType.CONSPIRATOR)
logger.debug("Payload received: %s", payload)
logger.error("Unexpected response", exc_info=True)
🧬 Custom Composition
For full control, build your logger like a system:
from logger_lab import lab, ExperimentType
logger = (
lab()
.with_experiment(ExperimentType.MINIMALIST)
.with_experiment(ExperimentType.FILE)
.with_level("DEBUG")
.build(__name__)
)
Mix a profile with additional experiments:
from logger_lab import lab, ExperimentType, ProfileType
logger = (
lab()
.with_profile(ProfileType.INVESTIGATOR)
.with_experiment(ExperimentType.AI)
.with_level("INFO")
.build(__name__)
)
🤖 AI Logging (Core Feature)
logger-lab includes a structured logging format designed for AI systems.
Logs become machine-readable events, not just text.
Example Output
{
"timestamp": "2026-05-05T12:00:00+00:00",
"level": "INFO",
"message": "User logged in",
"source": {
"module": "auth",
"function": "login",
"line": 88
},
"extra": {
"event": "user_login",
"context": { "user_id": 42 },
"tags": ["auth"]
}
}
Usage
Use log_event() — it constructs a fresh extra dict on every call so successive calls never share mutable state:
from logger_lab import get_logger, log_event, ProfileType
import logging
logger = get_logger(__name__, profile=ProfileType.AGENT)
log_event(
logger, logging.INFO, "User logged in",
event="user_login",
context={"user_id": 42},
tags=["auth"],
)
🚨 Error Handling
All exceptions inherit from LabError so you can catch broadly or precisely.
LabError
├── LabRegistryError
│ ├── ExperimentNotFoundError — valid ExperimentType not registered
│ ├── ProfileNotFoundError — valid ProfileType not registered
│ ├── InvalidExperimentName — unrecognised experiment string
│ └── InvalidProfileName — unrecognised profile string
├── LabConfigurationError
│ ├── InvalidLevelError — bad level string or int
│ ├── HandlerConfigurationError — handler failed to initialise
│ │ └── LogDirectoryError — log directory mkdir/access failure
│ ├── ExperimentRegistrationError — callable doesn't satisfy ExperimentFactory
│ └── ProfileRegistrationError — callable doesn't satisfy ProfileFactory
└── BuilderError — build() called with nothing queued
Broad catch
from logger_lab import get_logger, LabError
try:
logger = get_logger(__name__, profile="typo")
except LabError as exc:
print(f"logger-lab error: {exc}")
Precise catch
from logger_lab import get_logger, InvalidProfileName, BuilderError
try:
logger = get_logger(__name__, profile="typo")
except InvalidProfileName as exc:
print(f"Unknown profile: {exc}") # lists valid names in the message
except BuilderError as exc:
print(f"Builder misconfigured: {exc}")
🏗️ Architecture
logger_lab/
├── __init__.py ← public API: get_logger(), lab(), log_event()
├── core/
│ ├── enums.py ← ExperimentType, ProfileType
│ ├── registry.py ← EXPERIMENTS + PROFILES dicts, validated registration
│ └── builder.py ← LabBuilder fluent interface + lab() factory
├── experiments/ ← atomic handler factories (level) → list[Handler]
│ ├── standard.py ← RichHandler
│ ├── minimalist.py ← StreamHandler, warnings only
│ ├── verbose.py ← StreamHandler, full context
│ ├── file.py ← FileHandler
│ ├── rotating_file.py ← RotatingFileHandler
│ └── ai.py ← StreamHandler + JSONFormatter
├── profiles/ ← prebuilt logger configurations
│ ├── _base.py ← _build_profile() shared skeleton
│ ├── observer.py
│ ├── investigator.py
│ ├── conspiracy_theorist.py
│ └── ai_agent.py
├── theories/ ← explore different theories to invent new experiments
│ ├── _test_theory.py ← test a theory (even I don't know what'll happen)
│ ├── my_stuff_exp.py
│ └── your_stuff_exp.py
└── logging_kernel/ ← shared infrastructure
├── errors.py ← full exception hierarchy
├── formatters.py ← JSONFormatter, log_event(), formatter factories
├── handlers.py ← _configure_handler(), get_log_dir()
└── normalisers.py ← normalises all params,
🧬 Philosophy
logger-lab is built on three principles:
- Modularity — Logging behaviour should be reusable and composable.
- Clarity — Logs should be easy to read and understand.
- Structure — Logs should be usable as data, not just text.
Logs are not just for debugging. They are inputs for analysis, automation, and intelligence.
🧪 Experimental Features
Some features live in the experimental zone (theories):
from logger_lab import get_logger
from logger_lab.core.enums import TheoryType
# THEORIES (single handler factories):
theory_logger = get_logger(name="doom", theory=TheoryType.TIMED_FILE)
These are unstable and may change.
🤝 Contributing
Contributions are welcome.
Adding a new experiment
- Create
logger_lab/theories/your_name_exp.py - Define
your_name_experiment(level: int = DEBUG, **kwargs) -> list[logging.Handler] - Add the enum value to
TheoryTypeincore/enums.py - Manually register it in the THEORIES registry
- Test in
_test_theory.py - Document its purpose and behaviour
- After review, the Lab will add it to experiments logic
Adding a new profile
Currently just on a suggestion basis. I don't know about adding experimental logic for a profile
🧭 Roadmap
- More experiments (
async,http,db,performance) - Advanced profiles
- AI-assisted debugging tools
- Distributed tracing support
-
py.typedmarker + full type stub coverage
🧑💻 Author
Mosquito Lab (Cyber-Smoke) 📧 mosquitolab2024@protonmail.com 🔗 github.com/Mosquito-Lab/logger-lab
📄 License
MIT LICENSE
🌱 Status
STABLE RELEASE: v0.1.1
- Still in active development. New experiments, profiles, and capabilities are being added continuously.
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 logger_lab-0.1.1.tar.gz.
File metadata
- Download URL: logger_lab-0.1.1.tar.gz
- Upload date:
- Size: 28.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.9.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
846743885e2e382b1c18ecfd9399d6596fcf7811231e2ced835ab5d3a77ff442
|
|
| MD5 |
4899b6fc3720571f0756cce426c2baf8
|
|
| BLAKE2b-256 |
a6c3c183d5e2962ac3b17089133cec59e30264d5b624420ae11e1f7364e1c86e
|
File details
Details for the file logger_lab-0.1.1-py3-none-any.whl.
File metadata
- Download URL: logger_lab-0.1.1-py3-none-any.whl
- Upload date:
- Size: 37.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.9.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6eee0210ceeecbc45a899212c74963949eaa030e9ee20a15054a0be082a4f683
|
|
| MD5 |
5540887f34a1a6078b06f90589b8dc76
|
|
| BLAKE2b-256 |
21463a52e656858c8b3d085c205256e944451a5d59a1ff8505356e301333c92c
|