# 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.
