Metadata-Version: 2.4
Name: elven-opentelemetry-instrumentation-py
Version: 0.1.2
Summary: Universal OpenTelemetry bootstrap for Python services with elite-quality defaults, privacy, auto-instrumentation, traces, and metrics.
Project-URL: Homepage, https://github.com/elven/opentelemetry-instrumentation-py
Project-URL: Repository, https://github.com/elven/opentelemetry-instrumentation-py
Author: Leonardo Zwirtes
License: Apache-2.0
Keywords: instrumentation,metrics,observability,opentelemetry,python,tracing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.10
Requires-Dist: opentelemetry-api<1.41.0,>=1.40.0
Requires-Dist: opentelemetry-distro<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-exporter-otlp<1.41.0,>=1.40.0
Requires-Dist: opentelemetry-instrumentation-aiohttp-client<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-asgi<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-asyncio<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-boto3sqs<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-celery<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-django<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-fastapi<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-flask<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-grpc<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-httpx<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-kafka-python<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-logging<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-pika<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-psycopg2<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-psycopg<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-pymongo<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-pymysql<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-redis<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-requests<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-sqlalchemy<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-threading<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-urllib3<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation-wsgi<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-instrumentation<0.62.0,>=0.61b0
Requires-Dist: opentelemetry-propagator-b3<1.41.0,>=1.40.0
Requires-Dist: opentelemetry-sdk<1.41.0,>=1.40.0
Provides-Extra: dev
Requires-Dist: aiohttp>=3.12.0; extra == 'dev'
Requires-Dist: boto3>=1.42.0; extra == 'dev'
Requires-Dist: build>=1.4.0; extra == 'dev'
Requires-Dist: celery>=5.6.0; extra == 'dev'
Requires-Dist: django>=5.2.0; extra == 'dev'
Requires-Dist: fastapi>=0.115.0; extra == 'dev'
Requires-Dist: flask>=3.1.0; extra == 'dev'
Requires-Dist: graphql-core>=3.2.8; extra == 'dev'
Requires-Dist: grpcio>=1.76.0; extra == 'dev'
Requires-Dist: hatchling>=1.29.0; extra == 'dev'
Requires-Dist: httpx>=0.28.0; extra == 'dev'
Requires-Dist: kafka-python>=2.2.0; extra == 'dev'
Requires-Dist: loguru>=0.7.0; extra == 'dev'
Requires-Dist: pika>=1.3.0; extra == 'dev'
Requires-Dist: psycopg2-binary>=2.9.0; extra == 'dev'
Requires-Dist: psycopg[binary]>=3.2.0; extra == 'dev'
Requires-Dist: pymongo>=4.14.0; extra == 'dev'
Requires-Dist: pymysql>=1.1.0; extra == 'dev'
Requires-Dist: pyright>=1.1.408; extra == 'dev'
Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
Requires-Dist: pytest-cov>=7.1.0; extra == 'dev'
Requires-Dist: pytest>=9.0.0; extra == 'dev'
Requires-Dist: redis>=7.4.0; extra == 'dev'
Requires-Dist: requests>=2.32.0; extra == 'dev'
Requires-Dist: ruff>=0.15.0; extra == 'dev'
Requires-Dist: sqlalchemy>=2.0.0; extra == 'dev'
Requires-Dist: strawberry-graphql>=0.312.0; extra == 'dev'
Requires-Dist: structlog>=25.5.0; extra == 'dev'
Requires-Dist: urllib3>=2.5.0; extra == 'dev'
Provides-Extra: full
Requires-Dist: aiohttp>=3.12.0; extra == 'full'
Requires-Dist: boto3>=1.42.0; extra == 'full'
Requires-Dist: celery>=5.6.0; extra == 'full'
Requires-Dist: django>=5.2.0; extra == 'full'
Requires-Dist: fastapi>=0.115.0; extra == 'full'
Requires-Dist: flask>=3.1.0; extra == 'full'
Requires-Dist: graphql-core>=3.2.8; extra == 'full'
Requires-Dist: grpcio>=1.76.0; extra == 'full'
Requires-Dist: httpx>=0.28.0; extra == 'full'
Requires-Dist: kafka-python>=2.2.0; extra == 'full'
Requires-Dist: pika>=1.3.0; extra == 'full'
Requires-Dist: psycopg2-binary>=2.9.0; extra == 'full'
Requires-Dist: psycopg[binary]>=3.2.0; extra == 'full'
Requires-Dist: pymongo>=4.14.0; extra == 'full'
Requires-Dist: pymysql>=1.1.0; extra == 'full'
Requires-Dist: redis>=7.4.0; extra == 'full'
Requires-Dist: requests>=2.32.0; extra == 'full'
Requires-Dist: structlog>=25.5.0; extra == 'full'
Requires-Dist: urllib3>=2.5.0; extra == 'full'
Description-Content-Type: text/markdown

# OpenTelemetry Instrumentation Python (v1)

Python-first OpenTelemetry bootstrap for backend services, focused on:

- deterministic startup and shutdown
- explicit feature toggles for tracing, metrics and instrumentations
- strict privacy defaults for database statements and user identifiers
- zero-code startup through the official distro/configurator mechanism
- log correlation only, with no log export pipeline inside this package

## Installation

```bash
pip install "elven-opentelemetry-instrumentation-py[full]"
```

## Runtime support

`v1` supports `runtime="python"` only.

Passing `runtime="serverless"` or `runtime="edge"` raises an explicit error.

## Zero-code

```bash
export OTEL_SERVICE_NAME="my-service"
export OTEL_SERVICE_VERSION="1.0.0"
elven-otel-instrument python app.py
```

Disable wrapper initialization explicitly:

```bash
export OTEL_ZERO_CODE=false
```

## Kubernetes Operator

Build the Python auto-instrumentation image expected by the OpenTelemetry Operator:

```bash
docker build -f Dockerfile.operator -t your-registry/elven-opentelemetry-instrumentation-py:0.1.2 .
```

Use that image in the `Instrumentation` resource:

```yaml
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: instrumentation
spec:
  exporter:
    endpoint: "http://opentelemetrycollector.monitoring.svc.cluster.local:4318"
  propagators:
    - tracecontext
    - baggage
    - b3
    - b3multi
  sampler:
    type: parentbased_traceidratio
    argument: "1"
  python:
    image: docker.io/elvenobservability/python-k8s-operator:latest
    env:
      - name: OTEL_PYTHON_DISTRO
        value: "elven"
      - name: OTEL_PYTHON_CONFIGURATOR
        value: "elven"
      - name: OTEL_PYTHON_LOG_AUTO_INSTRUMENTATION
        value: "false"
      - name: OTEL_LOGS_EXPORTER
        value: "none"
      - name: OTEL_EXPORTER_OTLP_PROTOCOL
        value: "http/protobuf"
      - name: OTEL_METRICS_EXPORTER
        value: "otlp"
      - name: OTEL_TRACES_EXPORTER
        value: "otlp"
      - name: OTEL_EXPORTER_OTLP_ENDPOINT
        value: "http://opentelemetrycollector.monitoring.svc.cluster.local:4318"
```

This image ships both `/autoinstrumentation` and `/autoinstrumentation-musl`, sets
`OTEL_PYTHON_DISTRO=elven`, sets `OTEL_PYTHON_CONFIGURATOR=elven`, and keeps logs export disabled by default to match the package contract.

If you prefer split endpoints, keep the same `http/protobuf` protocol and point both variables to the collector HTTP port:

```yaml
- name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
  value: "http://opentelemetrycollector.monitoring.svc.cluster.local:4318/v1/traces"
- name: OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
  value: "http://opentelemetrycollector.monitoring.svc.cluster.local:4318/v1/metrics"
```

For Alpine-based workloads, add:

```yaml
metadata:
  annotations:
    instrumentation.opentelemetry.io/otel-python-platform: "musl"
```

## Manual initialization

```python
from opentelemetry.sdk.trace.sampling import Decision

from elven_opentelemetry_instrumentation import (
    MetricsConfig,
    ObservabilityConfig,
    PrivacyConfig,
    SamplingRule,
    ServiceConfig,
    TracingConfig,
    init_observability,
)

handle = init_observability(
    ObservabilityConfig(
        service=ServiceConfig(
            service_name="payment-service",
            service_version="1.0.0",
            deployment_environment="production",
        ),
        tracing=TracingConfig(
            enabled=True,
            rules=[
                SamplingRule(
                    attribute_key="http.route",
                    attribute_value="/healthz",
                    decision=Decision.DROP,
                ),
            ],
        ),
        metrics=MetricsConfig(enabled=True, export_interval_millis=60_000),
        privacy=PrivacyConfig(
            redact_db_statement=True,
            hash_user_id=True,
        ),
    )
)

handle.tracer.with_span("startup", lambda span: span.set_attribute("boot.ready", True))
handle.metrics.increment("jobs.started", 1)
handle.force_flush()
handle.shutdown()
```

## Public API

`init_observability(config)` returns an `ObservabilityHandle` with:

- `tracer`
- `metrics`
- `shutdown()`
- `force_flush()`
- `is_started()`

The initializer is idempotent and protects against duplicate startup.

## Feature precedence

For booleans, precedence is:

1. explicit config
2. environment variable
3. package default

Examples:

- `OTEL_TRACES_EXPORTER=none` disables traces by default
- `TracingConfig(enabled=True)` overrides that default
- `OTEL_INSTR_PSYCOPG=false` disables psycopg instrumentation unless explicitly enabled in config

## Supported coverage

- Web: ASGI, WSGI, FastAPI, Flask, Django
- GraphQL: request-level enrichment plus operation and field spans through `graphql-core`
- HTTP clients: requests, httpx, urllib3, aiohttp-client
- Data: SQLAlchemy, psycopg, psycopg2, pymysql, mysqlclient, Redis, MongoDB
- Workers and queues: Celery, threading, asyncio, gRPC, Kafka, RabbitMQ/Pika, SQS via boto3
- Logging: stdlib logging correlation

Instrumentation is activated only when the target library is installed and enabled.

## Development

```bash
python -m venv .venv
. .venv/bin/activate
pip install -e ".[dev]"
ruff check .
pyright
pytest
```
