Skip to main content

Production-ready observability SDK for Python web applications with FastAPI integration

Project description

Ledger SDK for Python

Production-ready observability SDK with zero-overhead logging for FastAPI, Flask, and Django applications.

Python Version License PyPI Version Status

Overview

Ledger SDK provides automatic request/response logging, exception tracking, and performance monitoring for Python web applications with zero performance impact on your request handlers. All logging happens asynchronously in the background with intelligent batching, rate limiting, and circuit breaker protection.

Key Benefits:

  • Non-blocking: <0.1ms overhead per request
  • Production-ready: Circuit breaker, retry logic, health checks
  • Framework support: FastAPI, Flask (coming soon), Django (coming soon)
  • Zero configuration: Works out of the box with sensible defaults
  • Observable: Built-in metrics, health checks, and diagnostics

Installation

# Install with FastAPI support
pip install ledger-sdk[fastapi]

# Or install core only
pip install ledger-sdk

Quick Start

FastAPI

from fastapi import FastAPI
from ledger import LedgerClient
from ledger.integrations.fastapi import LedgerMiddleware

app = FastAPI()

ledger = LedgerClient(
    api_key="ldg_proj_1_your_api_key_here",
    base_url="https://ledger-server.jtuta.cloud"
)

app.add_middleware(
    LedgerMiddleware,
    ledger_client=ledger,
    exclude_paths=["/health", "/metrics"]
)

@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.on_event("shutdown")
async def shutdown():
    await ledger.shutdown()

Features

  • Automatic request/response logging via middleware
  • Automatic exception capture with full stack traces
  • Non-blocking async operation
  • Intelligent batching and buffering (every 5s or 1000 logs)
  • Dual rate limiting (per-minute and per-hour)

Usage Examples

Basic Logging

from ledger import LedgerClient

ledger = LedgerClient(
    api_key="ldg_proj_1_your_api_key",
    base_url="https://ledger-server.jtuta.cloud"
)

ledger.log_info("User logged in", attributes={"user_id": 123, "ip": "192.168.1.1"})

ledger.log_error("Payment failed", attributes={"amount": 99.99, "error_code": "CARD_DECLINED"})

try:
    result = 1 / 0
except Exception as e:
    ledger.log_exception(e, message="Division error in payment calculation")

FastAPI Integration

from fastapi import FastAPI, HTTPException
from ledger import LedgerClient
from ledger.integrations.fastapi import LedgerMiddleware

app = FastAPI()
ledger = LedgerClient(api_key="ldg_proj_1_your_api_key")

app.add_middleware(
    LedgerMiddleware,
    ledger_client=ledger,
    exclude_paths=["/health", "/metrics"]
)

@app.get("/user/{user_id}")
async def get_user(user_id: int):
    ledger.log_info(f"Fetching user {user_id}", attributes={"user_id": user_id})

    if user_id == 0:
        raise HTTPException(status_code=404, detail="User not found")

    return {"user_id": user_id, "name": f"User {user_id}"}

@app.on_event("shutdown")
async def shutdown():
    await ledger.shutdown()

Advanced Configuration

All Configuration Options

from ledger import LedgerClient

ledger = LedgerClient(
    api_key="ldg_proj_1_your_api_key",
    base_url="https://api.ledger.example.com",

    flush_interval=5.0,
    flush_size=1000,
    max_buffer_size=10000,

    http_timeout=5.0,
    http_pool_size=10,

    rate_limit_buffer=0.9
)

High-Volume Configuration

For APIs handling >1000 req/sec:

ledger = LedgerClient(
    api_key="ldg_proj_1_your_api_key",
    flush_interval=2.0,
    flush_size=500,
    max_buffer_size=50000,
    http_pool_size=20,
    rate_limit_buffer=0.95
)

Low-Volume Configuration

For APIs handling <100 req/sec:

ledger = LedgerClient(
    api_key="ldg_proj_1_your_api_key",
    flush_interval=10.0,
    flush_size=50,
    max_buffer_size=1000,
    http_pool_size=5
)

Monitoring & Health Checks

Health Checks

if ledger.is_healthy():
    print("SDK is healthy")

status = ledger.get_health_status()

Health Status Response:

{
    "status": "healthy",
    "healthy": true,
    "issues": null,
    "buffer_utilization_percent": 42.5,
    "circuit_breaker_open": false,
    "consecutive_failures": 0
}

Metrics

metrics = ledger.get_metrics()

Metrics Response:

{
    "sdk": {
        "uptime_seconds": 123.45,
        "version": "1.0.0"
    },
    "buffer": {
        "current_size": 42,
        "max_size": 10000,
        "total_dropped": 0,
        "utilization_percent": 0.42
    },
    "flusher": {
        "total_flushes": 10,
        "successful_flushes": 9,
        "failed_flushes": 1,
        "consecutive_failures": 0,
        "circuit_breaker_open": false
    },
    "rate_limiter": {
        "current_rate": 12,
        "limit_per_minute": 900
    },
    "errors": {
        "network_error": 1,
        "rate_limit": 0
    }
}

Expose Health Endpoints (FastAPI)

@app.get("/sdk/health")
async def sdk_health():
    return ledger.get_health_status()

@app.get("/sdk/metrics")
async def sdk_metrics():
    return ledger.get_metrics()

Performance

The SDK is designed for zero impact on your application performance:

Metric Performance
Request overhead <0.1ms
Background flush 50-150ms
Memory usage 8-12MB
CPU overhead <0.5%

All logging operations are:

  • Non-blocking: Logs added to buffer in <0.1ms
  • Asynchronous: Network I/O happens in background task
  • Batched: Logs sent in batches (every 5s or 1000 logs)
  • Rate-limited: Client-side rate limiting prevents 429 errors

Error Handling

The SDK includes production-grade error handling:

Circuit Breaker

Automatically stops sending requests after 5 consecutive failures and retries after 60 seconds.

if ledger.get_health_status()["circuit_breaker_open"]:
    print("Circuit breaker is open - too many failures")

Exponential Backoff

Retries failed requests with exponential backoff:

  • Server errors (5xx): 2s, 4s, 8s (max 3 retries)
  • Network errors: 5s, 10s, 20s (max 3 retries)
  • Rate limits (429): Respects Retry-After header

Graceful Degradation

  • Buffer overflow: Drops oldest logs (FIFO) to prevent memory exhaustion
  • Network failures: Keeps retrying with backoff
  • Invalid responses: Logs to stderr and drops batch

Configuration Reference

Parameter Default Description
api_key Required Ledger API key (starts with ldg_)
base_url http://localhost:8000 Ledger server URL
flush_interval 5.0 Seconds between flushes
flush_size 1000 Logs before auto-flush
max_buffer_size 10000 Max logs in memory
http_timeout 5.0 Request timeout (seconds)
http_pool_size 10 HTTP connection pool size
rate_limit_buffer 0.9 Use 90% of rate limit

See CONFIGURATION.md for tuning recommendations.

Development Setup

1. Install in Development Mode

# Clone the repository
git clone https://github.com/JakubTuta/ledger-sdk.git
cd ledger-sdk/python

# Install with dev dependencies
pip install -e ".[dev]"

2. Run Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=ledger --cov-report=html

# Run specific test
pytest tests/test_client.py

3. Run Example App

python examples/basic_app.py

Visit http://localhost:8080/docs to test the API.

Production Deployment

Deployment Checklist

  • Set production API key as environment variable
  • Configure HTTPS base_url
  • Set up monitoring endpoints (/sdk/health, /sdk/metrics)
  • Configure alerts for circuit breaker and buffer utilization
  • Monitor stderr logs for warnings/errors
  • Load test at expected traffic levels

Environment Variables

export LEDGER_API_KEY="ldg_proj_1_your_production_key"
export LEDGER_BASE_URL="https://ledger-server.jtuta.cloud"

Docker Example

FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

ENV LEDGER_API_KEY=${LEDGER_API_KEY}
ENV LEDGER_BASE_URL=${LEDGER_BASE_URL}

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Kubernetes Example

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
        - name: app
          image: my-app:latest
          env:
            - name: LEDGER_API_KEY
              valueFrom:
                secretKeyRef:
                  name: ledger-secret
                  key: api-key
            - name: LEDGER_BASE_URL
              value: "https://ledger-server.jtuta.cloud"

Documentation

Support

Resources

Support

License

MIT License - see LICENSE for details

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

ledger_sdk-1.0.1.tar.gz (24.5 kB view details)

Uploaded Source

Built Distribution

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

ledger_sdk-1.0.1-py3-none-any.whl (18.1 kB view details)

Uploaded Python 3

File details

Details for the file ledger_sdk-1.0.1.tar.gz.

File metadata

  • Download URL: ledger_sdk-1.0.1.tar.gz
  • Upload date:
  • Size: 24.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for ledger_sdk-1.0.1.tar.gz
Algorithm Hash digest
SHA256 0561f3392378465c481b8ccc98280dcecd9787dc4b88203b2d012752d4f4d1d6
MD5 9660a0550c8a962d6c575e06b415d0ba
BLAKE2b-256 85704773afc3af6a7c4414bdc87c6c5dc318bb3846ccb18bd27d6cb5f29970b4

See more details on using hashes here.

File details

Details for the file ledger_sdk-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: ledger_sdk-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 18.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for ledger_sdk-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 46fbbfe8c14058f97623dda09b590d8917c60fafdca5f32674ef385111c783f7
MD5 c1ebdb3e4e92a9af76cf2c8607d20f59
BLAKE2b-256 e30991238668af61f261b2cec178a8b2acd493054c68c726354c44182d70ad32

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