Skip to main content

A Python library for collecting and sending telemetry data to Malti server

Project description

Malti Python SDK

PyPI version Python versions License: MIT

A Python library for collecting and sending telemetry data to Malti server using any Starlette-compatible framework.

Features

  • ๐Ÿš€ High Performance: Asynchronous batch processing with connection pooling
  • ๐Ÿ”’ Thread-Safe: Designed for multi-worker applications
  • ๐ŸŽฏ Clean Mode: Automatically filters out bot traffic (401/404 responses)
  • ๐ŸŒŸ Multi-Framework: Works with any Starlette-compatible framework (FastAPI, Starlette, Responder, etc.)
  • ๐Ÿ“Š Rich Telemetry: Collects method, endpoint, status, response time, consumer, and context
  • ๐Ÿ”„ Automatic Batching: Efficient batching with overflow protection
  • โšก Non-Blocking: Telemetry collection doesn't impact request performance
  • ๐Ÿ›ก๏ธ Retry Logic: Exponential backoff for failed requests
  • ๐ŸŽ›๏ธ Configurable: Extensive environment variable configuration
  • ๐Ÿ”ง Framework Optimized: Enhanced integrations for popular frameworks

Installation

pip install malti-telemetry

Quick Start

FastAPI Integration

from fastapi import FastAPI
from malti_telemetry.middleware import MaltiMiddleware

app = FastAPI()

# Add telemetry middleware (route patterns automatically extracted!)
app.add_middleware(MaltiMiddleware)

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return {"user_id": user_id, "name": "John Doe"}

# Recorded as: method=GET, endpoint="/users/{user_id}"

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app)

Starlette Integration

from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.responses import JSONResponse
from malti_telemetry.middleware import MaltiMiddleware

app = Starlette()

# Add telemetry middleware (lifespan auto-injected!)
app.add_middleware(Middleware(MaltiMiddleware))

@app.route("/users/{user_id}")
async def get_user(request):
    user_id = request.path_params["user_id"]
    return JSONResponse({"user_id": user_id, "name": "John Doe"})

# Recorded as: method=GET, endpoint="/users/{user_id}"

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app)

Responder Integration

from responder import API
from malti_telemetry.middleware import MaltiMiddleware

api = API()

# Add telemetry middleware (generic Starlette middleware works with Responder)
api.add_middleware(MaltiMiddleware)

@api.route("/users/{user_id}")
async def get_user(req, resp, *, user_id):
    resp.media = {"user_id": user_id, "name": "John Doe"}

Generic Starlette Middleware

from starlette.applications import Starlette
from starlette.middleware import Middleware
from malti_telemetry.middleware import MaltiMiddleware

app = Starlette()

# Add telemetry middleware (works with any Starlette framework)
app.add_middleware(Middleware(MaltiMiddleware))

@app.route("/api/data")
async def get_data(request):
    return JSONResponse({"data": "example"})

Environment Configuration

Set these environment variables before starting your application:

export MALTI_API_KEY="your-api-key-here"
export MALTI_SERVICE_NAME="my-fastapi-app"
export MALTI_URL="https://your-malti-server.com"
export MALTI_NODE="production-node-1"

Configuration

Environment Variables

Variable Default Description
MALTI_API_KEY (required) Your Malti API key
MALTI_SERVICE_NAME "unknown-service" Name of your service
MALTI_URL "http://localhost:8000" Malti server URL
MALTI_NODE "unknown-node" Node identifier
MALTI_BATCH_SIZE 500 Records per batch
MALTI_BATCH_INTERVAL 60.0 Seconds between batch sends
MALTI_MAX_RETRIES 3 Max retry attempts
MALTI_RETRY_DELAY 1.0 Base retry delay (seconds)
MALTI_HTTP_TIMEOUT 30.0 HTTP request timeout
MALTI_MAX_KEEPALIVE_CONNECTIONS 5 Max keepalive connections
MALTI_MAX_CONNECTIONS 10 Max total connections
MALTI_OVERFLOW_THRESHOLD_PERCENT 90.0 Buffer overflow threshold
MALTI_CLEAN_MODE true Ignore 401/404 responses

Programmatic Configuration

from malti_telemetry import configure_malti

configure_malti(
    service_name="my-service",
    api_key="your-api-key",
    malti_url="https://api.malti.dev",
    node="prod-web-01",
    batch_size=1000,
    clean_mode=True
)

Advanced Usage

Framework-Specific Features

FastAPI Features

Route Pattern Extraction: Automatic conversion of actual paths to route patterns:

  • /users/123 โ†’ /users/{user_id}
  • /api/v1/posts/456/comments โ†’ /api/v1/posts/{post_id}/comments
  • Works with nested routes and mount points

Context Information: Add context using FastAPI's request state:

from fastapi import Request

@app.route("/users/{user_id}")
async def get_user(request):
    user_id = request.path_params["user_id"]
    if user_id < 1000:
        request.state.context = "legacy"
    else:
        request.state.context = "current"
    return JSONResponse({"user_id": user_id, "name": "John Doe"})

Starlette Features

Automatic Lifespan Management: Telemetry system starts/stops automatically:

from starlette.applications import Starlette
from starlette.middleware import Middleware
from malti_telemetry.middleware import MaltiMiddleware

app = Starlette()
app.add_middleware(Middleware(MaltiMiddleware))  # Lifespan auto-injected!

# No need for manual lifespan management!

Route Pattern Extraction: Automatically extracts route patterns from Starlette routing:

from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.routing import Route, Mount
from malti_telemetry.middleware import MaltiMiddleware

app = Starlette()
app.add_middleware(Middleware(MaltiMiddleware))

async def user_handler(request):
    return JSONResponse({"user_id": request.path_params["user_id"]})

async def post_handler(request):
    return JSONResponse({"post_id": request.path_params["post_id"]})

# Works with all Starlette routing patterns
app.routes = [
    Route("/api/v1/users/{user_id}", endpoint=user_handler),
    Mount("/api/v2", routes=[
        Route("/posts/{post_id}", endpoint=post_handler),
    ]),
]

# Automatically recorded as:
# method=GET, endpoint="/api/v1/users/{user_id}"
# method=GET, endpoint="/api/v2/posts/{post_id}"

Consumer Identification

Malti automatically extracts consumer information from headers:

  1. x-consumer-id header (highest priority)
  2. x-user-id header (fallback)
  3. consumer-id header
  4. user-id header

Custom Consumer Extraction: Set consumer information in your framework:

# FastAPI
@app.middleware("http")
async def set_consumer(request: Request, call_next):
    request.state.malti_consumer = "app"
    return await call_next(request)

# Starlette
@app.middleware("http")
async def set_consumer(request, call_next):
    # Add consumer to ASGI scope
    request.scope["state"]["malti_consumer"] = "api"
    response = await call_next(request)
    return response

Manual Telemetry Recording

from malti_telemetry import get_telemetry_system

telemetry = get_telemetry_system()

# Record a custom event
telemetry.record_request(
    method="GET",
    endpoint="/api/custom",
    status=200,
    response_time=150,
    consumer="custom-client",
    context="manual-recording"
)

Statistics and Monitoring

from malti_telemetry import get_malti_stats

stats = get_malti_stats()
print(stats)
# {
#     'total_added': 1250,
#     'total_sent': 1200,
#     'total_failed': 50,
#     'current_size': 50,
#     'max_size': 25000,
#     'service_name': 'my-service',
#     'running': True
# }

Supported Frameworks

Malti Telemetry works with any Starlette-compatible framework:

  • FastAPI: Enhanced route pattern extraction and request.state integration
  • Starlette: Base middleware with full functionality and lifespan management
  • Responder: Works with generic Starlette middleware
  • Any ASGI framework: Generic middleware for custom implementations

Architecture

Core Components

  1. TelemetryCollector: Collects HTTP request telemetry data
  2. BatchSender: Sends batched telemetry data to Malti server
  3. TelemetrySystem: Combines collector and sender with unified interface
  4. TelemetryBuffer: Thread-safe buffer for storing records

Worker Process Model

Each FastAPI/Uvicorn worker process gets its own telemetry system instance:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Worker Process  โ”‚    โ”‚ Worker Process  โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚    โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚TelemetrySys โ”‚ โ”‚    โ”‚ โ”‚TelemetrySys โ”‚ โ”‚
โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚    โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
โ”‚ โ”‚ โ”‚Buffer   โ”‚ โ”‚ โ”‚    โ”‚ โ”‚ โ”‚Buffer   โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚    โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚    โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
โ”‚ โ”‚ โ”‚Sender   โ”‚ โ”‚ โ”‚    โ”‚ โ”‚ โ”‚Sender   โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚    โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚    โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Development

Setup

git clone https://github.com/muzy/malti-telemetry.git
cd python/
pip install -e ".[dev]"

Testing

pytest

Code Quality

black malti_telemetry/
isort malti_telemetry/
mypy malti_telemetry/
flake8 malti_telemetry/

License

MIT License - see LICENSE file 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

malti_telemetry-1.0.0.tar.gz (22.2 kB view details)

Uploaded Source

Built Distribution

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

malti_telemetry-1.0.0-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

Details for the file malti_telemetry-1.0.0.tar.gz.

File metadata

  • Download URL: malti_telemetry-1.0.0.tar.gz
  • Upload date:
  • Size: 22.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for malti_telemetry-1.0.0.tar.gz
Algorithm Hash digest
SHA256 20ba3198296410c565d57cf8b106fe93a900e32781224087e55f6ee7da828bcc
MD5 145bd16c9c0990d2480811c776bf3cd6
BLAKE2b-256 7e4c2f181a70d009daea422bc6eb48140bd76ae6595831a13b51f7f429faf15c

See more details on using hashes here.

Provenance

The following attestation bundles were made for malti_telemetry-1.0.0.tar.gz:

Publisher: publish-to-pypi.yml on muzy/malti-telemetry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file malti_telemetry-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for malti_telemetry-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f443c0eecacfd05a3aa52a6bd4709320d3a73ba457fc2a2e8085a9ab3437bd01
MD5 65c4c6cc0324dfff2cb20f0f04a1556a
BLAKE2b-256 4567ad632e25d8fad27bd4307e9e1b96e154eb6a8c25d8b952b1a93e0edb5829

See more details on using hashes here.

Provenance

The following attestation bundles were made for malti_telemetry-1.0.0-py3-none-any.whl:

Publisher: publish-to-pypi.yml on muzy/malti-telemetry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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