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
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:
pip install "elven-unified-observability-py[full]"
Verificar instalação
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
# === 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
elven-unified-observability -- python app.py
Funciona com qualquer comando:
# 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
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):
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áveisLOGS_*aceitam o prefixoLOKI_*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:
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
# .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
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
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
elven-unified-observability -- python manage.py runserver
Flask
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
elven-unified-observability -- flask --app app run
Celery
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
elven-unified-observability -- celery -A worker.app worker -l info
Script Python simples
Para scripts que não são web servers:
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:
from elven_unified_observability import logger, tracer, metrics
Logger
# 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
# 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
# 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
# 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
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)
from logs_interceptor import LoggingHandler
import logging
handler = LoggingHandler()
logging.getLogger("meu_modulo").addHandler(handler)
Com structlog
from logs_interceptor import StructlogProcessor
import structlog
structlog.configure(
processors=[
# ... seus processors ...
StructlogProcessor(),
structlog.dev.ConsoleRenderer(),
]
)
Com loguru
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):
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:
# 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!
# 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:
handle = init({
"telemetry": {
"tracing": {
"ratio": 0.1, # 10% dos traces
},
},
# ...
})
Ou via ambiente:
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:
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:
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:
# 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:
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):
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 runou nodocker-compose.yml— nunca hardcoded no Dockerfile.
docker run
docker build -t minha-api .
docker run -p 8000:8000 <br>
-e OTEL_SERVICE_NAME=minha-api <br>
-e OTEL_SERVICE_VERSION=1.0.0 <br>
-e OTEL_DEPLOYMENT_ENVIRONMENT=production <br>
-e OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.elvenobservability.com <br>
-e OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf <br>
-e OTEL_TRACES_EXPORTER=otlp <br>
-e OTEL_METRICS_EXPORTER=otlp <br>
-e OTEL_INSTR_FASTAPI=true <br>
-e OTEL_INSTR_HTTPX=true <br>
-e OTEL_PRIVACY_REDACT_DB_STATEMENT=true <br>
-e LOGS_URL=https://loki.elvenobservability.com/loki/api/v1/push <br>
-e LOGS_TENANT=seu-tenant-id <br>
-e LOGS_TOKEN=seu-api-token <br>
-e LOGS_COMPRESSION=gzip <br>
-e UO_ENABLE_LOGGING=true <br>
-e UO_ENABLE_TRACING=true <br>
-e UO_ENABLE_METRICS=true <br>
minha-api
docker-compose.yml
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
.envcompartilhado comenv_file:ou um blocox-common-env:com YAML anchors.
Dockerfile multi-stage (produção)
Para imagens menores e mais seguras:
# --- 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
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:
kubectl create secret generic elven-credentials <br>
--from-literal=tenant-id=seu-tenant-id <br>
--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:
- Confirme a versão do Python (
python --version): requer 3.11+ - Confirme que o pacote está instalado:
pip show elven-unified-observability-py - Se usar
strict=true/UO_STRICT=true, qualquer falha em logs ou OTel vai travar o bootstrap. Mude parafalsedurante debug
# 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:
- Confirme que
LOGS_URLestá correto e inclui o path completo:https://loki.elvenobservability.com/loki/api/v1/push - Confirme que
LOGS_TENANTeLOGS_TOKENestão preenchidos - Confirme que
UO_ENABLE_LOGGING=true - Habilite debug:
LOGS_DEBUG=truee verifique o stderr
# 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_URLdeve 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:
- Confirme que
OTEL_EXPORTER_OTLP_ENDPOINTestá definido - Confirme que
OTEL_TRACES_EXPORTER=otlp(e nãonone) - Confirme que
UO_ENABLE_TRACING=true - Verifique conectividade com o endpoint:
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:
- Confirme que
OTEL_METRICS_EXPORTER=otlp(e nãonone) - Confirme que
UO_ENABLE_METRICS=true - 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:
- Confirme que a biblioteca está instalada (ex:
pip show opentelemetry-instrumentation-fastapi) - Confirme que o toggle está ativo:
OTEL_INSTR_FASTAPI=true - 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:
- Confirme
LOGS_TOKENno painel da Elven - Confirme
LOGS_TENANT - Verifique se o token não expirou
Alto consumo de memória
Sintoma: A aplicação consome memória crescente.
Verificações:
- Verifique o tamanho do buffer:
LOGS_BUFFER_MAX_SIZE(default 100) - Se o Loki estiver inacessível, logs ficam no buffer / DLQ. Verifique
LOGS_CIRCUIT_BREAKER_ENABLED=truepara evitar acúmulo - Reduza
LOGS_BUFFER_MAX_MEMORY_MBpara 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.