Skip to main content

Minimalistic context-aware structured logging for Python

Project description

tinystructlog

PyPI version Python versions Build Status Coverage License Code style: black

Minimalistic context-aware structured logging for Python. Add contextual information to your logs effortlessly with thread-safe and async-safe context management.

Features

  • 🎯 Context-Aware: Automatically inject contextual information (user IDs, request IDs, etc.) into all log messages
  • 🔒 Thread & Async Safe: Built on Python's contextvars for perfect isolation across threads and async tasks
  • 🎨 Colored Output: Beautiful ANSI-colored terminal output for better readability
  • 🎛️ Flexible Formats: Customizable output with sensible defaults and preset formats (v0.1.1+)
  • ⚡ Zero Dependencies: No runtime dependencies - just pure Python
  • 📦 Minimal & Focused: Does one thing well - context-aware logging
  • 🔧 Zero Configuration: Sensible defaults, works out of the box
  • 💡 Type Hints: Full type hint support for better IDE experience

Installation

pip install tinystructlog

Quick Start

from tinystructlog import get_logger, set_log_context

# Create a logger
log = get_logger(__name__)

# Log without context
log.info("Application started")

# Set context - will be included in all subsequent logs
set_log_context(user_id="12345", request_id="abc-def")

log.info("Processing request")
# Output: [2024-01-17 10:30:45] [INFO] [main.<module>:10] [request_id=abc-def user_id=12345] Processing request

log.error("An error occurred")
# Output: [2024-01-17 10:30:46] [ERROR] [main.<module>:11] [request_id=abc-def user_id=12345] An error occurred

Why tinystructlog?

When building applications, especially web services or async workers, you often need to track context across multiple operations:

  • Multi-tenant applications: Track which tenant each log belongs to
  • Request tracing: Follow a request's journey through your application
  • User tracking: Know which user triggered each log event
  • Distributed systems: Correlate logs across different parts of your system

tinystructlog makes this trivial while staying out of your way.

Advanced Usage

Temporary Context

Use the log_context context manager for temporary context that automatically cleans up:

from tinystructlog import get_logger, log_context

log = get_logger(__name__)

with log_context(operation="cleanup", task_id="task-123"):
    log.info("Starting cleanup")  # Includes operation and task_id
    perform_cleanup()
# Context automatically removed after the block

log.info("Done")  # No operation/task_id context

Async Context Isolation

Each async task gets its own isolated context - no cross-contamination:

import asyncio
from tinystructlog import get_logger, set_log_context

log = get_logger(__name__)


async def handle_request(user_id: str, request_id: str):
    set_log_context(user_id=user_id, request_id=request_id)
    log.info("Processing request")  # Each task logs its own context
    await do_work()


# These run concurrently, each with isolated context
await asyncio.gather(
    handle_request("user1", "req001"),
    handle_request("user2", "req002"),
)

Web Framework Integration

Perfect for web applications - set context per request:

from fastapi import FastAPI, Request
from tinystructlog import get_logger, set_log_context, clear_log_context
import uuid

app = FastAPI()
log = get_logger(__name__)


@app.middleware("http")
async def add_context(request: Request, call_next):
    # Add request context
    set_log_context(
        request_id=str(uuid.uuid4()),
        path=request.url.path,
        method=request.method,
    )

    response = await call_next(request)

    # Clean up after request
    clear_log_context()
    return response

Configuration

Control log level via the LOG_LEVEL environment variable:

export LOG_LEVEL=DEBUG
python your_app.py

Supported levels: DEBUG, INFO, WARNING, ERROR, CRITICAL

Custom Log Formats (v0.1.1+)

While tinystructlog comes with sensible defaults, you can customize the output format to match your needs:

Using Preset Formats

from tinystructlog import get_logger, MINIMAL_FORMAT, DETAILED_FORMAT, SIMPLE_FORMAT

# Minimal format - just level and message
log = get_logger(__name__, fmt=MINIMAL_FORMAT)
log.info("Clean output")
# Output: INFO: Clean output

# Detailed format - includes process ID
log = get_logger(__name__, fmt=DETAILED_FORMAT)
log.info("Detailed output")
# Output: [2026-01-18 10:30:45] [INFO] [12345] [module.function:10] Message

# Simple format - level and context only
log = get_logger(__name__, fmt=SIMPLE_FORMAT)
log.info("Simple output")
# Output: [INFO] Message

Custom Format Strings

from tinystructlog import get_logger

# Fully custom format
log = get_logger(__name__, fmt="%(levelname)s | %(message)s")
log.info("Custom")
# Output: INFO | Custom

# Custom with timestamp
log = get_logger(__name__,
                 fmt="[%(asctime)s] %(message)s",
                 datefmt="%H:%M:%S"
                 )
log.info("Time only")
# Output: [10:30:45] Time only

Available Format Variables

Standard Python logging attributes:

  • %(asctime)s - Timestamp (customize with datefmt)
  • %(levelname)s - Log level (DEBUG, INFO, etc.)
  • %(module)s - Module name
  • %(funcName)s - Function name
  • %(lineno)d - Line number
  • %(message)s - Log message
  • %(process)d - Process ID

tinystructlog-specific attributes:

  • %(context)s - Raw context string (e.g., "key1=val1 key2=val2")
  • %(context_str)s - Bracketed context (e.g., " [key1=val1 key2=val2]")
  • Individual context keys as attributes

Note: Version 0.1.0 had an opinionated, hardcoded format. Starting with v0.1.1, you can customize it while maintaining full backward compatibility. The default format (when no fmt parameter is provided) remains identical to v0.1.0.

Use Cases

  • Microservices: Track requests across service boundaries
  • Multi-tenant SaaS: Isolate logs by tenant
  • Async workers: Track background job context
  • APIs: Add request/user context to all endpoints
  • Data pipelines: Track which dataset/batch is being processed

Comparison with Alternatives

vs. loguru

loguru is popular for its simplicity and rich features. Key differences:

  • Dependencies: tinystructlog has zero dependencies; loguru includes additional libraries
  • Context: tinystructlog uses contextvars for automatic thread/async isolation; loguru requires explicit bind() calls
  • Focus: tinystructlog focuses purely on context management; loguru provides rotation, retention, compression, and more
  • Integration: tinystructlog works with standard logging infrastructure; loguru replaces it

Choose tinystructlog for minimal footprint and automatic context propagation. Choose loguru for rich features and advanced error handling.

See the full comparison for details on reproducing tinystructlog's format in loguru.

vs. Standard logging

Standard library logging requires manual context passing or using filters on every logger. tinystructlog handles this automatically with proper async/thread safety.

vs. structlog

structlog is feature-rich but heavier. tinystructlog is minimalistic (zero dependencies!) and focuses purely on context management with sensible defaults for common use cases.

API Reference

get_logger(name: str) -> logging.Logger

Create a configured logger with context support.

set_log_context(**kwargs) -> None

Set context variables that will be included in all subsequent log messages.

clear_log_context(*keys: str) -> None

Clear specific context keys, or all context if no keys provided.

log_context(**kwargs) -> ContextManager

Context manager for temporary context that automatically cleans up.

Documentation

Full documentation is available at tinystructlog.readthedocs.io

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

License

MIT License - see LICENSE for details.

Credits

Created by Andrey Vykhodtsev (Aprova GmbH)

Inspired by the need for simple, reliable context management in production Python applications.

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

tinystructlog-0.1.2.tar.gz (87.1 kB view details)

Uploaded Source

Built Distribution

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

tinystructlog-0.1.2-py3-none-any.whl (9.9 kB view details)

Uploaded Python 3

File details

Details for the file tinystructlog-0.1.2.tar.gz.

File metadata

  • Download URL: tinystructlog-0.1.2.tar.gz
  • Upload date:
  • Size: 87.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for tinystructlog-0.1.2.tar.gz
Algorithm Hash digest
SHA256 54575289983bc5bc66ff55e78bf12b4fca978a523d0c6fd12214e9e73e9f363b
MD5 0ce962d2a6294e7ccf577a9c9273f10a
BLAKE2b-256 bba3aba1ddcbbbacdc8418b3cbacade2c60a332c969f158821942242071b3f23

See more details on using hashes here.

File details

Details for the file tinystructlog-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: tinystructlog-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 9.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for tinystructlog-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 326234084dbc6cb79429ab862a79c125516f3d50157aba626b7f90d8212eabb1
MD5 9b2873e988e1345d2ec4a470688d6b8c
BLAKE2b-256 a7ff911c64a6a868dc0500b69eb4341c1a916bcde2bbcffd24698e51878b7d37

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