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 │ │
│ │ - Console opcional │ │ - Métricas │ │
│ │ - Batching + retry │ │ - Auto-instrumentação │ │
│ │ - Exporta via OTLP │ │ - Exporta via OTLP │ │
│ └───────────┬────────────┘ └───────────┬────────────┘ │
│ │ │ │
└──────────────┼───────────────────────────┼───────────────┘
└───────────┬───────────────┘
▼
Collector / gateway OTLP aprovado
(logs, traces e métricas)
│
▼
Loki / Tempo / Mimir
| 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 via OTLP ao Collector; Loki direto é opcional |
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.10+
- pip (ou gerenciador de pacotes compatível)
- URL-base OTLP do Collector/gateway que receba logs, traces e métricas
- Conectividade da aplicação até essa URL-base
- Headers de entrada via secret, somente se o gateway exigir autenticação
- Tenant e endpoint Loki apenas para o modo Loki direto opcional
Instalação
Instalação básica
pip install elven-unified-observability-py
Instalação com extras completos (recomendado)
Inclui extras de logging e performance, sem instalar nem atualizar o framework da sua aplicação:
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.
Caminho padrão: envie logs, métricas e traces para um Collector/gateway OTLP aprovado. Com OTEL_SERVICE_NAME e OTEL_EXPORTER_OTLP_ENDPOINT, a wrapper publicada 0.1.22 autodetecta OTLP para logs e deriva /v1/logs. Não configure LOGS_URL, LOKI_URL, LOGS_TENANT ou LOGS_TOKEN na aplicação. O Collector/gateway precisa aceitar e encaminhar os três sinais; credenciais upstream ficam nele.
Nesta versão, logs são enviados como OTLP/HTTP JSON (application/json); traces e métricas usam OTLP/HTTP protobuf (application/x-protobuf). O endpoint de entrada precisa aceitar ambos os formatos.
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
# === URL-base OTLP para logs, traces e métricas ===
OTEL_EXPORTER_OTLP_ENDPOINT=https://collector.example.com
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
# === Controle unificado ===
UO_ENABLED=true
Substitua a URL de exemplo pela URL-base fornecida no onboarding. Não inclua /v1/logs na URL-base: a wrapper adiciona esse sufixo para logs. Se o gateway exigir autenticação na entrada, injete OTEL_EXPORTER_OTLP_HEADERS por secret, nunca em um .env versionado. Se os sinais usarem rotas diferentes, configure os endpoints OTLP específicos como overrides.
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
Após iniciar a aplicação, gere tráfego e confirme os três sinais no backend. Uma resposta 2xx do Collector confirma aceite do lote, não persistência em Loki, Tempo ou Mimir.
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 com OTLP
Defina OTEL_EXPORTER_OTLP_ENDPOINT=https://collector.example.com e OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf no ambiente antes de importar a aplicação. init() combina a configuração explícita com as envs, mas não carrega .env implicitamente.
from elven_unified_observability import init, logger, tracer, metrics
handle = init({
"service": {
"serviceName": "meu-servico-api",
"serviceVersion": "1.0.0",
"environment": "production",
},
"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")
Para manter Loki direto, use LOGS_EXPORTER=loki, LOGS_URL com o path completo e LOGS_TENANT; é uma configuração separada, não o Quick Start padrão.
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
No padrão OTLP, nenhum LOGS_* de transporte é obrigatório. O endpoint de logs é derivado da URL-base OTEL_EXPORTER_OTLP_ENDPOINT; OTEL_EXPORTER_OTLP_LOGS_ENDPOINT é um override opcional para rota exclusiva e deve conter a URL completa. As opções Loki da tabela abaixo são apenas para integração direta legada.
Atenção à migração: LOGS_URL/LOKI_URL herdadas fazem a wrapper selecionar Loki, mesmo com endpoint OTLP definido. Na versão 0.1.22, OTEL_LOGS_EXPORTER=none também impede a autodetecção OTLP para logs. Remova essas envs no caminho padrão; use LOGS_EXPORTER=otlp como override somente se não puder removê-las.
| Variável | Descrição | Default |
|---|---|---|
LOGS_EXPORTER |
Override opcional: otlp para forçar Collector, loki para modo direto |
Autodetectado |
LOGS_URL |
URL completa do Loki push endpoint, apenas no modo Loki direto; se presente, impede autodetecção OTLP | Não usada no padrão OTLP |
LOGS_TENANT |
Tenant ID (header X-Scope-OrgID) apenas para Loki direto |
Não usado no padrão OTLP |
LOGS_TOKEN |
Token de autenticação (Bearer) apenas para Loki direto | Não usado no padrão OTLP |
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 |
Loki direto (exceção): configure LOGS_EXPORTER=loki, LOGS_URL com /loki/api/v1/push e LOGS_TENANT. Injete LOGS_TOKEN por secret se o endpoint exigir Bearer. Esse modo altera apenas o destino dos logs; traces e métricas continuam em OTLP.
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
Os exemplos abaixo usam o mesmo Collector/gateway OTLP para os três sinais. Troque https://collector.example.com pelo endpoint aprovado; não adicione LOGS_URL ou OTEL_LOGS_EXPORTER=none ao caminho automático.
FastAPI
# .env
OTEL_SERVICE_NAME=minha-api
OTEL_EXPORTER_OTLP_ENDPOINT=https://collector.example.com
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
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://collector.example.com
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
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://collector.example.com
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
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://collector.example.com
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
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: Quando o gateway OTLP exigir headers de entrada, injete
OTEL_EXPORTER_OTLP_HEADERSpor secret no runtime — nunca hardcoded no Dockerfile ou em arquivo versionado.
docker run
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://collector.example.com \
-e OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
-e OTEL_TRACES_EXPORTER=otlp \
-e OTEL_METRICS_EXPORTER=otlp \
-e UO_ENABLED=true \
minha-api
Se o gateway OTLP exigir autenticação, injete OTEL_EXPORTER_OTLP_HEADERS a partir de um secret do orquestrador; não passe credenciais em argumentos do comando ou no Dockerfile.
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://collector.example.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"
# 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://collector.example.com
OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
OTEL_INSTR_CELERY: "true"
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://collector.example.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"
# 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
Se o gateway OTLP exigir autenticação na entrada, injete OTEL_EXPORTER_OTLP_HEADERS a partir de um Secret provisionado pelo mecanismo de secrets do cluster. Não coloque tokens em kubectl --from-literal, manifests versionados ou no Dockerfile:
- name: OTEL_EXPORTER_OTLP_HEADERS
valueFrom:
secretKeyRef:
name: elven-otlp-headers
key: headers
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.10+ - 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 na Elven Observability
Sintoma: A aplicação roda normalmente, mas nenhum log aparece.
Verificações:
- Confirme
OTEL_EXPORTER_OTLP_ENDPOINTcom a URL-base aprovada. O endpoint de logs derivado precisa chegar ao Collector em/v1/logs - Remova
LOGS_URL,LOKI_URLeOTEL_LOGS_EXPORTER=noneherdadas; se isso não for possível, forceLOGS_EXPORTER=otlp - Confirme que
UO_ENABLE_LOGGINGnão estáfalsee que a aplicação emite logs no nível esperado - Valide os headers do gateway, a resposta HTTP do Collector e a persistência no Loki;
2xxna entrada não prova armazenamento - 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:
LOGS_URLcom/loki/api/v1/pushsó é necessário no modo Loki direto. No padrão OTLP, a wrapper deriva/v1/logsda URL-base.
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)
Sintoma: O Collector/gateway ou o Loki direto retorna 401 ou 403.
Verificações:
- No padrão OTLP, confira os headers exigidos pelo gateway, a versão do secret e o encaminhamento do Collector ao backend; não configure
LOGS_TOKEN/LOGS_TENANTpara corrigir a autenticação upstream - No modo Loki direto, confira
LOGS_TOKEN,LOGS_TENANTe validade do token
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 Collector ou o Loki direto 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? Essa comparação vale apenas para Loki direto. Na lib Python, LOGS_URL deve incluir o path completo /loki/api/v1/push; na Lambda layer (Go), LOKI_URL é a URL-base. No caminho padrão OTLP da lib Python, não configure nenhuma das duas: use OTEL_EXPORTER_OTLP_ENDPOINT.
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.10 ou superior.
Como funciona o circuit breaker? Se o destino dos logs (Collector OTLP ou Loki direto) 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.