Quick Start Guide
Installation
Install tinystructlog using pip:
pip install tinystructlog
Requirements: Python 3.11 or higher.
Basic Usage
The simplest way to get started:
from tinystructlog import get_logger, set_log_context
# Create a logger
log = get_logger(__name__)
# Log without context
log.info("Application started")
# Set context that will be included in all subsequent logs
set_log_context(user_id="12345", request_id="abc-def")
log.info("Processing request")
log.error("An error occurred")
Output will look like:
[2024-01-17 10:30:45] [INFO] [__main__:5] Application started
[2024-01-17 10:30:46] [INFO] [__main__:10] [request_id=abc-def user_id=12345] Processing request
[2024-01-17 10:30:47] [ERROR] [__main__:11] [request_id=abc-def user_id=12345] An error occurred
Setting Context
Use set_log_context() to add or update context variables:
from tinystructlog import set_log_context, get_logger
log = get_logger(__name__)
# Set initial context
set_log_context(user_id="user123")
log.info("User logged in")
# Add more context (merges with existing)
set_log_context(session_id="sess456")
log.info("Session created") # Will have both user_id and session_id
# Override existing values
set_log_context(user_id="user789")
log.info("Context updated") # user_id is now user789
Clearing Context
Remove specific keys or clear all context:
from tinystructlog import clear_log_context, set_log_context, get_logger
log = get_logger(__name__)
set_log_context(user_id="123", session_id="abc")
log.info("With full context")
# Clear specific keys
clear_log_context("session_id")
log.info("Session cleared") # Only has user_id
# Clear all context
clear_log_context()
log.info("All context cleared") # No context
Temporary Context
Use the log_context context manager for temporary context:
from tinystructlog import log_context, get_logger
log = get_logger(__name__)
with log_context(operation="cleanup", task_id="task-123"):
log.info("Starting cleanup") # Includes operation and task_id
perform_cleanup()
log.info("Cleanup completed")
# Context automatically removed after the block
log.info("Back to normal") # No operation/task_id
Async Usage
tinystructlog is fully async-safe with automatic context isolation:
import asyncio
from tinystructlog import get_logger, set_log_context
log = get_logger(__name__)
async def handle_request(user_id: str, request_id: str):
# Each task gets isolated context
set_log_context(user_id=user_id, request_id=request_id)
log.info("Processing request")
await asyncio.sleep(1)
log.info("Request completed")
# Run multiple tasks concurrently - contexts won't interfere
async def main():
await asyncio.gather(
handle_request("user1", "req001"),
handle_request("user2", "req002"),
handle_request("user3", "req003"),
)
asyncio.run(main())
Web Framework Integration
Example with FastAPI:
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,
)
log.info("Request started")
response = await call_next(request)
log.info("Request completed", extra={"status": response.status_code})
# Clean up after request
clear_log_context()
return response
@app.get("/")
async def root():
log.info("Handling root endpoint")
return {"message": "Hello World"}
Example with Flask:
from flask import Flask, request, g
from tinystructlog import get_logger, set_log_context, clear_log_context
import uuid
app = Flask(__name__)
log = get_logger(__name__)
@app.before_request
def before_request():
set_log_context(
request_id=str(uuid.uuid4()),
path=request.path,
method=request.method,
)
log.info("Request started")
@app.after_request
def after_request(response):
log.info("Request completed", extra={"status": response.status_code})
clear_log_context()
return response
@app.route("/")
def home():
log.info("Handling home page")
return "Hello, World!"
Configuration
Log Level
Control the log level using the LOG_LEVEL environment variable:
export LOG_LEVEL=DEBUG
python your_app.py
Supported levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
Default is INFO.
Colored Output
Colored output is enabled by default when logging to a terminal. Colors are automatically disabled when output is redirected to a file or pipe.
Custom Log Formats (v0.1.1+)
While tinystructlog comes with sensible defaults, you can customize the output format.
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 withdatefmt)%(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
Backward Compatibility: 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.
Next Steps
Check out the API Reference for detailed API reference
See Usage Examples for more advanced usage patterns