Skip to content

tejus3131/bozo

bozo

Production-grade structured logging with optional real-time web viewer.

Python 3.13+ MIT License Tests Passing Code Coverage

Simple. One function to set up structured logging. Powerful. File, JSON, HTTP, console—all at once. Developer-Friendly. Type-safe, zero-config defaults.


Features

Structured Logging Context-aware, nested logging with built-in support for sensitive data redaction.

📊 Multiple Outputs Simultaneously log to console (colored), text files, JSON files, and HTTP endpoints.

🌐 Web Viewer (Optional) Real-time log streaming dashboard. Perfect for development and debugging.

🛠 Production-Ready Automatic log rotation, third-party library suppression, and thread-safe operations.

🔍 Full Type Safety Fully typed with Python 3.13+ support. Works great with type checkers.

⚙️ Smart Defaults Intelligent log file management, automatic cleanup, and sensible configuration presets.


Quick Start

Installation

# Core library
pip install bozo

# With web viewer support
pip install bozo[viewer]

Basic Usage

import bozo

# Initialize once at startup
bozo.setup("myapp")
log = bozo.get(__name__)

# Log with structured data
log.info("user_login", user_id=42, email="user@example.com")
log.warning("slow_query", query_time=1.5, threshold=1.0)
log.error("payment_failed", amount=99.99, reason="insufficient_funds")

Output (console, file, JSON—simultaneously):

2026-02-04 10:23:45 | INFO     | myapp.main | user_login
2026-02-04 10:23:46 | WARNING  | myapp.main | slow_query
2026-02-04 10:23:47 | ERROR    | myapp.main | payment_failed

Sensitive Data

Automatically redact passwords, tokens, and secrets:

log.info(
    "auth_attempt",
    username="alice",
    password=bozo.redact("secret123")  # Will log as [REDACTED]
)

Context Management

Attach request context that persists across async/threaded operations:

with bozo.log_context(request_id="abc-123", user_id=42):
    log.info("processing")  # request_id and user_id added automatically
    await some_async_operation()
    log.info("completed")  # context still present

Web Viewer

View logs in real-time from a beautiful dashboard:

# Enable during setup
bozo.setup(
    "myapp",
    enable_viewer=True,
    viewer_port=8080
)

# Or start it manually
bozo.start_viewer(open_browser=True)  # Opens http://127.0.0.1:8080

Configuration

Development vs. Production

# Development: Pretty-printed, colored console output
bozo.setup("myapp", environment=bozo.Environment.DEVELOPMENT)

# Production: Plain text, structured JSON, minimal console
bozo.setup("myapp", environment=bozo.Environment.PRODUCTION)

Output Handlers

Control what gets logged and where:

bozo.setup(
    "myapp",
    # Console
    enable_console=True,
    console_level=bozo.LogLevel.INFO,
    # Text files
    enable_file=True,
    file_level=bozo.LogLevel.DEBUG,
    enable_error_file=True,  # Separate ERROR+ logs
    # JSON files (for log aggregation)
    enable_json=True,
    json_level=bozo.LogLevel.DEBUG,
    # HTTP shipping (for external platforms)
    enable_http=True,
)

Log Directory

Logs are organized by run:

~/.local/share/bozo/myapp/          # macOS/Linux (or platform-specific)
├── current/                         # Latest run
│   ├── 2026-02-04_10-23-45.log
│   ├── 2026-02-04_10-23-45.error
│   └── 2026-02-04_10-23-45.json
├── 2026-02-03_18-15-22/             # Previous runs
│   ├── 2026-02-03_18-15-22.log
│   ├── 2026-02-03_18-15-22.error
│   └── 2026-02-03_18-15-22.json
└── ...

Automatically cleaned up (configurable):

bozo.setup("myapp", max_runs_to_keep=10)  # Keep only 10 most recent runs

Advanced Usage

Capturing Python Warnings

Route Python warnings through bozo:

import warnings

bozo.setup("myapp", capture_warnings=True)

warnings.warn("deprecated feature")  # Will be logged

Third-Party Library Suppression

Reduce noise from verbose libraries:

bozo.setup("myapp", suppress_third_party=True)
# Automatically reduces verbosity for: urllib3, httpx, httpcore, etc.

Programmatic Context

# Set context that persists
bozo.set_context(request_id="req-123")
log.info("operation_started")  # Has request_id

# Clear specific context
bozo.clear_context()

Logging Levels

All standard levels are supported:

log.debug("verbose_info")
log.info("important_event")
log.warning("potential_issue")
log.error("something_failed", error=str(exception))

Type Safety

Full IDE autocomplete and type checking:

import bozo
from bozo import BoundLogger, LogLevel, Environment

log: BoundLogger = bozo.get(__name__)
env: Environment = bozo.Environment.PRODUCTION
level: LogLevel = bozo.LogLevel.DEBUG

Common Patterns

Web Framework Integration

FastAPI:

from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
import bozo

bozo.setup("api", environment=bozo.Environment.PRODUCTION)
log = bozo.get(__name__)

@app.middleware("http")
async def log_requests(request: Request, call_next):
    with bozo.log_context(
        method=request.method,
        path=request.url.path,
        client=request.client.host
    ):
        response = await call_next(request)
        log.info("request", status_code=response.status_code)
        return response

Django:

# settings.py
import bozo

bozo.setup(
    "myproject",
    environment=bozo.Environment.PRODUCTION,
    enable_viewer=False,
)

LOGGING = {"version": 1, "disable_existing_loggers": False}

Database Operations

with bozo.log_context(operation="user_insert"):
    try:
        db.insert_user(user_data)
        log.info("user_created", user_id=user_data["id"])
    except Exception as e:
        log.error("insert_failed", error=str(e), data=user_data)
        raise

Background Tasks

import asyncio

async def process_queue():
    while True:
        item = await queue.get()
        with bozo.log_context(job_id=item["id"]):
            try:
                await process_item(item)
                log.info("job_completed")
            except Exception as e:
                log.error("job_failed", error=str(e))
                await queue.put(item)  # Retry
            await asyncio.sleep(1)

Performance

  • Minimal overhead: Structured logging is negligible vs. application logic
  • Thread-safe: All operations are safe for concurrent use
  • Bounded memory: Web viewer queue has configurable limits
  • Efficient rotation: Automatic file rotation prevents disk bloat

Troubleshooting

Q: Where are my log files?

A: Check ~/.local/share/bozo/yourapp/current/ (or the path printed at startup)

Q: Web viewer not working?

A: Install viewer dependencies: pip install bozo[viewer]

Q: How do I disable file logging?

A: bozo.setup("app", enable_file=False, enable_json=False)

Q: Can I use bozo with existing logging setup?

A: bozo replaces your logging setup. Call bozo.setup() once at startup.


Contributing

Contributions welcome! See CONTRIBUTING.md for guidelines.


License

MIT License - see LICENSE for details.


Support

Made with ❤️ by Tejus Gupta

About

Production-grade structured logging with optional real-time web viewer

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Contributors