Skip to main content

Rust + OpenTelemetry powered Python bindings for traces, metrics, and logs (SLS-first)

Project description

pytracingx

中文版 README

Rust + OpenTelemetry powered Python bindings for traces, metrics and logs, with first-class support for Aliyun SLS and ARMS as OTLP backends.

Why pytracingx over Python OpenTelemetry SDK?

pytracingx (Rust) opentelemetry-python
Performance Serialization (protobuf), compression (gzip/lz4), batching, network I/O all happen on Rust native threads — never holds the GIL Every export step runs on Python threads under the GIL; 5–15% CPU overhead is measurable under heavy span/metric load
Memory Span/metric data structures live on the Rust heap, zero Python object overhead Each span is a Python object with dict attributes; significant GC pressure under high traffic
Startup Single .so file, import pytracingx ~15ms Pulls in opentelemetry-api + -sdk + -exporter-otlp + grpcio/protobuf and a dozen others, cold start 200–500ms
Dependencies Zero Python runtime deps (everything compiled into the native module) Drags in grpcio (C build), protobuf, googleapis-common-protos; wheel size > 50MB
GIL friendliness start_span() / counter.add() / logger.info() only do FFI argument conversion (μs), then drop the GIL Python SDK's start_span does context management, attribute serialization and sampler decisions in Python (10–50μs) holding the GIL throughout
Async safety Span context lives in contextvars, naturally inherited by asyncio.Task; the Rust tracing layer doesn't depend on the Python event loop BatchSpanProcessor spawns extra daemon threads and uses threading.Event; occasional races when paired with uvloop
Console output tracing's fmt::Layer unifies span begin/end + log events with compact / pretty / json formats Needs a separate ConsoleSpanExporter plus a logging handler; two inconsistent formats
Native SLS Built-in SlsLogSink writes to any logstore directly (protobuf + lz4 + HMAC signing all done in Rust) Requires aliyun-log-python-sdk or hand-rolled HTTP upload
Single wheel One abi3-py39 wheel covers Python 3.9–3.13+ across all platforms (manylinux/macOS/Windows) grpcio wheel must be built per Python version per platform

When to use it

  • High-QPS services (>1000 RPS): Rust handles batch export in the background; per-call overhead < 1μs on the Python side
  • Latency-sensitive workloads: span export never blocks the GIL
  • Containers / serverless: single-file deploy, fast cold start, no grpcio compilation
  • Aliyun full stack: traces → ARMS, metrics → ARMS, logs → any SLS logstore — one Config covers all

Observability for the AI era — built for LLM inference

In LLM / large model inference, any CPU-side observability cost translates directly into GPU underutilization. When the Python main thread is busy with trace serialization, log formatting and metric aggregation, GPU kernel launches, KV-cache scheduling and batch composition all get delayed. Symptoms include:

  • TTFT (Time To First Token) jitter: span export blocks the GIL and request enqueue is delayed
  • GPU bubbles: the CPU can't feed data fast enough, GPU SMs idle, throughput drops
  • Degraded batch scheduling: vLLM / SGLang schedulers depend on a low-latency event loop; daemon threads from the Python SDK fight uvloop and break continuous batching

pytracingx's Rust-native design fits these scenarios naturally:

Pain point Traditional Python SDK pytracingx
GPU scheduling blocked by GIL start_span holds GIL for 10–50μs, preempting inference steps FFI argument copy then GIL released, μs-level return
Token-level tracing overhead Per-token spans create heavy Python GC pressure Spans allocated on the Rust heap, zero impact on Python GC
Prompt/completion log volume Large payloads serialized in Python slow down the main loop Protobuf + async batching all run inside the Rust tokio runtime
Multi-GPU / multi-process deployment Each worker loads the full Python OTel stack, doubling memory Single .so, shared abi3 wheel, < 5MB resident overhead beyond GPU memory

Inference service integration pattern

# At the entry point of vLLM / SGLang / TGI etc.
with ptx.start_span("llm.inference", attributes={
    "llm.model": "qwen2.5-72b",
    "llm.prompt_tokens": prompt_len,
    "gen.batch_size": batch_size,
}) as span:
    output = engine.generate(prompts)        # GPU work runs undisturbed
    span.set_attribute("llm.completion_tokens", output.usage.completion_tokens)
    span.set_attribute("llm.ttft_ms", output.metrics.first_token_ms)

Suggested observation dimensions:

  • Trace: end-to-end request → tokenize → schedule → prefill → decode → detokenize
  • Metrics: TTFT / TPOT (Time Per Output Token) / GPU SM utilization / KV-cache hit rate
  • Logs: sample prompt / completion to SLS for offline RAG / fine-tuning data

Core idea: observability should be part of the AI infrastructure, not a performance tax.

Architecture

Python  ──►  ptx.start_span / ptx.get_logger / ptx.get_meter
                                │
                                ▼
                        tracing crate (Rust)
              ┌──────────────────┴──────────────────┐
              │                                     │
        fmt::Layer                       tracing-opentelemetry
        (terminal)                  + opentelemetry-appender-tracing
                                    + SlsLogLayer (native SLS)
                                                    │
                                                    ▼
                            SdkTracerProvider / SdkLoggerProvider / SdkMeterProvider
                                       opentelemetry-otlp (async reqwest)
                                                    │
                                                    ▼
                                   SLS / ARMS / any OTLP Collector

Each signal is configured via a Sink object. A signal is enabled if its Sink appears in the sinks list.

Installation

pip install pytracingx

Pre-built wheels are available on PyPI for:

  • Linux x86_64 / aarch64 — manylinux_2_28 (glibc) and musllinux_1_2 (Alpine)
  • macOS — universal2 (Intel + Apple Silicon)
  • Windows — x64 (MSVC)
  • Python 3.9, 3.10, 3.11, 3.12, 3.13+ (single abi3 wheel)

No Rust toolchain or system OpenSSL is required at install time — everything is statically linked into the wheel.

Quickstart

import asyncio
import pytracingx as ptx

async def main():
    ptx.init(ptx.Config(
        service_name="payment-svc",
        resource_attributes={"deployment.environment": "prod"},
        sinks=[
            # Traces + Metrics → ARMS
            ptx.TraceSink(
                endpoint="http://tracing-xxx.arms.aliyuncs.com/.../api/otlp/traces",
                protocol="http/protobuf",
                sampler="parent_based_traceid_ratio",
                sampler_arg=0.5,
            ),
            ptx.MetricSink(
                endpoint="http://tracing-xxx.arms.aliyuncs.com/.../api/otlp/metrics",
                protocol="http/protobuf",
                export_interval_ms=30_000,
            ),
            # Logs → SLS native (any logstore)
            ptx.SlsLogSink(
                endpoint="cn-hangzhou.log.aliyuncs.com",
                project="my-proj",
                logstore="app-logs",
                ak_id="...",
                ak_secret="...",
            ),
        ],
    ))

    meter = ptx.get_meter("payment")
    logger = ptx.get_logger("payment")
    orders = meter.counter("orders_total")

    with ptx.start_span("checkout", kind="server", attributes={"user.id": "u1"}) as span:
        orders.add(1, attributes={"sku": "abc"})
        logger.info("checkout done", attributes={"sku": "abc"})
        span.set_attribute("amount", 12.34)

    ptx.shutdown()

asyncio.run(main())

Sink Types

Sink Backend Protocol Use Case
TraceSink Any OTLP collector gRPC / HTTP Distributed tracing spans
MetricSink Any OTLP collector gRPC / HTTP Counters, histograms, gauges
OtlpLogSink Any OTLP collector gRPC / HTTP Logs via OTLP (lands in the trace instance's -logs logstore on SLS)
SlsLogSink Aliyun SLS native API HTTPS Logs to any SLS logstore (not limited to the trace instance)

Console-only mode

# No sinks → no network, just terminal output
ptx.init(ptx.Config(service_name="my-app", console_level="debug"))

Context propagation (server side)

# with-syntax auto-restores context on exit
with ptx.extract_headers(dict(request.headers)):
    with ptx.start_span("POST /api/orders", kind="server") as span:
        ...

Examples and benchmarks

  • examples/demo.py — comprehensive async example covering traces + metrics + logs + context propagation
  • examples/fastapi_middleware.py — FastAPI middleware that creates a server span per request and propagates W3C trace context
  • examples/traces_to_xtrace.py — route traces to ARMS while metrics/logs go to SLS
  • benchmarks/ — microbenchmarks comparing pytracingx vs opentelemetry-python on the hot path

Bridging stdlib logging

import logging
from pytracingx.logging import SLSLoggingHandler

logging.basicConfig(level=logging.INFO, handlers=[SLSLoggingHandler()])
logging.getLogger("foo").info("hello from stdlib")

Building from source

pip install maturin
maturin develop --release

Requires Rust >= 1.85 (edition 2024) and Python >= 3.9. Wheels are abi3 (abi3-py39).

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

pytracingx-0.2.0.tar.gz (68.9 kB view details)

Uploaded Source

Built Distributions

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

pytracingx-0.2.0-cp39-abi3-win_amd64.whl (5.3 MB view details)

Uploaded CPython 3.9+Windows x86-64

pytracingx-0.2.0-cp39-abi3-musllinux_1_2_x86_64.whl (8.1 MB view details)

Uploaded CPython 3.9+musllinux: musl 1.2+ x86-64

pytracingx-0.2.0-cp39-abi3-musllinux_1_2_aarch64.whl (8.0 MB view details)

Uploaded CPython 3.9+musllinux: musl 1.2+ ARM64

pytracingx-0.2.0-cp39-abi3-manylinux_2_28_x86_64.whl (7.9 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ x86-64

pytracingx-0.2.0-cp39-abi3-manylinux_2_28_aarch64.whl (7.6 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.28+ ARM64

pytracingx-0.2.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (10.6 MB view details)

Uploaded CPython 3.9+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file pytracingx-0.2.0.tar.gz.

File metadata

  • Download URL: pytracingx-0.2.0.tar.gz
  • Upload date:
  • Size: 68.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pytracingx-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f8a48992607c1e52a00a191f8e90470554d5a1b32e8943fb36e42e9c01ee6c94
MD5 a1a13770f934fcbc48b1a3241fe5d9ff
BLAKE2b-256 a689dc5938b36c46a8afd28f22e93d49e72b49ac41a6ec63297e4624ef2e25ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytracingx-0.2.0.tar.gz:

Publisher: release.yml on smallsunsun1/pytracingx

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

File details

Details for the file pytracingx-0.2.0-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: pytracingx-0.2.0-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 5.3 MB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pytracingx-0.2.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 d8de32b7c33200f3622fba2aff8dfd51af5f5aca0e7250efab9e61ec513c0093
MD5 922101f7b3885db2c9f517b3576d2c33
BLAKE2b-256 235e3f8c2f1573d86200fd1dbf2efdfa23c82d88b94677112d9b27ad4fcd6d76

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytracingx-0.2.0-cp39-abi3-win_amd64.whl:

Publisher: release.yml on smallsunsun1/pytracingx

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

File details

Details for the file pytracingx-0.2.0-cp39-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for pytracingx-0.2.0-cp39-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 4014e6d053eff0e2a807f16ba64d1dea3f04dd30de55434e0fbde24f2358cd1e
MD5 d05751e24fad519710b63d6471b0bf45
BLAKE2b-256 afe85c7b5b306013c50840e45d8c0956395ee6e8da7d21e44934a6565af3be8f

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytracingx-0.2.0-cp39-abi3-musllinux_1_2_x86_64.whl:

Publisher: release.yml on smallsunsun1/pytracingx

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

File details

Details for the file pytracingx-0.2.0-cp39-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for pytracingx-0.2.0-cp39-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 0aabb49c8b2ab774e2f237e6d5b0c54e7ed8a3bdd00f184ae6e0d8db14c230f0
MD5 f6d9687c3610e8b37a7e6f54c655038c
BLAKE2b-256 c9f9e5f6e485e1e9ee8b1ba0e857198cdfdf4b9106ce683a9859064ce6f0cd7d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytracingx-0.2.0-cp39-abi3-musllinux_1_2_aarch64.whl:

Publisher: release.yml on smallsunsun1/pytracingx

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

File details

Details for the file pytracingx-0.2.0-cp39-abi3-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pytracingx-0.2.0-cp39-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 a82bde01420fb7ab7733b6b2d2f822f74be49e8d4f6b974553b4889026b61078
MD5 4f1d33040340c4a872fa04b2daaa2f31
BLAKE2b-256 87538f44259f70fb60ea25ecfef5a355c86f5ea506174b22d9d45cb44f60fa03

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytracingx-0.2.0-cp39-abi3-manylinux_2_28_x86_64.whl:

Publisher: release.yml on smallsunsun1/pytracingx

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

File details

Details for the file pytracingx-0.2.0-cp39-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pytracingx-0.2.0-cp39-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 9eeee39cc0a3733b8c824fdd1458f81a93ab2d4d22f4e30b11288f3cb8f2261b
MD5 a3367e7889d7e7d8d48861dab6a7aa79
BLAKE2b-256 cbbec68ba33a90caeb42f541a7702bea360a13404b9b1f9c9261de789d00f262

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytracingx-0.2.0-cp39-abi3-manylinux_2_28_aarch64.whl:

Publisher: release.yml on smallsunsun1/pytracingx

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

File details

Details for the file pytracingx-0.2.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for pytracingx-0.2.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 d25f1d033c0a4938d14ded83d80a9a00ed45e33889fd33137983ab0d99468098
MD5 90261c24771aac8b24530b6a3e9d57be
BLAKE2b-256 05fa40bdfe90f6e2593d7f58bd87d3431d495cc292c5683e67f7019293326a1a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytracingx-0.2.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: release.yml on smallsunsun1/pytracingx

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