HyperLog
One import. Better logging. Simple. Batteries included.
Thin ergonomic layer: decorator + timing + prefixes + minimal structured context. Zero config by default.
Features:
- Dual‑purpose object:
logis both a decorator (@log()/@log) and logger (log.info(...)) - Decorator adds automatic timing + success (✓) / failure (✗) logs (sync & async)
- Granular timing utilities: marks, elapsed, timer context, sequential checkpoints
- Performance threshold filtering (
threshold_ms) & verbose argument logging (verbose=True) - Lightweight structured context via
bind()(and utilities to manage it) - Custom log levels (
add_level) & optional SUCCESS convenience - File logging with sane rotation/retention defaults (
add_file) - Simple global prefix (
log.prefix) for service / component labeling
Install
pip install -U hyperlog
Smallest Possible Use
from hyperlog import log
@log # or @log()
def embed_user_query(query):
...
return embedded_query
Console (ms timing + success mark):
12:34:56.011 INFO ✓ embed_user_query completed in 9.20ms
Walkthrough
Timing (4 ways)
1. Decorator timing – automatic for any function:
@log()
def search_vectors(query):
# work
return results
# → ✓ search_vectors completed in 45.23ms
2. Mark & elapsed – ad‑hoc sections:
log.mark("db_query")
results = database.search(query)
log.elapsed("db_query", log_level="info") # logs Elapsed (db_query): 23.1ms
3. Timer context manager – block timing:
with log.timer("vectorstore_connection"):
credentials = authenticate()
client = get_client(credentials)
# → vectorstore_connection: 847.3ms
4. Checkpoints – sequential step timeline:
log.checkpoint("Initialize", reset=True)
results = search_vectors(query)
log.checkpoint("Vector search")
response = generate_response(context)
log.checkpoint("LLM inference")
Current output (numbered steps – the provided names are stored internally but not displayed yet):
→ Step 1: 0.0ms | Total: 0.0ms
→ Step 2: 45.2ms | Total: 45.2ms
→ Step 3: 10.2ms | Total: 55.4ms
Logging & Structured Data
Basic logging with structured data:
log.info("Vector search", query=query[:50], collection="docs", threshold=0.8)
# Output: Vector search | query=What is machine learning? collection=docs threshold=0.8
log.debug("Cache hit", key="user:123", ttl=3600)
log.warning("Rate limit approaching", current=95, max=100, endpoint="/api/search")
log.error("Payment failed", user_id=456, amount=29.99, error_code="INSUFFICIENT_FUNDS")
Binding Context Fields
Create logger instances with persistent fields that attach to all subsequent logs:
# Create a bound logger for a specific service
billing_log = log.bind(service="billing", version="1.0")
billing_log.info("Charge created", amount=19.99)
# Fields service=billing version=1.0 amount=19.99 are in record.extra
# Managing bound fields on the global logger
log.bind(request_id="abc-123") # Adds request_id to all subsequent logs
log.info("Processing request") # Includes request_id=abc-123
log.unbind("request_id") # Remove specific field
log.unbind_all() # Remove all bound fields
Decorator Options
@log(
level="DEBUG", # override completion log level (default INFO)
prefix="[Stage] ", # per-function prefix (prepended to messages)
tags=["etl", "batch"], # stored in record extra (not shown unless format includes {extra})
threshold_ms=50, # only emit completion log if runtime >= 50ms
verbose=True, # log call args at DEBUG before execution
catch=True # wrap with loguru.catch (re-raises after logging)
)
def transform(df):
...
Decorator behavior:
- On success:
✓ function_name completed in XX.XXms - On exception:
✗ function_name failed after XX.XXms(logged at ERROR) then re-raised verbose=Trueadds a DEBUG line like:→ transform((args_repr), {'kw': 'vals'})threshold_mssuppresses fast successes (still logs failures)
Custom Levels
log.add_level("TRACE", 5, color="<magenta>")
log.trace("Deep details")
# SUCCESS may already exist (recent loguru). Only add if missing.
log.add_level("SUCCESS", 25, color="<green>")
log.success("Pipeline complete")
File Logging
log.add_file("app.log", rotation="10 MB", retention="1 week")
# rotation examples: "10 MB", "1 day", "1 week"
# retention can be duration ("1 week") or number (e.g. 3)
Sensible defaults enabled: backtrace & diagnose for rich tracebacks.
Prefixes
Set a prefix to identify different services or modules:
# auth.py
from hyperlog import log
log.prefix = "[AUTH] "
log.info("Login attempt") # [AUTH] Login attempt
# database.py
from hyperlog import log
log.prefix = "[DB] "
log.info("Query executed") # [DB] Query executed
# main.py
from hyperlog import log
log.prefix = "[MAIN] "
log.info("Application started") # [MAIN] Application started
The prefix applies to every emission (including decorator success/failure outputs).
Put It All Together (RAG Mini Pipeline)
from hyperlog import log
log.prefix = "[RAG] "
log.add_file("rag.log", rotation="1 day")
@log()
def search_vectors(query, collection="documents"):
log.mark("db_connection")
log.info("Vector search", query=query[:50], collection=collection, threshold=0.85)
# ... search logic ...
log.elapsed("db_connection", log_level="debug")
return [{"doc": "ml_guide.pdf", "score": 0.91}]
@log()
def generate_response(context, model="gpt-4"):
with log.timer("llm_inference"):
log.info("LLM call", model=model, context_tokens=len(context.split()), max_tokens=200)
# ... LLM call ...
return "Machine learning is a subset of AI..."
log.checkpoint("Pipeline start", reset=True)
results = search_vectors("What is machine learning?", collection="ml_docs")
log.checkpoint("Vector search complete")
context = f"Context: {results[0]['doc']} (relevance: {results[0]['score']})"
response = generate_response(context, model="gpt-4-turbo")
log.checkpoint("Response generated")
log.info("Pipeline complete", docs_found=len(results), response_length=len(response))
Sample console (note: decorator completion in ms, timer may auto-switch to seconds if >1s):
12:45:30.001 INFO [RAG] → Step 1: 0.0ms | Total: 0.0ms
12:45:30.002 INFO [RAG] Vector search
12:45:30.352 DEBUG [RAG] Elapsed (db_connection): 349.8ms
12:45:30.353 INFO [RAG] ✓ search_vectors completed in 351.20ms
12:45:30.354 INFO [RAG] → Step 2: 351.2ms | Total: 351.2ms
12:45:30.355 INFO [RAG] LLM call
12:45:31.878 INFO [RAG] llm_inference: 1.52s
12:45:31.879 INFO [RAG] ✓ generate_response completed in 1520.10ms
12:45:31.880 INFO [RAG] → Step 3: 1.52s | Total: 1.87s
12:45:31.881 INFO [RAG] Pipeline complete
Observability Benefits:
- Identify bottlenecks instantly (search vs inference)
- Sequential timeline of multi-step flows
- Optional structured metadata (via bind / kwargs) without config
- Production friendly file sinks & prefixes
Public API Quick Reference
log.debug/info/warning/error/critical/success/<whatever_else_you_add>
@log / @log(...) decorator (options above)
log.prefix (string)
log.add_file(path, rotation, retention, compression, level)
log.add_level(name, severity, color)
log.mark(name) / log.elapsed(name, unit, log_level)
log.checkpoint(name, reset)
log.timer(name, log_level, unit)
log.bind / log.unbind / log.unbind_all
log.catch (direct access to loguru catcher)
Notes / Gotchas
- Extra fields (kwargs, bound fields, tags, duration_ms) are present in record.extra even if not visible. Include
{extra}in your format to display. - Decorator duration units are always ms; timer & checkpoint total/step formatting auto-switch between μs/ms/s/min.
- Checkpoint names currently not printed (only step numbers) – future enhancement may show them.
- SUCCESS level: Added automatically only if you call
add_leveland it doesn't already exist in your loguru version.
Enjoy. Minimal surface, progressive enhancement. If a feature adds mental overhead for marginal benefit, it probably won’t be added.
Metadata
Release files for hyperlog 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hyperlog-0.2.0.tar.gz | 38.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hyperlog-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 50.4 kB
Release files / hyperlog-0.2.0.tar.gz
| Download URL | hyperlog-0.2.0.tar.gz |
|---|---|
| Size | 38.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
88c336af513a162d86b9200a757c99b073092b8119e746a8d0008c1c576f1924
|
|
BLAKE2b-256 checksum How to use checksums |
e4f5d788b7f3048495245f0c52960d70e0d6ecadc07d05acf8215b3828479c70
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.13
|
Release files / hyperlog-0.2.0-py3-none-any.whl
| Download URL | hyperlog-0.2.0-py3-none-any.whl |
|---|---|
| Size | 12.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4ce9220d0119b2030d73a64d520f10bd272e73a0801db1894dd2fc37c4c583fd
|
|
BLAKE2b-256 checksum How to use checksums |
156e3a45f7f5d418e8de35b623274e859525f6fef6fa2e779b7aafca9e4518c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.13
|