Skip to main content

Python client library for DevStream logging service

Project description

DevStream Python Client

Python client library for sending logs to DevStream logging service.

For AI coding agents: a machine-readable integration guide is hosted at your DevStream server's /llms.txt (e.g. https://devstream.fly.dev/llms.txt), covering this client, the raw HTTP API, and the OpenAPI spec.

Installation

pip install devstream-client

Or install from source:

cd client
pip install -e .

Quick Start

Basic Usage

from devstream_client import DevStreamClient

# Initialize client
client = DevStreamClient(
    api_key="your-api-key",
    app_key="my-app",
    deployment_key="production",
    base_url="http://localhost:8787"  # or your production URL
)

# Send a simple log
client.log("Application started successfully")

# Send a log with tags
client.log_with_tags(
    "User logged in",
    user_id="12345",
    level="info",
    ip_address="192.168.1.1"
)

# Attach structured JSON data to a log
client.log(
    "Order placed",
    tags=[{"name": "level", "value": "info"}],
    data={"order_id": 4823, "total": 19.99, "items": ["sku-1", "sku-2"]},
)

# data also works with the keyword-tag helper
client.log_with_tags(
    "Order placed",
    data={"order_id": 4823, "total": 19.99},
    level="info",
)

Batch Sending

Send many messages in a single HTTP request (one bulk insert server-side):

client.log_batch([
    {"message": "step 1", "correlation_id": "req-1"},
    {"message": "step 2", "tags": [{"name": "level", "value": "info"}]},
    {"message": "step 3", "data": {"rows": 42}},
])

Each entry accepts message (required), tags, data, and correlation_id.

Python Logging Integration

import logging
from devstream_client import DevStreamHandler

# Create logger
logger = logging.getLogger("myapp")
logger.setLevel(logging.INFO)

# Add DevStream handler
handler = DevStreamHandler(
    api_key="your-api-key",
    app_key="my-app",
    deployment_key="production",
    base_url="http://localhost:8787"  # or your production URL
)
logger.addHandler(handler)

# Use standard Python logging
logger.info("Application started")
logger.error("Something went wrong", exc_info=True)

The handler is non-blocking: each record is queued and sent on a background thread, so logging never blocks the calling thread on the network (important under async servers like Daphne and in Celery tasks). If the queue fills up (default 1000 pending records, configurable via queue_size), new records are dropped rather than blocking. Pending records are flushed on interpreter exit.

For high-volume logging, pass batch=True to coalesce queued records into a single batch request per drain (uses the server's batch endpoint):

handler = DevStreamHandler(..., batch=True, batch_max=100)

Context tags (correlation id, etc.)

Attach request-scoped context to every log line as a tag, without custom handler code, using a filter that reads a contextvars.ContextVar:

import contextvars
from devstream_client import ContextVarTagFilter

slack_thread = contextvars.ContextVar("slack_thread", default=None)
handler.addFilter(ContextVarTagFilter(slack_thread, "slack_thread"))

slack_thread.set("T123.456")  # set per request/task; appears as a tag on logs

If you use asgi-correlation-id, there's a ready-made filter (install with pip install devstream-client[asgi]):

from devstream_client import CorrelationIdFilter

handler.addFilter(CorrelationIdFilter())  # adds a "correlation_id" tag

Django Integration

Add to your Django settings:

# settings.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'devstream': {
            'class': 'devstream_client.client.DevStreamHandler',
            'api_key': 'your-api-key',
            'app_key': 'my-django-app',
            'deployment_key': os.environ.get('DEPLOYMENT', 'local'),
            'base_url': 'http://localhost:8787',  # or your production URL
        },
    },
    'loggers': {
        'django': {
            'handlers': ['devstream'],
            'level': 'INFO',
        },
        'myapp': {
            'handlers': ['devstream'],
            'level': 'DEBUG',
        },
    },
}

Configuration

Client Parameters

  • api_key (required): Your DevStream API key
  • app_key (required): Application identifier
  • deployment_key (required): Deployment environment (e.g., 'local', 'dev', 'staging', 'production')
  • base_url (optional): DevStream service URL (default: http://localhost:8787)
  • timeout (optional): Per-request timeout in seconds (default: 5.0)
  • max_retries (optional): Automatic retries on connection errors and transient 5xx responses (default: 2)
  • retry_after_cap (optional): On a 429 Too Many Requests response, the maximum seconds to honour the server's Retry-After header before giving up (default: 10.0; set 0 to never wait). This bounds how long a send can block.

Rate limiting

If the server rate-limits ingestion it responds with 429 and a Retry-After header. The client waits for that interval and retries once, but only up to retry_after_cap seconds — beyond that it drops the log (returns False) rather than blocking your application. With the non-blocking DevStreamHandler this backpressure happens entirely on the background thread.

Scrubbing sensitive data (client-side)

Enable scrubbing to redact or mask sensitive data — emails, passwords, tokens, API keys, Bearer/JWT — from the message, data and tags before it leaves your application:

client = DevStreamClient(
    api_key="...", app_key="...", deployment_key="prod",
    scrub=True,            # off by default
    scrub_mode="redact",   # "redact" -> [EMAIL]/[REDACTED], or "mask" -> j***@x.com / ***1234
)
client.log("login user@example.com password=hunter2")
# sent as: "login [EMAIL] password=[REDACTED]"

The same options work on DevStreamHandler(..., scrub=True, scrub_mode="mask").

This is best-effort (regex-based) and complements the server-side scrubbing that can be enabled per application — use either or both. Client-side keeps the data off the network entirely; server-side covers every sender.

Structured Data

Pass a data dictionary to attach arbitrary JSON to a log message. It is stored alongside the message and returned by the API and log viewer:

client.log("Payment failed", data={"amount": 50, "currency": "USD", "code": "card_declined"})

Tags

Tags are key-value pairs that help you filter and search logs. You can add tags in two ways:

  1. As a list of dictionaries:
client.log("User action", tags=[
    {"name": "user_id", "value": "12345"},
    {"name": "action", "value": "login"}
])
  1. As keyword arguments:
client.log_with_tags(
    "User action",
    user_id="12345",
    action="login"
)

Features

  • Simple API for sending logs
  • Integration with Python's standard logging module
  • Support for custom tags
  • Automatic retry and error handling
  • Django-ready configuration

License

MIT License

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

devstream_client-0.4.0.tar.gz (13.4 kB view details)

Uploaded Source

Built Distribution

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

devstream_client-0.4.0-py3-none-any.whl (11.8 kB view details)

Uploaded Python 3

File details

Details for the file devstream_client-0.4.0.tar.gz.

File metadata

  • Download URL: devstream_client-0.4.0.tar.gz
  • Upload date:
  • Size: 13.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for devstream_client-0.4.0.tar.gz
Algorithm Hash digest
SHA256 f092550ed3db23e5a481a7943b6cf1e1a5469650abb3de1588a39292075789d7
MD5 121f646641a17c93dde4010f85d99330
BLAKE2b-256 191c2444baad53f3823f055f30ef1560be9fba250f5a5da78ca17c00c6ce5705

See more details on using hashes here.

File details

Details for the file devstream_client-0.4.0-py3-none-any.whl.

File metadata

File hashes

Hashes for devstream_client-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5a078d912333930ecbb605ee4471e0fae23b311bd304ce5c197c195037e8a391
MD5 bdcbba55e8ee1962dd7d0ae5bd06e9d4
BLAKE2b-256 a66f7bd7b82d3bb139e9dcdd95ff59398564d4d48fb4e280f212538485f997dc

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