Skip to main content

Lightweight, non-blocking Python SDK for TraceHub log ingestion and error tracking

Project description

TraceHub

Lightweight, non-blocking Python SDK for TraceHub — a log ingestion and error-tracking platform.

The SDK collects logs from your application, batches them in a background thread, and ships them to the TraceHub API via gzip-compressed HTTP. Logs flow through a RabbitMQ queue on the backend for reliable, asynchronous processing.

Your App ──▶ SDK (batch + gzip) ──▶ TraceHub API ──▶ RabbitMQ ──▶ Worker ──▶ PostgreSQL

Table of Contents


Installation

pip install tracehub

With framework integrations:

pip install tracehub[fastapi]   # FastAPI / Starlette
pip install tracehub[flask]     # Flask
pip install tracehub[django]    # Django

Quick Start

from tracehub import TraceHubLogger

# Initialize (endpoint defaults to http://103.127.146.14)
logger = TraceHubLogger(
    api_key="th_your_api_key",      # from TraceHub dashboard
    service="my-app",               # your service name
    environment="production",       # production / staging / dev
)

# Log messages at any severity level
logger.info("Application started", module="main")
logger.warn("Disk usage above 80%", module="monitoring")

# Capture errors with full stack traces
try:
    process_payment(order_id=123)
except Exception:
    logger.error("Payment failed", exc_info=True, module="billing",
                 extra={"order_id": 123})

# Attach arbitrary metadata
logger.info("User logged in", module="auth",
            extra={"user_id": "usr_42", "ip": "10.0.0.1"})

# Ensure all logs are sent before shutdown
logger.close()

Configuration

Parameter Type Default Description
api_key str required Project API key (starts with th_)
service str required Name of your service / application
environment str required Deployment environment (production, staging, dev)
endpoint str http://103.127.146.14 TraceHub API base URL
batch_size int 50 Flush when buffer reaches this many entries
flush_interval float 5.0 Max seconds between flushes
max_buffer int 10000 Ring buffer capacity (oldest entries dropped when full)
max_retries int 3 Retry count on 5xx / network errors
timeout float 10.0 HTTP request timeout in seconds
compress bool True Gzip-compress payloads before sending
dlq_path str ~/.tracehub/dlq Dead-letter queue directory for failed batches

Example — full configuration

logger = TraceHubLogger(
    api_key="th_abc123",
    service="order-service",
    environment="production",
    endpoint="http://103.127.146.14",
    batch_size=100,
    flush_interval=3.0,
    max_buffer=50_000,
    max_retries=5,
    timeout=15.0,
    compress=True,
    dlq_path="/var/log/tracehub/dlq",
)

Logging Methods

Five severity levels matching the backend's log_level enum:

logger.debug("Verbose diagnostic info",   module="db")
logger.info("Normal operational message",  module="auth")
logger.warn("Something looks unusual",     module="cache")
logger.error("Operation failed",           module="api",  exc_info=True)
logger.fatal("Critical system failure",    module="core", exc_info=True)

All methods accept these keyword arguments:

Argument Type Description
module str Logical module name (e.g. "auth", "payments")
extra dict[str, Any] Arbitrary key-value metadata
exc_info bool Capture current exception stack trace (error/fatal)

Error Tracking

When you log at ERROR or FATAL with exc_info=True, the SDK captures the full stack trace. The backend's RabbitMQ worker then:

  1. Normalizes the error message (strips UUIDs, timestamps, hex addresses)
  2. Extracts the top 5 stack frames
  3. Generates a SHA-256 fingerprint
  4. Creates or updates an Issue in the dashboard

This means repeated occurrences of the same error are grouped into a single issue with an incrementing event count.

try:
    db.execute("SELECT * FROM users WHERE id = ?", user_id)
except DatabaseError:
    logger.error("Query failed", exc_info=True, module="db",
                 extra={"query": "get_user", "user_id": user_id})

Extra Metadata

The extra parameter accepts any JSON-serializable dictionary. This data is stored in a JSONB column and is fully searchable in the dashboard.

logger.info("Order placed", module="orders", extra={
    "order_id": "ord_789",
    "total": 49.99,
    "items": 3,
    "customer_tier": "premium",
})

Framework Integrations

FastAPI

from fastapi import FastAPI
from tracehub import TraceHubLogger
from tracehub.integrations.fastapi import TraceHubMiddleware

app = FastAPI()
app.add_middleware(TraceHubMiddleware)

logger = TraceHubLogger(
    api_key="th_your_key",
    service="my-fastapi-app",
    environment="production",
)

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    logger.info("Fetching user", module="api", extra={"user_id": user_id})
    return {"id": user_id}

The middleware automatically:

  • Reads X-Trace-ID from the request header (or generates a UUID)
  • Attaches the trace ID to all logs emitted during that request
  • Returns X-Trace-ID in the response header

Flask

from flask import Flask
from tracehub import TraceHubLogger
from tracehub.integrations.flask import init_tracehub

app = Flask(__name__)
init_tracehub(app)

logger = TraceHubLogger(
    api_key="th_your_key",
    service="my-flask-app",
    environment="production",
)

@app.route("/health")
def health():
    logger.info("Health check", module="api")
    return {"status": "ok"}

Django

Add the middleware to your settings.py:

MIDDLEWARE = [
    "tracehub.integrations.django.TraceHubMiddleware",
    # ... other middleware
]

Then use the logger anywhere:

from tracehub import TraceHubLogger

logger = TraceHubLogger(
    api_key="th_your_key",
    service="my-django-app",
    environment="production",
)

def my_view(request):
    logger.info("Processing request", module="views")
    # trace_id is automatically attached

Architecture

┌─────────────────────────────────────────────────────────┐
│                     Your Application                     │
│                                                          │
│   logger.info("msg")                                     │
│       │                                                  │
│       ▼                                                  │
│   ┌──────────┐    ┌────────────┐    ┌────────────────┐  │
│   │ Enricher │───▶│ RingBuffer │───▶│  BatchWorker   │  │
│   │ (1ms)    │    │ (10k cap)  │    │ (daemon thread)│  │
│   └──────────┘    └────────────┘    └───────┬────────┘  │
│                                             │            │
│   Enricher adds:                   Flushes on:           │
│   - timestamp (UTC ISO)            - batch_size reached  │
│   - hostname                       - flush_interval      │
│   - PID / thread_id               - shutdown             │
│   - sdk_version                                          │
│   - trace_id                                             │
└─────────────────────────────────────────────────────────┘
                          │
                          │ POST /api/v1/ingest
                          │ X-API-Key: th_xxx
                          │ Content-Encoding: gzip
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   TraceHub Backend                        │
│                                                          │
│   ┌───────────┐    ┌──────────┐    ┌─────────────────┐  │
│   │ FastAPI   │───▶│ RabbitMQ │───▶│ Worker Process  │  │
│   │ Ingestion │    │  Queue   │    │ (log_ingestion) │  │
│   └───────────┘    └──────────┘    └────────┬────────┘  │
│                                             │            │
│                                    ┌────────▼────────┐  │
│                                    │   PostgreSQL     │  │
│                                    │  (partitioned)   │  │
│                                    └─────────────────┘  │
└─────────────────────────────────────────────────────────┘

Components

Component Description
Enricher Adds host, PID, timestamp, trace_id (~1ms, runs on caller thread)
RingBuffer Thread-safe circular buffer. Drops oldest entries when full.
BatchWorker Daemon thread that flushes buffer on size/time thresholds.
HttpTransport Sends gzip-compressed batches. Retries with exponential backoff.
DeadLetterQueue Persists failed batches to disk for later replay.

Reliability Features

  • Non-blocking: Logging calls return immediately (~1ms)
  • Background batching: Reduces HTTP overhead by grouping logs
  • Gzip compression: Minimizes bandwidth usage
  • Exponential backoff: Retries on 5xx / timeout / network errors
  • Dead-letter queue: Failed batches saved to disk, replayed on next startup
  • Ring buffer: Fixed memory footprint, no OOM risk
  • Graceful shutdown: atexit hook flushes remaining logs

API Reference

TraceHubLogger

class TraceHubLogger:
    def __init__(self, api_key, service, environment, endpoint="", *, ...)
    def debug(self, message, *, module="", extra=None) -> None
    def info(self, message, *, module="", extra=None) -> None
    def warn(self, message, *, module="", extra=None) -> None
    def error(self, message, *, exc_info=False, module="", extra=None) -> None
    def fatal(self, message, *, exc_info=False, module="", extra=None) -> None
    def flush(self) -> None
    def close(self) -> None

tracehub.enricher

def set_trace_id(trace_id: str) -> None    # Set trace ID for current thread
def get_trace_id() -> str                   # Get current thread's trace ID
def clear_trace_id() -> None                # Clear current thread's trace ID

Exceptions

TraceHubError            # Base exception
TraceHubConfigError      # Invalid configuration (missing api_key, etc.)
TraceHubTransportError   # HTTP transport failure

Testing

Run unit tests

cd SDK
pip install -e ".[dev]"
pytest tests/ -v

Run integration tests (requires live backend + RabbitMQ)

TRACEHUB_TEST_API_KEY=th_your_key pytest tests/test_integration_rabbitmq.py -v -s

What the integration tests verify

Test Validates
test_single_log_ingestion SDK -> API accepts a single log
test_batch_ingestion All five severity levels are accepted
test_error_with_stack_trace Stack traces flow through RabbitMQ to issue creation
test_high_volume_batch 50 logs batched and flushed correctly
test_extra_metadata Arbitrary JSON metadata is transmitted

Troubleshooting

Logs not appearing in dashboard

  1. Check API key: Ensure it starts with th_ and is active in the project settings
  2. Check endpoint: Default is http://103.127.146.14 -- verify it's reachable
  3. Check DLQ: Look in ~/.tracehub/dlq/ for failed batches
  4. Check RabbitMQ: Verify the worker is running on the backend

High memory usage

Reduce max_buffer (default 10,000 entries). The ring buffer drops oldest entries when full.

Slow application startup

The SDK replays any dead-letter queue files on startup. If ~/.tracehub/dlq/ has many files, clear them or increase the timeout.

TraceHubConfigError: api_key is required

Pass a non-empty api_key parameter. Generate one from the TraceHub dashboard under Project Settings > API Keys.


License

MIT

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

tracehub_logger-1.1.0.tar.gz (23.0 kB view details)

Uploaded Source

Built Distribution

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

tracehub_logger-1.1.0-py3-none-any.whl (16.2 kB view details)

Uploaded Python 3

File details

Details for the file tracehub_logger-1.1.0.tar.gz.

File metadata

  • Download URL: tracehub_logger-1.1.0.tar.gz
  • Upload date:
  • Size: 23.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for tracehub_logger-1.1.0.tar.gz
Algorithm Hash digest
SHA256 aa91367d2ea874747250908d9ca1f60cf8aaa7650f993294ce45d31bf9ae456b
MD5 4b0c28f0efdc08131afffeb65d401ea3
BLAKE2b-256 726131cdbd92b852083410bf1d5636a92176d44eaec8694a5a55450708273486

See more details on using hashes here.

File details

Details for the file tracehub_logger-1.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for tracehub_logger-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 93b9ab223d591ea70f83c932876e269546492b9fae596c3d74cd43f29ee7b43c
MD5 48129d0ff69a36a7fc42d4543cba7cc9
BLAKE2b-256 306f984dbb668220e9fc8b47859c239d3ce31692eed8991ec596f6eb11275d08

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