Production-ready observability SDK for Python web applications with FastAPI, Django, and Flask integrations
Project description
Ledger SDK for Python
Observability for developers who just want to ship.
Add one line of code. Get automatic request logging, exception tracking, and performance monitoring. No configuration required.
from ledger.integrations.fastapi import LedgerMiddleware
app.add_middleware(LedgerMiddleware, ledger_client=ledger)
That's it. Every request, response, and exception is now logged to your Ledger dashboard.
Supported Frameworks: FastAPI • Django • Flask
Why Ledger?
- Actually zero overhead - Less than 0.1ms per request. Your users won't notice.
- Works out of the box - No configuration files, no setup guides, no dashboards to build.
- Production-ready from day one - Built-in retry logic, rate limiting, and graceful failure handling.
Installation
pip install ledger-sdk
Quick Start
FastAPI
from contextlib import asynccontextmanager
from fastapi import FastAPI
from ledger import LedgerClient
from ledger.integrations.fastapi import LedgerMiddleware
ledger = LedgerClient(
api_key="ledger_proj_1_your_api_key",
base_url="https://ledger-server.jtuta.cloud"
)
@asynccontextmanager
async def lifespan(app: FastAPI):
yield
await ledger.shutdown()
app = FastAPI(lifespan=lifespan)
app.add_middleware(LedgerMiddleware, ledger_client=ledger)
Django
# settings.py
import os
from ledger import LedgerClient
LEDGER_CLIENT = LedgerClient(
api_key=os.getenv("LEDGER_API_KEY", "ledger_proj_1_your_api_key"),
base_url=os.getenv("LEDGER_BASE_URL", "https://ledger-server.jtuta.cloud")
)
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.middleware.common.CommonMiddleware",
"ledger.integrations.django.LedgerMiddleware", # Add this
]
Flask
from flask import Flask
from ledger import LedgerClient
from ledger.integrations.flask import LedgerMiddleware
app = Flask(__name__)
ledger = LedgerClient(
api_key="ledger_proj_1_your_api_key",
base_url="https://ledger-server.jtuta.cloud"
)
app.config["LEDGER_CLIENT"] = ledger
LedgerMiddleware(app)
That's all you need. Start your app and watch the logs flow into your Ledger dashboard.
Get your API key • View examples
What You Get
Automatic capture - Every request, response, and exception. No manual logging code.
Distributed tracing - W3C-compatible spans across services. Trace IDs automatically attached to logs emitted inside a span.
Full context - Stack traces, request headers, response bodies, user attributes. Everything you need to debug.
Performance insights - Response times, error rates, slow endpoints. Know where to optimize.
Production reliability - Automatic retries, rate limiting, and graceful degradation. Works even when your network doesn't.
Zero performance impact - All logging happens in the background. Your API stays fast.
Manual Logging
ledger.log_info("User logged in", attributes={"user_id": 123})
ledger.log_warning("Slow query", attributes={"duration_ms": 450})
ledger.log_error("Payment failed", attributes={"amount": 99.99, "error_code": "CARD_DECLINED"})
try:
result = process_payment()
except Exception as e:
ledger.log_exception(e, message="Payment processing failed")
Exclude Paths
app.add_middleware(
LedgerMiddleware,
ledger_client=ledger,
exclude_paths=["/health", "/metrics"]
)
Only Log Registered Routes
By default, the SDK only logs requests that match a registered route — scanner noise, 404s, and bot traffic are dropped automatically.
# To log everything including unmatched paths:
app.add_middleware(
LedgerMiddleware,
ledger_client=ledger,
only_registered_routes=False
)
Configuration
The defaults work for most applications. Tune when needed:
ledger = LedgerClient(
api_key="ledger_proj_1_your_api_key",
flush_interval=5.0, # Seconds between flushes
flush_size=1000, # Logs before auto-flush
max_buffer_size=10000, # Max logs in memory
)
High traffic (>1000 req/sec)? Decrease flush_interval to 2.0 and increase max_buffer_size to 50000.
Low traffic (<100 req/sec)? Increase flush_interval to 10.0 and decrease flush_size to 50.
Distributed Tracing
Trace requests across services with spans. Traces appear in Ledger's Trace List panel on the dashboard.
Setup
Tracing is enabled automatically when you call LedgerClient(...).
from ledger import LedgerClient
from ledger.tracing import get_tracer
ledger = LedgerClient(api_key="...", base_url="https://ledger-server.jtuta.cloud", service_name="my-service")
tracer = get_tracer()
Manual spans
with tracer.start_as_current_span("process-order", attributes={"order_id": 42}) as span:
result = process_order(42)
span.set_attribute("status", result.status)
Cross-service propagation
Inject the W3C traceparent header into outgoing HTTP calls so downstream services can continue the trace:
from ledger.tracing import propagation
with tracer.start_as_current_span("outgoing-call") as span:
headers = {}
propagation.inject(headers, span)
response = httpx.get("https://downstream/api", headers=headers)
In the downstream service, extract the context before starting spans:
ctx = propagation.extract(request.headers)
with tracer.start_as_current_span("downstream-handler", parent=ctx):
...
FastAPI auto-instrumentation
With LedgerMiddleware, every request automatically becomes a root span. Spans you create inside request handlers are nested under it:
app.add_middleware(LedgerMiddleware, ledger_client=ledger)
@app.get("/orders/{id}")
async def get_order(id: int):
tracer = get_tracer()
with tracer.start_as_current_span("db-fetch", attributes={"order_id": id}):
return await db.get_order(id)
Trace IDs in logs
Any log emitted inside an active span automatically includes the trace_id and span_id as attributes, linking logs to traces in the dashboard.
Monitoring the SDK
Check if the SDK is working properly:
if ledger.is_healthy():
print("SDK is healthy")
status = ledger.get_health_status()
metrics = ledger.get_metrics()
Expose as HTTP endpoints (FastAPI):
@app.get("/sdk/health")
async def sdk_health():
return ledger.get_health_status()
Production
Set your API key as an environment variable:
export LEDGER_API_KEY="ledger_proj_1_your_production_key"
export LEDGER_BASE_URL="https://ledger-server.jtuta.cloud"
import os
ledger = LedgerClient(
api_key=os.getenv("LEDGER_API_KEY"),
base_url=os.getenv("LEDGER_BASE_URL")
)
Need Help?
- Open an issue - Bug reports and feature requests
- View examples - See it in action
- Changelog - Version history
Links
- PyPI Package - Install the SDK
- Dashboard - View your logs
- API Server - Server endpoint
- Backend Source - API server code
- Frontend Source - Dashboard code
License
MIT License - see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ledger_sdk-1.7.0.tar.gz.
File metadata
- Download URL: ledger_sdk-1.7.0.tar.gz
- Upload date:
- Size: 50.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ff2e176ef7f2700e3d6d77d805c593ad3dd31e2883508d1a95e2080946dea8b
|
|
| MD5 |
7c597dfac53884b2d2c638201b97b2d1
|
|
| BLAKE2b-256 |
9aac28ed0a4fea0825b63d2b41ceee20672551c1aacc95aeb5b1cacd90c0d966
|
File details
Details for the file ledger_sdk-1.7.0-py3-none-any.whl.
File metadata
- Download URL: ledger_sdk-1.7.0-py3-none-any.whl
- Upload date:
- Size: 37.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f4c5cefd794bad0a9d503a0becf6105de6fa0e1123f4848b237db480aab8890
|
|
| MD5 |
1331ce810bb057f7e1c33e38c194f840
|
|
| BLAKE2b-256 |
35c9bc7623d44e04f6411c662b30dbf4fa90360f4f2afb2d95d5159613a61f45
|