Skip to main content

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: log is 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=True adds a DEBUG line like: → transform((args_repr), {'kw': 'vals'})
  • threshold_ms suppresses 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_level and 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hyperlog-0.2.0.tar.gz (38.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hyperlog-0.2.0-py3-none-any.whl (12.0 kB view details)

Uploaded Python 3

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

Hashes for hyperlog-0.2.0.tar.gz
Algorithm Hash digest
SHA256 88c336af513a162d86b9200a757c99b073092b8119e746a8d0008c1c576f1924
MD5 d80b48c18491a749fa7a77508dfd6c14
BLAKE2b-256 e4f5d788b7f3048495245f0c52960d70e0d6ecadc07d05acf8215b3828479c70

See more details on using hashes here.

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

Hashes for hyperlog-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4ce9220d0119b2030d73a64d520f10bd272e73a0801db1894dd2fc37c4c583fd
MD5 0dc44aa6a715edb10ac633b9e016f402
BLAKE2b-256 156e3a45f7f5d418e8de35b623274e859525f6fef6fa2e779b7aafca9e4518c3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page