# Instrumentação Python com Elven Observability

***

### Sumário

* Visão geral
* Pré-requisitos
* Instalação
* Quick Start — Zero-Code (recomendado)
* Quick Start — Inicialização manual
* Configuração por variáveis de ambiente
* Guia por framework
* Usando logger, tracer e metrics
* Instrumentações automáticas
* Configuração avançada
* Boas práticas
* Deploy com Docker
* Troubleshooting
* FAQ

***

### Visão geral

A instrumentação Python da Elven é composta por **um pacote unificado** que coordena dois componentes internos:

```
┌──────────────────────────────────────────────────────────┐
│              elven-unified-observability-py               │
│                                                          │
│  ┌────────────────────────┐  ┌────────────────────────┐  │
│  │  Logs Interceptor      │  │  OTel Instrumentation  │  │
│  │                        │  │                        │  │
│  │  - Captura logs        │  │  - Traces distribuídos │  │
│  │  - Intercepta console  │  │  - Métricas            │  │
│  │  - Batching + retry    │  │  - Auto-instrumentação │  │
│  │  - Envia para Loki     │  │  - Exporta via OTLP    │  │
│  └───────────┬────────────┘  └───────────┬────────────┘  │
│              │                           │               │
└──────────────┼───────────────────────────┼───────────────┘
               │                           │
               ▼                           ▼
    Elven Loki Gateway            Elven OTLP Collector
         (logs)                  (traces & métricas)
```

| Componente                                   | O que faz                                                                      |
| -------------------------------------------- | ------------------------------------------------------------------------------ |
| **`elven-unified-observability-py`**         | Pacote principal — instale apenas este. Coordena bootstrap, config e lifecycle |
| **`elven-logs-interceptor-python`**          | Pipeline de logs: captura, filtra, faz batching e envia para Loki              |
| **`elven-opentelemetry-instrumentation-py`** | Distro OTel: configura traces, métricas, auto-instrumentação e privacy         |

> **Você só precisa instalar o pacote unificado.** As dependências são resolvidas automaticamente.

***

### Pré-requisitos

* **Python 3.11+**
* **pip** (ou gerenciador de pacotes compatível)
* Credenciais da Elven Observability:
  * **Tenant ID**
  * **API Token**
  * **Endpoint OTLP** (para traces/métricas)
  * **Endpoint Loki** (para logs)

***

### Instalação

#### Instalação básica

```bash
pip install elven-unified-observability-py
```

#### Instalação com extras completos (recomendado)

Inclui compressão avançada (brotli), serialização otimizada (orjson) e integrações de framework:

```bash
pip install "elven-unified-observability-py[full]"
```

#### Verificar instalação

```bash
python -c "import elven_unified_observability; print('OK')"
```

***

### Quick Start — Zero-Code (recomendado)

O modo **zero-code** instrumenta sua aplicação sem nenhuma alteração no código fonte. A lib injeta um `sitecustomize.py` que inicializa tudo antes da sua app rodar.

#### 1. Crie um arquivo `.env` na raiz do projeto

```bash
# === Identidade do serviço ===
OTEL_SERVICE_NAME=meu-servico-api
OTEL_SERVICE_VERSION=1.0.0
OTEL_DEPLOYMENT_ENVIRONMENT=production

# === Telemetria (traces + métricas) ===
OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.elvenobservability.com
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp

# === Logs ===
LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push
LOGS_TENANT=seu-tenant-id
LOGS_TOKEN=seu-api-token
LOGS_COMPRESSION=gzip

# === Controle unificado ===
UO_ENABLE_LOGGING=true
UO_ENABLE_METRICS=true
UO_ENABLE_TRACING=true
```

#### 2. Rode sua aplicação com a CLI

```bash
elven-unified-observability -- python app.py
```

Funciona com qualquer comando:

```bash
# FastAPI com Uvicorn
elven-unified-observability -- uvicorn app:app --host 0.0.0.0 --port 8000

# Flask
elven-unified-observability -- flask --app app run

# Celery worker
elven-unified-observability -- celery -A worker.app worker -l info

# Módulo Python
elven-unified-observability -- python -m meu_servico
```

**Pronto!** Traces, métricas e logs já estão sendo coletados.

***

### Quick Start — Inicialização manual

Use esta abordagem quando precisar de controle programático sobre a inicialização, ou quando não puder usar a CLI.

#### Exemplo mínimo

```python
from elven_unified_observability import init, logger, tracer, metrics

handle = init({
    "service": {
        "serviceName": "meu-servico-api",
        "serviceVersion": "1.0.0",
        "environment": "production",
    },
    "logging": {
        "transport": {
            "url": "https://loki.elvenobservability.com/loki/api/v1/push",
            "tenantId": "seu-tenant-id",
            "authToken": "seu-api-token",
        },
    },
    "telemetry": {
        "exporters": {
            "protocol": "http/protobuf",
        },
    },
    "enableLogging": True,
    "enableMetrics": True,
    "enableTracing": True,
})

# Usar os proxies globais
logger.info("aplicação iniciada", {"version": "1.0.0"})
metrics.increment("app_startups_total", 1)

def do_work(span):
    span.set_attribute("work.type", "processing")
    return {"result": "ok"}

result = tracer.with_span("meu-trabalho", do_work)

# No shutdown da aplicação
handle.force_flush()
handle.shutdown()
```

#### Inicialização a partir do ambiente

Se as variáveis de ambiente já estiverem configuradas (ex: Kubernetes, Docker):

```python
from elven_unified_observability import init_from_env, logger

handle = init_from_env()

logger.info("serviço pronto")
```

***

### Configuração por variáveis de ambiente

#### Identidade do serviço

Estas variáveis definem como o serviço aparece na Elven Observability. A resolução segue uma ordem de precedência:

| Atributo  | 1a opção                      | 2a opção           | 3a opção                  | Default           |
| --------- | ----------------------------- | ------------------ | ------------------------- | ----------------- |
| Nome      | `OTEL_SERVICE_NAME`           | `LOGS_APP_NAME`    | `LOKI_APP_NAME`           | `unknown-service` |
| Versão    | `OTEL_SERVICE_VERSION`        | `LOGS_APP_VERSION` | `LOKI_APP_VERSION`        | `1.0.0`           |
| Ambiente  | `OTEL_DEPLOYMENT_ENVIRONMENT` | `LOGS_ENVIRONMENT` | `ENVIRONMENT` / `APP_ENV` | `development`     |
| Namespace | `OTEL_SERVICE_NAMESPACE`      | —                  | —                         | —                 |

#### Controle unificado (wrapper)

| Variável            | Descrição                                                  | Default               |
| ------------------- | ---------------------------------------------------------- | --------------------- |
| `UO_ENABLED`        | Liga/desliga todos os sinais de uma vez                    | `true`                |
| `UO_ENABLE_LOGGING` | Override para logs                                         | valor de `UO_ENABLED` |
| `UO_ENABLE_METRICS` | Override para métricas                                     | valor de `UO_ENABLED` |
| `UO_ENABLE_TRACING` | Override para tracing                                      | valor de `UO_ENABLED` |
| `UO_STRICT`         | Se `true`, falha o bootstrap se qualquer componente falhar | `false`               |
| `UO_LOAD_DOTENV`    | Carregar `.env` automaticamente no preload/CLI             | `true`                |
| `UO_DOTENV_PATH`    | Caminho alternativo para o arquivo `.env`                  | `.env`                |

#### Telemetria — Traces e Métricas

| Variável                         | Descrição                                         | Default         |
| -------------------------------- | ------------------------------------------------- | --------------- |
| `OTEL_EXPORTER_OTLP_ENDPOINT`    | URL do coletor OTLP                               | —               |
| `OTEL_EXPORTER_OTLP_PROTOCOL`    | Protocolo: `http/protobuf` ou `grpc`              | `http/protobuf` |
| `OTEL_EXPORTER_OTLP_HEADERS`     | Headers extras (formato `key=value,key2=value2`)  | —               |
| `OTEL_EXPORTER_OTLP_COMPRESSION` | Compressão: `gzip` ou `none`                      | `gzip`          |
| `OTEL_TRACES_EXPORTER`           | Exporter de traces: `otlp`, `console` ou `none`   | `otlp`          |
| `OTEL_METRICS_EXPORTER`          | Exporter de métricas: `otlp`, `console` ou `none` | `otlp`          |
| `OTEL_TRACING_ENABLED`           | Habilitar/desabilitar tracing explicitamente      | `true`          |
| `OTEL_METRICS_ENABLED`           | Habilitar/desabilitar métricas explicitamente     | `true`          |
| `OTEL_METRIC_EXPORT_INTERVAL`    | Intervalo de export de métricas (ms)              | `60000`         |
| `OTEL_METRIC_EXPORT_TIMEOUT`     | Timeout de export de métricas (ms)                | `30000`         |

#### Telemetria — Privacy

| Variável                           | Descrição                         | Default |
| ---------------------------------- | --------------------------------- | ------- |
| `OTEL_PRIVACY_REDACT_DB_STATEMENT` | Redactar statements SQL nos spans | `false` |
| `OTEL_PRIVACY_HASH_USER_ID`        | Fazer hash de user IDs nos spans  | `false` |

#### Logs — Transporte

| Variável           | Descrição                                | Default |
| ------------------ | ---------------------------------------- | ------- |
| `LOGS_URL`         | URL completa do Loki push endpoint       | —       |
| `LOGS_TENANT`      | Tenant ID (header `X-Scope-OrgID`)       | —       |
| `LOGS_TOKEN`       | Token de autenticação (Bearer)           | —       |
| `LOGS_COMPRESSION` | Compressão: `gzip`, `brotli`, `none`     | `gzip`  |
| `LOGS_TIMEOUT`     | Timeout HTTP (segundos)                  | `10`    |
| `LOGS_MAX_RETRIES` | Número de retentativas                   | `3`     |
| `LOGS_RETRY_DELAY` | Delay base entre retentativas (segundos) | `1`     |

> **Fallback `LOKI_*`:** Todas as variáveis `LOGS_*` aceitam o prefixo `LOKI_*` como fallback. Ex: `LOKI_URL`, `LOKI_TENANT`, `LOKI_TOKEN`.

#### Logs — Buffer e Filtro

| Variável                         | Descrição                                 | Default                       |
| -------------------------------- | ----------------------------------------- | ----------------------------- |
| `LOGS_BUFFER_MAX_SIZE`           | Tamanho máximo do buffer de logs          | `100`                         |
| `LOGS_BUFFER_FLUSH_INTERVAL`     | Intervalo de flush (segundos)             | `5`                           |
| `LOGS_BUFFER_MAX_MEMORY_MB`      | Limite de memória do buffer (MB)          | —                             |
| `LOGS_FILTER_LEVELS`             | Níveis permitidos (separados por vírgula) | `debug,info,warn,error,fatal` |
| `LOGS_FILTER_SAMPLING_RATE`      | Taxa de amostragem (0.0 a 1.0)            | `1.0`                         |
| `LOGS_FILTER_MAX_MESSAGE_LENGTH` | Tamanho máximo da mensagem                | —                             |

#### Logs — Resiliência

| Variável                                 | Descrição                                      | Default  |
| ---------------------------------------- | ---------------------------------------------- | -------- |
| `LOGS_CIRCUIT_BREAKER_ENABLED`           | Habilitar circuit breaker                      | `true`   |
| `LOGS_CIRCUIT_BREAKER_FAILURE_THRESHOLD` | Falhas para abrir o circuito                   | `5`      |
| `LOGS_CIRCUIT_BREAKER_RESET_TIMEOUT`     | Tempo para tentar fechar o circuito (segundos) | `30`     |
| `LOGS_DLQ_ENABLED`                       | Habilitar Dead Letter Queue                    | `false`  |
| `LOGS_DLQ_TYPE`                          | Tipo: `memory` ou `file`                       | `memory` |
| `LOGS_DLQ_MAX_SIZE`                      | Tamanho máximo da DLQ                          | `1000`   |

#### Logs — Interceptação

| Variável                         | Descrição                                        | Default |
| -------------------------------- | ------------------------------------------------ | ------- |
| `LOGS_INTERCEPT_CONSOLE`         | Capturar `print()` e root logger                 | `false` |
| `LOGS_PRESERVE_ORIGINAL_CONSOLE` | Manter output original no console ao interceptar | `true`  |
| `LOGS_DEBUG`                     | Logs de debug interno da lib                     | `false` |

#### Labels customizados

Qualquer variável com prefixo `LOGS_LABEL_` vira um label no Loki:

```bash
LOGS_LABEL_TEAM=backend
LOGS_LABEL_SQUAD=payments
LOGS_LABEL_CLUSTER=prod-us
```

Resultado no Loki: labels `team=backend`, `squad=payments`, `cluster=prod-us`.

***

### Guia por framework

#### FastAPI

```bash
# .env
OTEL_SERVICE_NAME=minha-api
OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.elvenobservability.com
LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push
LOGS_TENANT=meu-tenant
LOGS_TOKEN=meu-token
OTEL_INSTR_FASTAPI=true
OTEL_INSTR_HTTPX=true
UO_ENABLE_LOGGING=true
UO_ENABLE_TRACING=true
UO_ENABLE_METRICS=true
```

```bash
elven-unified-observability -- uvicorn app:app --host 0.0.0.0 --port 8000
```

A auto-instrumentação do FastAPI gera spans automaticamente para cada request, incluindo:

* Método HTTP, rota, status code
* Duração da requisição
* Propagação de contexto (trace ID nos headers)

#### Django

```bash
OTEL_SERVICE_NAME=meu-django-app
OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.elvenobservability.com
LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push
LOGS_TENANT=meu-tenant
LOGS_TOKEN=meu-token
OTEL_INSTR_DJANGO=true
UO_ENABLE_LOGGING=true
UO_ENABLE_TRACING=true
```

```bash
elven-unified-observability -- python manage.py runserver
```

#### Flask

```bash
OTEL_SERVICE_NAME=meu-flask-app
OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.elvenobservability.com
LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push
LOGS_TENANT=meu-tenant
LOGS_TOKEN=meu-token
OTEL_INSTR_FLASK=true
UO_ENABLE_LOGGING=true
UO_ENABLE_TRACING=true
```

```bash
elven-unified-observability -- flask --app app run
```

#### Celery

```bash
OTEL_SERVICE_NAME=meu-worker
OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.elvenobservability.com
LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push
LOGS_TENANT=meu-tenant
LOGS_TOKEN=meu-token
OTEL_INSTR_CELERY=true
UO_ENABLE_LOGGING=true
UO_ENABLE_TRACING=true
```

```bash
elven-unified-observability -- celery -A worker.app worker -l info
```

#### Script Python simples

Para scripts que não são web servers:

```python
from elven_unified_observability import init_from_env, logger, shutdown

handle = init_from_env()

logger.info("processamento iniciado")
# ... sua lógica ...
logger.info("processamento finalizado")

handle.force_flush()
handle.shutdown()
```

***

### Usando logger, tracer e metrics

Após a inicialização (via CLI ou `init()`), os proxies globais ficam disponíveis:

```python
from elven_unified_observability import logger, tracer, metrics
```

#### Logger

```python
# Níveis de log
logger.debug("detalhes técnicos", {"key": "value"})
logger.info("evento importante", {"user_id": "123", "action": "login"})
logger.warn("algo inesperado", {"retry_count": 3})
logger.error("falha no processamento", {"error": "timeout", "service": "payments"})
logger.fatal("erro crítico irrecuperável")

# Log genérico com nível
logger.log("info", "mensagem customizada", {"custom": "data"})

# Tracking de eventos (semântico)
logger.track_event("user.signup", {"plan": "pro", "source": "landing"})

# Context manager — adiciona labels a todos os logs no bloco
with logger.with_context({"request_id": "abc-123", "user_id": "456"}):
    logger.info("processando request")  # inclui request_id e user_id automaticamente
    logger.info("request finalizado")

# Context manager async
async with logger.with_context_async({"request_id": "abc-123"}):
    logger.info("processando async")
```

#### Tracer

```python
# Span com callback (recomendado — gerencia lifecycle automaticamente)
def process_order(span):
    span.set_attribute("order.id", "ORD-789")
    span.set_attribute("order.total", 150.00)
    # ... lógica ...
    return {"status": "processed"}

result = tracer.with_span("process-order", process_order)

# Span async
async def fetch_data(span):
    span.set_attribute("source", "external-api")
    async with httpx.AsyncClient() as client:
        response = await client.get("https://api.example.com/data")
        return response.json()

data = await tracer.with_span("fetch-external-data", fetch_data)

# Span manual (mais controle)
span = tracer.start_span("custom-operation")
try:
    # ... lógica ...
    span.set_attribute("result", "success")
finally:
    span.end()
```

#### Metrics

```python
# Contador (incrementos)
metrics.increment("requests_total", 1, {"method": "GET", "route": "/api/users"})
metrics.increment("orders_processed_total", 1, {"status": "success"})

# Histograma (distribuições — latência, tamanho, etc.)
metrics.record_histogram(
    "request_duration_ms",
    145.2,
    {"route": "/api/users", "method": "GET"},
    unit="ms",
)

metrics.record_histogram(
    "payload_size_bytes",
    2048.0,
    {"endpoint": "/upload"},
    unit="bytes",
)
```

***

### Instrumentações automáticas

A lib detecta automaticamente as bibliotecas instaladas e instrumenta-as. Você pode controlar quais instrumentações ficam ativas:

#### Toggles por variável de ambiente

Cada instrumentação tem uma variável `OTEL_INSTR_*`:

| Variável                    | Biblioteca                                |
| --------------------------- | ----------------------------------------- |
| `OTEL_INSTR_FASTAPI`        | FastAPI                                   |
| `OTEL_INSTR_FLASK`          | Flask                                     |
| `OTEL_INSTR_DJANGO`         | Django                                    |
| `OTEL_INSTR_REQUESTS`       | requests                                  |
| `OTEL_INSTR_HTTPX`          | httpx                                     |
| `OTEL_INSTR_URLLIB3`        | urllib3                                   |
| `OTEL_INSTR_AIOHTTP_CLIENT` | aiohttp (client)                          |
| `OTEL_INSTR_SQLALCHEMY`     | SQLAlchemy                                |
| `OTEL_INSTR_PSYCOPG`        | psycopg (3.x)                             |
| `OTEL_INSTR_PSYCOPG2`       | psycopg2                                  |
| `OTEL_INSTR_PYMYSQL`        | PyMySQL                                   |
| `OTEL_INSTR_PYMONGO`        | PyMongo                                   |
| `OTEL_INSTR_REDIS`          | redis-py                                  |
| `OTEL_INSTR_CELERY`         | Celery                                    |
| `OTEL_INSTR_KAFKA`          | kafka-python                              |
| `OTEL_INSTR_PIKA`           | pika (RabbitMQ)                           |
| `OTEL_INSTR_BOTO3SQS`       | boto3 SQS                                 |
| `OTEL_INSTR_GRPC`           | gRPC                                      |
| `OTEL_INSTR_GRAPHQL`        | graphql-core                              |
| `OTEL_INSTR_LOGGING`        | stdlib logging (correlação trace/span ID) |
| `OTEL_INSTR_THREADING`      | threading                                 |
| `OTEL_INSTR_ASYNCIO`        | asyncio                                   |

Valores aceitos: `true` / `1` / `yes` / `on` para habilitar, `false` / `0` / `no` / `off` para desabilitar.

#### Exemplo: habilitar apenas o necessário

```bash
# API FastAPI que usa PostgreSQL e Redis
OTEL_INSTR_FASTAPI=true
OTEL_INSTR_PSYCOPG=true
OTEL_INSTR_REDIS=true
OTEL_INSTR_HTTPX=true
```

#### Precedência

Config explícita no `init()` > variáveis de ambiente `OTEL_INSTR_*` > defaults da lib.

***

### Configuração avançada

#### Inicialização manual com config completo

```python
from elven_unified_observability import init

handle = init({
    "service": {
        "serviceName": "payments-service",
        "serviceVersion": "2.1.0",
        "environment": "production",
        "serviceNamespace": "fintech",
        "attributes": {
            "team": "payments",
            "region": "us-east-1",
        },
    },
    "logging": {
        "transport": {
            "url": "https://loki.elvenobservability.com/loki/api/v1/push",
            "tenantId": "meu-tenant",
            "authToken": "meu-token",
            "compression": "gzip",
        },
        "labels": {
            "team": "payments",
            "squad": "checkout",
        },
        "buffer": {
            "maxSize": 500,
            "flushInterval": 3,
        },
        "filter": {
            "levels": ["info", "warn", "error", "fatal"],
            "samplingRate": 1.0,
        },
        "circuitBreaker": {
            "enabled": True,
            "failureThreshold": 5,
            "resetTimeout": 30,
        },
        "interceptConsole": False,
    },
    "telemetry": {
        "exporters": {
            "protocol": "http/protobuf",
            "compression": "gzip",
        },
        "tracing": {
            "enabled": True,
            "ratio": 1.0,
        },
        "metrics": {
            "enabled": True,
            "exportIntervalMillis": 15000,
        },
        "privacy": {
            "redactDbStatement": True,
            "hashUserId": True,
        },
        "instrumentations": {
            "fastapi": {"enabled": True},
            "httpx": {"enabled": True},
            "sqlalchemy": {"enabled": True},
            "redis": {"enabled": True},
        },
    },
    "enableLogging": True,
    "enableMetrics": True,
    "enableTracing": True,
    "strict": False,
})
```

#### Integrações com bibliotecas de logging

**Com `logging` (stdlib)**

```python
from logs_interceptor import LoggingHandler

import logging

handler = LoggingHandler()
logging.getLogger("meu_modulo").addHandler(handler)
```

**Com `structlog`**

```python
from logs_interceptor import StructlogProcessor

import structlog

structlog.configure(
    processors=[
        # ... seus processors ...
        StructlogProcessor(),
        structlog.dev.ConsoleRenderer(),
    ]
)
```

**Com `loguru`**

```python
from logs_interceptor import LoguruSink
from loguru import logger as loguru_logger

loguru_logger.add(LoguruSink())
```

#### Usando FastAPIMiddleware (opcional)

Se quiser middleware explícito do log interceptor (além da auto-instrumentação OTel):

```python
from fastapi import FastAPI
from logs_interceptor import FastAPIMiddleware

app = FastAPI()
app.add_middleware(FastAPIMiddleware)
```

***

### Boas práticas

#### Naming convention para serviços

Use nomes descritivos e consistentes:

```
{dominio}-{componente}
```

Exemplos: `payments-api`, `orders-worker`, `notifications-scheduler`, `auth-service`.

#### Labels no Loki

Use labels para dimensões de baixa cardinalidade (equipe, ambiente, cluster). **Não** use para valores de alta cardinalidade (user ID, request ID) — esses devem ir no corpo do log:

```bash
# Bom: labels de baixa cardinalidade
LOGS_LABEL_TEAM=backend
LOGS_LABEL_CLUSTER=prod-us

# Ruim: não coloque isso como label
# LOGS_LABEL_USER_ID=...    # alta cardinalidade!
```

```python
# User ID e request ID vão como metadata, não como label
logger.info("request processada", {"user_id": "123", "request_id": "abc"})
```

#### Sampling em produção

Para serviços com alto throughput, considere amostragem de traces:

```python
handle = init({
    "telemetry": {
        "tracing": {
            "ratio": 0.1,  # 10% dos traces
        },
    },
    # ...
})
```

Ou via ambiente:

```bash
OTEL_TRACES_SAMPLER=traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1
```

#### Redação de dados sensíveis

Habilite privacy para evitar vazamento de dados em spans:

```bash
OTEL_PRIVACY_REDACT_DB_STATEMENT=true   # redacta queries SQL
OTEL_PRIVACY_HASH_USER_ID=true          # faz hash de user IDs
```

#### Shutdown gracioso

Sempre faça flush antes de encerrar:

```python
import atexit
from elven_unified_observability import force_flush, shutdown

atexit.register(shutdown)
```

> A CLI zero-code já registra handlers de SIGTERM, SIGINT e atexit automaticamente.

#### Instrumentações — habilite só o necessário

Cada instrumentação adiciona overhead. Habilite apenas as que sua aplicação realmente usa:

```bash
# API REST simples com PostgreSQL
OTEL_INSTR_FASTAPI=true
OTEL_INSTR_PSYCOPG=true
OTEL_INSTR_HTTPX=true
```

***

### Deploy com Docker

#### Dockerfile — FastAPI com Uvicorn

Se a lib já está no seu `requirements.txt`:

```dockerfile
FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["elven-unified-observability", "--", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
```

Se você quer **adicionar a instrumentação direto no Dockerfile** sem alterar o `requirements.txt` da aplicação (útil para instrumentar apps existentes sem mexer no código):

```dockerfile
FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Instalar a lib de observabilidade separadamente
RUN pip install --no-cache-dir "elven-unified-observability-py[full]"

COPY . .

CMD ["elven-unified-observability", "--", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
```

> **Credenciais:** As variáveis de ambiente são passadas no `docker run` ou no `docker-compose.yml` — **nunca** hardcoded no Dockerfile.

#### docker run

```bash
docker build -t minha-api .

docker run -p 8000:8000 \
  -e OTEL_SERVICE_NAME=minha-api \
  -e OTEL_SERVICE_VERSION=1.0.0 \
  -e OTEL_DEPLOYMENT_ENVIRONMENT=production \
  -e OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.elvenobservability.com \
  -e OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
  -e OTEL_TRACES_EXPORTER=otlp \
  -e OTEL_METRICS_EXPORTER=otlp \
  -e OTEL_INSTR_FASTAPI=true \
  -e OTEL_INSTR_HTTPX=true \
  -e OTEL_PRIVACY_REDACT_DB_STATEMENT=true \
  -e LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push \
  -e LOGS_TENANT=seu-tenant-id \
  -e LOGS_TOKEN=seu-api-token \
  -e LOGS_COMPRESSION=gzip \
  -e UO_ENABLE_LOGGING=true \
  -e UO_ENABLE_TRACING=true \
  -e UO_ENABLE_METRICS=true \
  minha-api
```

#### docker-compose.yml

```yaml
services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      # Identidade
      OTEL_SERVICE_NAME: minha-api
      OTEL_SERVICE_VERSION: "1.0.0"
      OTEL_DEPLOYMENT_ENVIRONMENT: production

      # Telemetria
      OTEL_EXPORTER_OTLP_ENDPOINT: https://otlp.elvenobservability.com
      OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
      OTEL_TRACES_EXPORTER: otlp
      OTEL_METRICS_EXPORTER: otlp
      OTEL_METRIC_EXPORT_INTERVAL: "15000"
      OTEL_INSTR_FASTAPI: "true"
      OTEL_INSTR_HTTPX: "true"
      OTEL_PRIVACY_REDACT_DB_STATEMENT: "true"

      # Logs
      LOGS_URL: https://loki.elvenobservability.com/loki/api/v1/push
      LOGS_TENANT: seu-tenant-id
      LOGS_TOKEN: seu-api-token
      LOGS_COMPRESSION: gzip

      # Controle
      UO_ENABLE_LOGGING: "true"
      UO_ENABLE_TRACING: "true"
      UO_ENABLE_METRICS: "true"

  worker:
    build: .
    command: ["elven-unified-observability", "--", "celery", "-A", "worker.app", "worker", "-l", "info"]
    environment:
      OTEL_SERVICE_NAME: meu-worker
      OTEL_SERVICE_VERSION: "1.0.0"
      OTEL_DEPLOYMENT_ENVIRONMENT: production
      OTEL_EXPORTER_OTLP_ENDPOINT: https://otlp.elvenobservability.com
      OTEL_INSTR_CELERY: "true"
      LOGS_URL: https://loki.elvenobservability.com/loki/api/v1/push
      LOGS_TENANT: seu-tenant-id
      LOGS_TOKEN: seu-api-token
      UO_ENABLE_LOGGING: "true"
      UO_ENABLE_TRACING: "true"
```

> **Dica:** Para não repetir variáveis entre serviços, use um arquivo `.env` compartilhado com `env_file:` ou um bloco `x-common-env:` com YAML anchors.

#### Dockerfile multi-stage (produção)

Para imagens menores e mais seguras:

```dockerfile
# --- Build ---
FROM python:3.12-slim AS builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# Se a lib não está no requirements.txt, adicione aqui:
RUN pip install --no-cache-dir --prefix=/install "elven-unified-observability-py[full]"

# --- Runtime ---
FROM python:3.12-slim

WORKDIR /app

COPY --from=builder /install /usr/local
COPY . .

RUN useradd -r -s /bin/false appuser
USER appuser

EXPOSE 8000

CMD ["elven-unified-observability", "--", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
```

#### Kubernetes — Deployment

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: minha-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: minha-api
  template:
    metadata:
      labels:
        app: minha-api
    spec:
      containers:
        - name: api
          image: minha-api:1.0.0
          ports:
            - containerPort: 8000
          env:
            # Identidade
            - name: OTEL_SERVICE_NAME
              value: minha-api
            - name: OTEL_SERVICE_VERSION
              value: "1.0.0"
            - name: OTEL_DEPLOYMENT_ENVIRONMENT
              value: production

            # Telemetria
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: https://otlp.elvenobservability.com
            - name: OTEL_EXPORTER_OTLP_PROTOCOL
              value: http/protobuf
            - name: OTEL_TRACES_EXPORTER
              value: otlp
            - name: OTEL_METRICS_EXPORTER
              value: otlp
            - name: OTEL_INSTR_FASTAPI
              value: "true"

            # Logs
            - name: LOGS_URL
              value: https://loki.elvenobservability.com/loki/api/v1/push
            - name: LOGS_TENANT
              valueFrom:
                secretKeyRef:
                  name: elven-credentials
                  key: tenant-id
            - name: LOGS_TOKEN
              valueFrom:
                secretKeyRef:
                  name: elven-credentials
                  key: api-token
            - name: LOGS_COMPRESSION
              value: gzip

            # Controle
            - name: UO_ENABLE_LOGGING
              value: "true"
            - name: UO_ENABLE_TRACING
              value: "true"
            - name: UO_ENABLE_METRICS
              value: "true"

            # Labels customizados
            - name: LOGS_LABEL_CLUSTER
              value: prod-us
            - name: LOGS_LABEL_TEAM
              value: backend
```

Com o Secret:

```bash
kubectl create secret generic elven-credentials \
  --from-literal=tenant-id=seu-tenant-id \
  --from-literal=api-token=seu-api-token
```

***

### Troubleshooting

#### A aplicação não inicia / crash no bootstrap

**Sintoma:** Erro no import ou na inicialização.

**Verificações:**

1. Confirme a versão do Python (`python --version`): requer **3.11+**
2. Confirme que o pacote está instalado: `pip show elven-unified-observability-py`
3. Se usar `strict=true` / `UO_STRICT=true`, qualquer falha em logs ou OTel vai travar o bootstrap. Mude para `false` durante debug

```bash
# Testar import
python -c "from elven_unified_observability import init; print('OK')"
```

#### Logs não aparecem no Loki

**Sintoma:** A aplicação roda normalmente, mas nenhum log aparece.

**Verificações:**

1. Confirme que `LOGS_URL` está correto e inclui o path completo: `https://loki.elvenobservability.com/loki/api/v1/push`
2. Confirme que `LOGS_TENANT` e `LOGS_TOKEN` estão preenchidos
3. Confirme que `UO_ENABLE_LOGGING=true`
4. Habilite debug: `LOGS_DEBUG=true` e verifique o stderr

```bash
# Teste rápido
LOGS_DEBUG=true UO_STRICT=true elven-unified-observability -- python -c "
from elven_unified_observability import logger
logger.info('teste de log')
"
```

> **Nota:** Diferente da Lambda layer, aqui o `LOGS_URL` deve incluir o path completo (`/loki/api/v1/push`), pois a lib Python **não** appenda o path automaticamente.

#### Traces não aparecem

**Sintoma:** Logs funcionam, mas traces não aparecem na Elven.

**Verificações:**

1. Confirme que `OTEL_EXPORTER_OTLP_ENDPOINT` está definido
2. Confirme que `OTEL_TRACES_EXPORTER=otlp` (e não `none`)
3. Confirme que `UO_ENABLE_TRACING=true`
4. Verifique conectividade com o endpoint:

```bash
curl -v https://otlp.elvenobservability.com/v1/traces
```

#### Métricas não aparecem

**Sintoma:** Traces e logs funcionam, mas métricas não.

**Verificações:**

1. Confirme que `OTEL_METRICS_EXPORTER=otlp` (e não `none`)
2. Confirme que `UO_ENABLE_METRICS=true`
3. Métricas são exportadas em intervalos (`OTEL_METRIC_EXPORT_INTERVAL`). Aguarde pelo menos o intervalo configurado antes de verificar

#### Auto-instrumentação não funciona

**Sintoma:** A lib não gera spans para requests HTTP, queries SQL, etc.

**Verificações:**

1. Confirme que a biblioteca está instalada (ex: `pip show opentelemetry-instrumentation-fastapi`)
2. Confirme que o toggle está ativo: `OTEL_INSTR_FASTAPI=true`
3. A auto-instrumentação deve ser inicializada **antes** de importar o framework. O modo zero-code (CLI) garante isso. No modo manual, chame `init()` **antes** de criar a app

#### Erro de autenticação (401/403) no Loki

**Sintoma:** `LOGS_DEBUG=true` mostra `server error 401` ou `403`.

**Verificações:**

1. Confirme `LOGS_TOKEN` no painel da Elven
2. Confirme `LOGS_TENANT`
3. Verifique se o token não expirou

#### Alto consumo de memória

**Sintoma:** A aplicação consome memória crescente.

**Verificações:**

1. Verifique o tamanho do buffer: `LOGS_BUFFER_MAX_SIZE` (default 100)
2. Se o Loki estiver inacessível, logs ficam no buffer / DLQ. Verifique `LOGS_CIRCUIT_BREAKER_ENABLED=true` para evitar acúmulo
3. Reduza `LOGS_BUFFER_MAX_MEMORY_MB` para limitar uso

***

### FAQ

**Preciso instalar os 3 pacotes separadamente?** Não. Instale apenas `elven-unified-observability-py` — ele puxa as duas libs automaticamente.

**A CLI zero-code funciona com qualquer framework?** Sim. A CLI injeta a instrumentação via `sitecustomize.py` antes de qualquer import. Funciona com FastAPI, Django, Flask, Celery, scripts puros, etc.

**Posso usar apenas logs sem traces?** Sim. Defina `UO_ENABLE_TRACING=false` e `UO_ENABLE_METRICS=false` para usar apenas a pipeline de logs.

**Posso usar apenas traces sem logs?** Sim. Defina `UO_ENABLE_LOGGING=false` para desabilitar a pipeline de logs e usar apenas OTel.

**Funciona com `asyncio` / `async`?** Sim. O `tracer.with_span()` detecta funções async automaticamente. O `logger.with_context_async()` fornece context manager async. As instrumentações de `asyncio`, `aiohttp`, `httpx` são totalmente async-safe.

**Qual a diferença entre `LOGS_URL` na lib Python e `LOKI_URL` na Lambda layer?** Na lib Python, `LOGS_URL` deve ser a URL **completa** incluindo o path (`https://loki.elvenobservability.com/loki/api/v1/push`). Na Lambda layer (Go), `LOKI_URL` deve ser apenas a URL **base** (`https://loki.elvenobservability.com`), pois a extension appenda o path automaticamente.

**Posso usar `structlog` / `loguru` em vez do logger padrão?** Sim. A lib fornece `StructlogProcessor` e `LoguruSink` que redirecionam logs para a pipeline da Elven. Você pode usar sua lib preferida e os logs ainda chegam no Loki.

**Qual versão mínima do Python?** Python **3.11** ou superior.

**Como funciona o circuit breaker?** Se o Loki retornar erros consecutivos (`LOGS_CIRCUIT_BREAKER_FAILURE_THRESHOLD`), o circuito "abre" e logs são descartados (ou vão para a DLQ se habilitada). Após `LOGS_CIRCUIT_BREAKER_RESET_TIMEOUT` segundos, o circuito tenta fechar gradualmente.

**Posso usar em containers / Kubernetes?** Sim! Veja a seção Deploy com Docker para exemplos completos de Dockerfile, docker-compose e Kubernetes Deployment com Secrets.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.elven.works/elven-platform/elven-observability/integracao-e-instrumentacao/python/instrumentacao-python-com-elven-observability.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
