A lightweight, zero-setup decorator for logging ML experiments to a JSONL file.
Project description
This tool is for the solo data scientist, student, or hobbyist in a Jupyter Notebook who just wants to keep track of their experiments without setting up a database or heavy framework.
Quick Setup
Get started in 30 seconds.
1. Install from PyPI:
pip install littlelogger
2. Import and use the decorator:
from littlelogger import log_run
# NOTE: for this to work, we need the training function to input the parameters that need to be logged
# and output the performance metric e.g., f1_score, accuracy_score, etc.
@log_run(log_file="my_experiments.jsonl")
def train_model(learning_rate, n_estimators):
# Your training logic...
f1 = 0.80
return {"f1_score": f1}
# Just run your function as normal
train_model(0.1, 100)
train_model(0.05, 200)
3. Check your results:
A my_experiments.jsonl file will be created, logging every run.
See it in Action
Want to see how it works? Check out the Demo Notebook to see a real-world example of logging experiments from different models into one file.
The Problem
You're tuning a model and your notebook looks like this:
# metrics = train_model(max_depth=5, n_estimators=100) # f1: 0.82
# metrics = train_model(max_depth=7, n_estimators=100) # f1: 0.81
metrics = train_model(max_depth=5, n_estimators=200) # f1: 0.83
print(metrics)
A day later, you've lost track of your best run.
The Solution
Wrap your function with the @log_run decorator.
from littlelogger import log_run
@log_run(log_file="experiment_log.jsonl")
def train_model(max_depth, n_estimators):
# ... your training logic ...
f1_score = 0.83 # Your metric
return {"f1": f1_score}
# Run your experiments
train_model(max_depth=5, n_estimators=100)
train_model(max_depth=7, n_estimators=100)
train_model(max_depth=5, n_estimators=200)
This will create a experiment_log.jsonl file with one line per experiment:
{"timestamp": "2025-11-01T16:30:00...", "runtime_seconds": 12.3, "params": {"max_depth": 5, "n_estimators": 100}, "metrics": {"f1": 0.82}}
{"timestamp": "2025-11-01T16:32:12...", "runtime_seconds": 14.1, "params": {"max_depth": 7, "n_estimators": 100}, "metrics": {"f1": 0.81}}
{"timestamp": "2025-11-01T16:34:45...", "runtime_seconds": 23.5, "params": {"max_depth": 5, "n_estimators": 200}, "metrics": {"f1": 0.83}}
Analyzing Your Results
You can easily load your results back into pandas to find your best run. The key is using load_log() from littlelogger
from littlelogger import load_log
log_df = load_log(PATH_TO_LOG_FILE)
# Find your best run!
log_df.sort_values(by="metric_f1_score", ascending=False)
API Reference
@log_run(log_file="experiment_log.jsonl")
This is the main decorator. You place it above your function definition.
Parameters:
log_file(str): The path to the.jsonlfile where logs will be written.- Default:
"experiment_log.jsonl" - Behavior: The decorator will append to this file. It does not overwrite.
- Default:
What is Logged?
The decorator will write a single JSON line to the file for each function call, containing:
timestamp: An ISO 8601 formatted UTC timestamp.function_name: The name of the function that was run (e.g.,train_model).runtime_seconds: The execution time of the function (in seconds).params: A dictionary of all arguments (including defaults) passed to your function.metrics: The value returned by your function. This is expected to be a dictionary (e.g.,{"f1": 0.8, "accuracy": 0.9})
⚠️ Important Limitations
This tool is built for simplicity and has intentional trade-offs:
- Not Thread-Safe: This logger is NOT designed for concurrency. If you run functions in parallel (using
multiprocessingorthreadingfrom the same script), they will try to write to the log file at the same time, which will corrupt the file. It is for single-process, iterative experiments only. - JSON-Serializable Data Only: The decorator assumes your function arguments and return values are "JSON-serializable" (strings, ints, floats, lists, dicts). If you return a complex object (like a scikit-learn model), the logger will fail to serialize it.
- Best-Effort Logging (No Retries): If logging fails (due to a non-serializable object or a file permission error),
littleloggerwill not crash your script. It will print aUserWarningto your console and let your function return its value, prioritizing your main script's execution over logging.
License & Contributing
- License: This project is licensed under the MIT License. See the
LICENSEfile for details. - Contributing: Feel free to open an issue or submit a pull request!
Project details
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 littlelogger-1.1.1.tar.gz.
File metadata
- Download URL: littlelogger-1.1.1.tar.gz
- Upload date:
- Size: 7.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.13.9 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d574feb56043fc19b67001cd748fbdf916330b8dd099c1e398124d2c25120e7f
|
|
| MD5 |
bfa53ccf96e6e0f77d48e4bd139f0027
|
|
| BLAKE2b-256 |
09a0f1656843dbbccffe60f6a40dc7af574f2b6949e738861830374cae7b4f98
|
File details
Details for the file littlelogger-1.1.1-py3-none-any.whl.
File metadata
- Download URL: littlelogger-1.1.1-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.13.9 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4220056fd793b41819c8b1e065c2314b33a8afd327ea4e337fd9130b3f7ee32
|
|
| MD5 |
0d4a9e31680b14b381e1b04d49b38830
|
|
| BLAKE2b-256 |
a5b16d21bc14579920711f3f90e43b4c9c2fafde705bbf9e7bf89b208a2a3a9f
|