One import. Better logging. Simple. Batteries included.
Project description
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.
Project details
Release history Release notifications | RSS feed
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 hyperlog-0.2.0.tar.gz.
File metadata
- Download URL: hyperlog-0.2.0.tar.gz
- Upload date:
- Size: 38.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88c336af513a162d86b9200a757c99b073092b8119e746a8d0008c1c576f1924
|
|
| MD5 |
d80b48c18491a749fa7a77508dfd6c14
|
|
| BLAKE2b-256 |
e4f5d788b7f3048495245f0c52960d70e0d6ecadc07d05acf8215b3828479c70
|
File details
Details for the file hyperlog-0.2.0-py3-none-any.whl.
File metadata
- Download URL: hyperlog-0.2.0-py3-none-any.whl
- Upload date:
- Size: 12.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ce9220d0119b2030d73a64d520f10bd272e73a0801db1894dd2fc37c4c583fd
|
|
| MD5 |
0dc44aa6a715edb10ac633b9e016f402
|
|
| BLAKE2b-256 |
156e3a45f7f5d418e8de35b623274e859525f6fef6fa2e779b7aafca9e4518c3
|