Instrumentação Python no Google Cloud Run
Colete logs, métricas e traces de aplicações Python no Cloud Run com um único bootstrap e envio OTLP para um OpenTelemetry Collector.
Nota: O exemplo principal usa Python 3.11.16, mas o pacote publicado declara suporte a Python 3.10 ou superior. Valide a versão exata da aplicação em homologação antes do rollout de produção.
Caminho padrão: configure a identidade do serviço e uma URL-base em OTEL_EXPORTER_OTLP_ENDPOINT. Sem LOGS_URL ou LOKI_URL, a versão publicada 0.1.22 escolhe OTLP para os logs e deriva /v1/logs automaticamente. Não é necessário definir LOGS_EXPORTER, LOGS_TENANT nem LOGS_TOKEN na aplicação; o Collector ou gateway aprovado precisa aceitar os três sinais.
O interceptor 0.1.17 envia logs em OTLP/HTTP JSON (application/json), enquanto o OTel 0.1.5 envia traces e métricas em OTLP/HTTP protobuf (application/x-protobuf). Confirme que o gateway aceita os dois formatos nos caminhos /v1/logs, /v1/traces e /v1/metrics.
Sumário
- Visão geral
- Quando usar este guia
- Arquitetura
- Pré-requisitos
- Quick Start
- Instalação passo a passo
- Configuração
- Controle por revisão
- Validação ponta a ponta
- Troubleshooting
- FAQ
- Veja também
Visão geral
O pacote elven-unified-observability-py inicializa os três sinais de observabilidade antes da aplicação:
- intercepta
logginge exceções não tratadas;print()depende deLOGS_INTERCEPT_CONSOLE=true, eloguruestructlogdependem das bridges opcionais; - cria e exporta traces das bibliotecas Python suportadas pelo OpenTelemetry;
- exporta métricas automáticas das instrumentações compatíveis e métricas customizadas da aplicação;
- adiciona identidade de serviço consistente aos três sinais;
- correlaciona logs emitidos dentro de um span com
trace_idespan_id; - coordena
force_flush()eshutdown()quando o processo recebeSIGTERMou termina normalmente.
A integração não exige uma imagem de aplicação fornecida pela Elven. Instale a biblioteca PyPI na imagem da própria aplicação. Quando um Collector sidecar for necessário, use somente a imagem e o digest aprovados para o ambiente do cliente.
Importante: A versão pública estável usada neste guia é elven-unified-observability-py==0.1.22. Não use números de versões candidatas ou imagens sem release verificável em produção.
Cobertura por sinal
| Sinal | Cobertura automática | Cobertura manual |
|---|---|---|
| Logs | logging, Uvicorn, Gunicorn e exceções não tratadas; print() com interceptação de console habilitada e bridges para loguru e structlog |
Proxy logger para logs estruturados e eventos |
| Traces | Frameworks web, clientes HTTP, bancos, filas e bibliotecas instaladas compatíveis | Proxy tracer para spans de negócio |
| Métricas | Métricas emitidas pelas instrumentações OpenTelemetry compatíveis | Counters, histograms e up/down counters pelo proxy metrics |
Aviso: CPU, memória, quantidade de instâncias e métricas nativas do Cloud Run não são coletadas pela biblioteca Python. Use Cloud Monitoring ou um Collector configurado para essas métricas de infraestrutura.
Bibliotecas instrumentadas
A distribuição tenta instrumentar somente bibliotecas presentes no ambiente. A ausência de uma biblioteca não impede o startup.
| Categoria | Integrações suportadas |
|---|---|
| Web | ASGI, WSGI, FastAPI, Starlette, Flask, Django, GraphQL |
| HTTP e RPC | requests, httpx, urllib3, aiohttp, gRPC |
| Bancos e cache | SQLAlchemy, psycopg, psycopg2, PyMySQL, mysqlclient, MongoDB, Redis |
| Mensageria | Celery, Kafka Python, Pika, boto3 SQS |
| Runtime | asyncio, threading e logging |
Quando usar este guia
Use este guia quando:
- a aplicação Python roda como Cloud Run Service ou Cloud Run Job;
- o código já é empacotado em uma imagem OCI;
- existe conectividade HTTPS entre o Cloud Run e o Collector;
- o objetivo é instrumentar sem alterar os handlers da aplicação;
- logs, métricas e traces devem compartilhar a mesma identidade de serviço.
Não use este guia quando:
- o workload roda em GKE, VM ou função com outro modelo de bootstrap;
- já existe outro
opentelemetry-instrument, agent ou bootstrap de logging no mesmo processo; - o serviço não consegue alcançar o endpoint OTLP aprovado;
- o runtime é diferente de Python.
Atenção: Não combine elven-unified-observability -- ... com opentelemetry-instrument, LOGS_AUTO_INIT=true ou outro agente de startup. Mantenha uma única autoridade de instrumentação para evitar spans, handlers e métricas duplicados.
Arquitetura
O caminho recomendado envia os três sinais diretamente para um Collector remoto. A biblioteca fica dentro da imagem da aplicação; o backend e suas credenciais permanecem atrás do Collector.
Collector remoto
Use esta topologia como padrão:
- uma única imagem de aplicação;
- URL-base OTLP HTTPS fornecida no onboarding;
- autenticação injetada pelo Secret Manager;
- menor consumo de CPU e memória por instância;
- operação do Collector separada do ciclo de vida do Cloud Run.
Collector sidecar
Use um Collector sidecar somente quando houver requisito de isolamento de credenciais, processamento local ou endpoint remoto inacessível diretamente pela aplicação.
localhost:4318 → Collector ou gateway Elven.Nesta topologia:
- a aplicação usa
http://localhost:4318sem token do backend; - somente o sidecar recebe os secrets de exportação;
- o sidecar precisa de startup probe na porta de health check;
- a aplicação deve depender do sidecar na ordem de inicialização;
- a imagem do Collector deve ser fixada por digest.
Cuidado: Não use tags mutáveis como latest em produção. A referência <COLLECTOR_IMAGE>@sha256:<DIGEST> deve ser substituída por um artefato aprovado e informado no onboarding.
Pré-requisitos
Google Cloud
- projeto e região definidos;
- API do Cloud Run, Cloud Build e Artifact Registry habilitadas; Secret Manager somente se o gateway exigir autenticação na entrada;
- Artifact Registry criado para a imagem da aplicação;
- service account do Cloud Run com acesso ao secret de autenticação, quando o gateway exigir headers;
- conectividade de saída HTTPS para o Collector;
- VPC Connector e regras de firewall quando o Collector for privado.
Aplicação
- Python 3.10 ou superior;
- imagem Linux
amd64compatível com o contrato do Cloud Run; - processo HTTP ouvindo em
0.0.0.0na porta configurada,8080por padrão; - dependências resolvidas sem conflito;
- apenas um processo Python por instância como baseline recomendado.
O exemplo foi preparado para a imagem python:3.11.16-slim-bookworm.
Elven Observability
Solicite no onboarding:
- URL-base OTLP HTTP aprovada para os três sinais; se o gateway usar rotas distintas, solicite endpoints completos para cada sinal;
- headers exigidos pelo gateway ou Collector;
- nome do tenant;
- convenção esperada para
service.name, ambiente e namespace.
Cuidado: Nunca grave tokens, headers de autenticação ou tenants privados no Dockerfile, repositório, imagem ou arquivo de configuração versionado.
Quick Start
Este fluxo instrumenta um Cloud Run Service com Collector remoto.
1. Adicione a dependência
No requirements.txt, fixe a versão da aplicação:
elven-unified-observability-py[full]==0.1.22
O extra full adiciona suporte opcional a loguru, structlog e serialização otimizada. Ele não instala FastAPI, Flask, Django ou o servidor da aplicação.
Nota: Se a aplicação usa somente o logging padrão, elven-unified-observability-py==0.1.22 é suficiente.
2. Use o bootstrap zero-code na imagem
Exemplo para FastAPI e Uvicorn:
FROM python:3.11.16-slim-bookworm
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PORT=8080
WORKDIR /app
RUN groupadd --system app && useradd --system --gid app --home-dir /app app
COPY requirements.txt ./
RUN python -m pip install --no-cache-dir --upgrade pip \
&& python -m pip install --no-cache-dir -r requirements.txt \
&& python -m pip check
COPY . .
RUN chown -R app:app /app
USER app
EXPOSE 8080
CMD ["elven-unified-observability", "--", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080", "--workers", "1"]
Altere app.main:app para o import path real da aplicação.
3. Crie o arquivo de variáveis não sensíveis
Crie cloudrun.env.yaml sem tokens:
UO_ENABLED: "true"
UO_LOAD_DOTENV: "false"
UO_LOGGING_INTEGRATIONS: "auto"
OTEL_SERVICE_NAME: "orders-api"
OTEL_SERVICE_VERSION: "1.0.0"
OTEL_SERVICE_NAMESPACE: "commerce"
OTEL_DEPLOYMENT_ENVIRONMENT: "production"
OTEL_RESOURCE_ATTRIBUTES: "cloud.provider=gcp,cloud.platform=gcp_cloud_run,team=commerce"
OTEL_EXPORTER_OTLP_ENDPOINT: "https://collector.example.com"
OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf"
OTEL_TRACES_EXPORTER: "otlp"
OTEL_METRICS_EXPORTER: "otlp"
Substitua a URL-base e a identidade pelos valores aprovados para o ambiente. UO_ENABLED=true habilita os três sinais por padrão; os toggles individuais são opcionais. A wrapper deriva /v1/logs para logs, enquanto traces e métricas usam a mesma URL-base OTLP. Use endpoints separados somente quando as rotas do gateway forem diferentes. Para capturar também print(), adicione LOGS_INTERCEPT_CONSOLE=true como ajuste opcional de captura, não de transporte.
4. Cadastre a autenticação no Secret Manager, se exigida
Se o gateway exigir headers de entrada, crie o secret uma vez. Caso ele aceite OTLP sem autenticação na entrada, pule este passo e não configure OTEL_EXPORTER_OTLP_HEADERS:
gcloud secrets create elven-otlp-headers \
--replication-policy=automatic
Adicione o valor sem colocá-lo no histórico do shell:
read -r -s -p "Headers OTLP: " ELVEN_OTLP_HEADERS
printf '%s' "${ELVEN_OTLP_HEADERS}" | \
gcloud secrets versions add elven-otlp-headers --data-file=-
unset ELVEN_OTLP_HEADERS
O conteúdo exato do secret deve ser fornecido no onboarding. Exemplo de formato, sem credenciais reais:
Authorization=Bearer <TOKEN>,X-Scope-OrgID=<TENANT>
Conceda acesso à service account do serviço:
gcloud secrets add-iam-policy-binding elven-otlp-headers \
--member="serviceAccount:<SERVICE_ACCOUNT>" \
--role="roles/secretmanager.secretAccessor"
5. Construa e publique a imagem
Use Cloud Build para produzir uma imagem compatível com o runtime Linux do Cloud Run:
export PROJECT_ID="<PROJECT_ID>"
export REGION="<REGION>"
export REPOSITORY="<ARTIFACT_REGISTRY_REPOSITORY>"
export SERVICE="orders-api"
export IMAGE="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY}/${SERVICE}:1.0.0"
gcloud builds submit --project "${PROJECT_ID}" --tag "${IMAGE}" .
6. Faça o deploy
gcloud run deploy "${SERVICE}" \
--project "${PROJECT_ID}" \
--region "${REGION}" \
--image "${IMAGE}" \
--port 8080 \
--service-account "<SERVICE_ACCOUNT>" \
--env-vars-file cloudrun.env.yaml \
--update-secrets "OTEL_EXPORTER_OTLP_HEADERS=elven-otlp-headers:1" \
--no-cpu-throttling \
--concurrency 40 \
--max-instances 20
Fixe a versão do secret em produção. Atualize deliberadamente para uma nova versão durante a rotação.
Se o gateway não exigir headers de entrada, remova --update-secrets do comando de deploy. Isso não altera as credenciais upstream mantidas no Collector.
Importante: --no-cpu-throttling usa billing por instância e mantém CPU disponível para buffers e exportadores em background enquanto a instância existir. Avalie custo e capacidade antes do rollout.
Instalação passo a passo
Passo 1: Resolva as dependências
Instale a wrapper como dependência direta e deixe que ela resolva as versões compatíveis dos componentes:
python -m pip install "elven-unified-observability-py[full]==0.1.22"
python -m pip check
O release 0.1.22 exige:
elven-logs-interceptor-python>=0.1.17,<0.2.0;elven-opentelemetry-instrumentation-py>=0.1.5,<0.2.0;python-dotenv>=1.0.0,<2.0.0;httpx>=0.24.1,<0.29.0por meio do interceptor de logs.
Atenção: Um pin antigo de httpx ou httpcore pode tornar a resolução impossível. Não force versões incompatíveis com --no-deps. Ajuste o lock da aplicação e execute pip check na imagem final.
Passo 2: Escolha um único bootstrap
Use o modo zero-code como padrão:
elven-unified-observability -- uvicorn app.main:app --host 0.0.0.0 --port 8080
O comando injeta sitecustomize, inicializa a observabilidade antes dos imports da aplicação e substitui o próprio processo pelo servidor. Dessa forma, sinais do Cloud Run chegam diretamente ao processo Python e o shutdown coordenado recebe SIGTERM.
Use inicialização manual somente quando o comando de startup não puder ser alterado:
from elven_unified_observability import init_from_env
init_from_env()
from app.application import application
Inicialize antes de importar e criar a aplicação web.
Passo 3: Ajuste o comando por framework
FastAPI ou Starlette com Uvicorn
CMD ["elven-unified-observability", "--", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080", "--workers", "1"]
Flask com Gunicorn
CMD ["elven-unified-observability", "--", "gunicorn", "--bind", "0.0.0.0:8080", "--workers", "1", "app:create_app()"]
Django com Gunicorn
CMD ["elven-unified-observability", "--", "gunicorn", "--bind", "0.0.0.0:8080", "--workers", "1", "project.wsgi:application"]
Dica: Comece com um worker por instância. O Cloud Run escala horizontalmente, e múltiplos processos no mesmo container mantêm filas e providers de métricas separados. Aumente workers somente após teste de carga e validação de cardinalidade.
Passo 4: Configure o transporte de logs
No caminho recomendado, não há configuração separada para transporte de logs:
OTEL_SERVICE_NAME: "orders-api"
OTEL_EXPORTER_OTLP_ENDPOINT: "https://collector.example.com"
OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf"
Sem LOGS_URL/LOKI_URL, a wrapper 0.1.22 seleciona OTLP e deriva https://collector.example.com/v1/logs. OTEL_EXPORTER_OTLP_LOGS_ENDPOINT é opcional: use uma URL completa somente quando os logs tiverem rota própria. Remova LOGS_TENANT e LOGS_TOKEN do caminho Collector; as credenciais e o tenant upstream ficam no Collector/gateway. Se a aplicação herdar OTEL_LOGS_EXPORTER=none, remova essa variável: nesta versão ela impede a autodetecção OTLP. Quando não puder removê-la, defina LOGS_EXPORTER=otlp como override explícito.
Para um Loki direto, use uma configuração separada e não a trate como padrão:
LOGS_EXPORTER: "loki"
LOGS_URL: "https://loki.example.com/loki/api/v1/push"
LOGS_TENANT: "<TENANT>"
Injete LOGS_TOKEN pelo Secret Manager.
Aviso: O caminho Loki direto cobre somente logs. Traces e métricas continuam exigindo endpoints OTLP.
Passo 5: Preserve os logs nativos do Cloud Run
Mantenha os handlers originais e o stdout ativo:
LOGS_INTERCEPT_CONSOLE: "true"
LOGS_PRESERVE_ORIGINAL_CONSOLE: "true"
UO_ENABLE_PYTHON_LOGGING_BRIDGE: "true"
Esse modo envia o log para a Elven Observability e mantém a cópia no Cloud Logging. A bridge do logging captura também loggers com configuração própria, incluindo Uvicorn e Gunicorn, respeitando os filtros de ruído.
Passo 6: Garanta shutdown dentro da janela do Cloud Run
O preload registra handlers para SIGTERM, SIGINT e atexit. No shutdown, os logs são descarregados antes de traces e métricas.
Use timeouts menores que a janela de encerramento da plataforma:
LOGS_TIMEOUT: "5000"
OTEL_EXPORTER_OTLP_TIMEOUT: "5000"
OTEL_METRIC_EXPORT_TIMEOUT: "5000"
Evite retries excessivos no shutdown. O processo precisa concluir antes do SIGKILL do Cloud Run.
Passo 7: Instrumente Cloud Run Jobs
Para jobs finitos, use o mesmo wrapper:
CMD ["elven-unified-observability", "--", "python", "-m", "app.jobs.reconcile"]
No modo manual, descarregue os sinais antes de retornar:
from elven_unified_observability import force_flush, init_from_env, shutdown
init_from_env()
try:
run_job()
finally:
force_flush()
shutdown()
Passo 8: Configure um Collector sidecar opcional
No modo sidecar, a aplicação envia para loopback:
OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318"
OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf"
Não configure LOGS_URL/LOKI_URL nem OTEL_LOGS_EXPORTER=none; os logs seguem para http://localhost:4318/v1/logs automaticamente.
Estrutura mínima do serviço:
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: orders-api
spec:
template:
metadata:
annotations:
run.googleapis.com/container-dependencies: '{"app":["collector"]}'
spec:
containers:
- name: app
image: <APP_IMAGE>@sha256:<DIGEST>
ports:
- containerPort: 8080
- name: collector
image: <COLLECTOR_IMAGE>@sha256:<DIGEST>
args:
- --config=/etc/otelcol/config.yaml
startupProbe:
httpGet:
path: /
port: 13133
periodSeconds: 2
timeoutSeconds: 2
failureThreshold: 30
O Collector precisa expor OTLP HTTP em 0.0.0.0:4318 e health check em 0.0.0.0:13133. Mantenha os secrets somente no container collector.
Configuração
Variáveis essenciais
| Variável | Default | Descrição |
|---|---|---|
UO_ENABLED |
habilitado | Controle mestre da wrapper |
UO_ENABLE_LOGGING |
herdado de UO_ENABLED |
Habilita logs |
UO_ENABLE_METRICS |
herdado de UO_ENABLED |
Habilita métricas |
UO_ENABLE_TRACING |
herdado de UO_ENABLED |
Habilita traces |
UO_STRICT |
false |
Se true, falha o bootstrap quando um componente falha |
UO_LOAD_DOTENV |
habilitado no preload | Defina false no Cloud Run |
OTEL_SERVICE_NAME |
unknown-service |
Identidade principal dos três sinais |
OTEL_SERVICE_VERSION |
1.0.0 |
Versão lógica da aplicação |
OTEL_DEPLOYMENT_ENVIRONMENT |
development |
Ambiente de execução |
OTEL_RESOURCE_ATTRIBUTES |
vazio | Atributos adicionais separados por vírgula |
Logs
O transporte OTLP é autodetectado a partir da URL-base. As variáveis abaixo são opcionais para rotas diferentes, ajustes de captura ou compatibilidade com Loki direto.
| Variável | Default | Descrição |
|---|---|---|
LOGS_EXPORTER |
autodetectado | Não configure no padrão OTLP; use otlp para forçar OTLP quando houver env legada herdada, ou loki no modo direto |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT |
derivado do OTLP genérico | Override opcional para uma rota de logs diferente; informe a URL completa |
LOGS_INTERCEPT_CONSOLE |
false |
Captura saída de console como print(); logs do logging usam a bridge própria |
LOGS_PRESERVE_ORIGINAL_CONSOLE |
true |
Preserva stdout e handlers originais |
UO_LOGGING_INTEGRATIONS |
bridge logging |
Use auto para detectar loguru e structlog |
LOGS_FILTER_LEVELS |
debug,info,warn,error,fatal |
Níveis enviados |
LOGS_FILTER_SAMPLING_RATE |
1.0 |
Amostragem de logs entre 0.0 e 1.0 |
LOGS_FILTER_SANITIZE |
true |
Mascara dados sensíveis |
LOGS_FILTER_MAX_MESSAGE_LENGTH |
8192 |
Tamanho máximo da mensagem |
LOGS_BUFFER_MAX_SIZE |
100 |
Quantidade de registros por lote |
LOGS_BUFFER_FLUSH_INTERVAL |
5000 |
Intervalo de flush em milissegundos |
LOGS_TIMEOUT |
10000 |
Timeout de envio em milissegundos |
LOGS_MAX_RETRIES |
3 |
Tentativas de reenvio |
LOGS_SILENT_ERRORS |
false |
Se false, falhas aparecem no stderr |
Use LOGS_FILTER_LEVELS=debug,info,warn,error,fatal somente quando o volume e a política de retenção permitirem. Em produção, comece com info,warn,error,fatal.
Traces
| Variável | Default | Descrição |
|---|---|---|
OTEL_TRACES_EXPORTER |
otlp |
Exporter de traces |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT |
derivado do endpoint genérico | Endpoint completo /v1/traces |
OTEL_TRACES_SAMPLER |
sampler compatível da distribuição | Sampler OpenTelemetry |
OTEL_TRACES_SAMPLER_ARG |
conforme sampler | Razão do sampler |
UO_TRACING_RATIO |
não definido | Override de razão da wrapper |
UO_TRACING_MAX_SPANS_PER_TRACE |
sem limite | Limite defensivo de spans por trace |
OTEL_BSP_SCHEDULE_DELAY |
default do SDK | Intervalo do BatchSpanProcessor |
OTEL_BSP_MAX_QUEUE_SIZE |
default do SDK | Limite da fila de spans |
OTEL_BSP_MAX_EXPORT_BATCH_SIZE |
default do SDK | Tamanho máximo do lote |
Use sampling 1.0 durante a validação inicial e reduza conscientemente em produção. O limite de spans protege o backend, mas não substitui a divisão correta de processos longos em traces independentes.
Métricas
| Variável | Default | Descrição |
|---|---|---|
OTEL_METRICS_EXPORTER |
otlp |
Exporter de métricas |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT |
derivado do endpoint genérico | Endpoint completo /v1/metrics |
OTEL_METRIC_EXPORT_INTERVAL |
60000 |
Intervalo periódico em milissegundos |
OTEL_METRIC_EXPORT_TIMEOUT |
30000 |
Timeout de exportação em milissegundos |
LOGS_ENABLE_METRICS |
true |
Métricas internas do interceptor de logs |
UO_ENABLE_METRICS controla a telemetria unificada. LOGS_ENABLE_METRICS controla somente as métricas internas do logger.
Headers e secrets
Use um único secret quando logs, métricas e traces compartilham autenticação:
OTEL_EXPORTER_OTLP_HEADERS: "<INJETADO_PELO_SECRET_MANAGER>"
Para headers exclusivos de logs, use LOGS_OTLP_HEADERS. Não armazene o valor no arquivo cloudrun.env.yaml.
Privacidade e redaction
Logs são sanitizados por padrão. A regra mascara valores associados a chaves e padrões como:
password,passwd,pwd,senha;token,jwt,secret,api_key,authorization;cpf,cnpj, documento, passaporte e SSN;- cartão, CVV, conta bancária, IBAN e chave Pix;
- e-mail e credenciais.
A mensagem ao redor do valor é preservada. Em objetos, somente os campos sensíveis são substituídos por [REDACTED].
LOGS_FILTER_SANITIZE: "true"
OTEL_PRIVACY_REDACT_DB_STATEMENT: "true"
OTEL_PRIVACY_HASH_USER_ID: "true"
Cuidado: LOGS_FILTER_SANITIZE=false desativa a proteção dos logs. Use somente após aprovação formal, com prazo definido e sem payloads reais de clientes.
Métricas e traces customizados
Use os proxies globais depois do bootstrap:
from elven_unified_observability import logger, metrics, tracer
def process_order(order_id: str) -> None:
def run(span):
span.set_attribute("order.id", order_id)
logger.info("Processando pedido", context={"order_id": order_id})
metrics.increment("orders.processed", 1, {"result": "success"})
tracer.with_span("orders.process", run)
Não envie payloads, tokens, documentos ou dados pessoais como atributos de span, labels de métrica ou labels de log.
CPU e batching no Cloud Run
Os exportadores usam filas e threads em background. Há duas opções:
| Billing | Comportamento | Recomendação |
|---|---|---|
| Request-based | CPU pode ser limitada fora das requisições | Aceite atraso entre requests ou faça flush explícito em jobs curtos |
| Instance-based | CPU permanece alocada durante a vida da instância | Recomendado para flush periódico previsível |
Não use métricas de alta cardinalidade. IDs de usuário, pedido, requisição ou trace não devem ser labels de métricas.
Controle por revisão
Cada alteração de imagem, variável ou secret cria uma nova revisão do Cloud Run. Use revisões para rollout canário e rollback.
Publique sem tráfego
gcloud run deploy "${SERVICE}" \
--project "${PROJECT_ID}" \
--region "${REGION}" \
--image "${IMAGE}" \
--env-vars-file cloudrun.env.yaml \
--update-secrets "OTEL_EXPORTER_OTLP_HEADERS=elven-otlp-headers:1" \
--no-traffic
Envie tráfego canário
gcloud run services update-traffic "${SERVICE}" \
--project "${PROJECT_ID}" \
--region "${REGION}" \
--to-revisions "<NOVA_REVISAO>=10,<REVISAO_ESTAVEL>=90"
Promova ou reverta
Promova somente depois de validar os três sinais:
gcloud run services update-traffic "${SERVICE}" \
--project "${PROJECT_ID}" \
--region "${REGION}" \
--to-revisions "<NOVA_REVISAO>=100"
Para rollback, direcione 100% para a revisão estável anterior. Não altere simultaneamente imagem, endpoints, sampling e regras de rede durante o primeiro rollout.
Validação ponta a ponta
Valide separadamente instalação, runtime, transporte e persistência no backend.
1. Verifique a imagem
docker run --rm "${IMAGE}" python --version
docker run --rm "${IMAGE}" python -m pip check
Confirme Python 3.11.16 no caso do cliente que originou este guia.
2. Verifique a configuração da revisão
gcloud run services describe "${SERVICE}" \
--project "${PROJECT_ID}" \
--region "${REGION}" \
--format export
Confirme:
- comando iniciado por
elven-unified-observability; - imagem correta;
- endpoints corretos;
- secret montado como
OTEL_EXPORTER_OTLP_HEADERS; - CPU e concorrência conforme planejado;
- ausência de
LOGS_URL,LOKI_URLeOTEL_LOGS_EXPORTER=nonepara autodetecção OTLP; se alguma env legada for obrigatória, useLOGS_EXPORTER=otlpcomo override.
3. Verifique o startup
gcloud run services logs read "${SERVICE}" \
--project "${PROJECT_ID}" \
--region "${REGION}" \
--limit 100
Não devem aparecer mensagens de componente ignorado, erro de configuração, 401, 404, timeout ou conflito de provider OpenTelemetry.
4. Gere tráfego conhecido
SERVICE_URL=$(gcloud run services describe "${SERVICE}" \
--project "${PROJECT_ID}" \
--region "${REGION}" \
--format='value(status.url)')
curl --fail --show-error --silent "${SERVICE_URL}/health"
curl --fail --show-error --silent "${SERVICE_URL}/<ENDPOINT_DE_TESTE>"
Use um endpoint autorizado e sem dados sensíveis.
5. Verifique o trace no Tempo
Use TraceQL:
{ resource.service.name = "orders-api" }
Confirme rota, status HTTP, duração e spans filhos esperados.
6. Verifique logs no Loki
O label final depende do mapeamento do Collector. Tente a convenção configurada no ambiente:
{service_name="orders-api"}
Quando o pipeline mantém o label legado:
{app="orders-api"}
Confirme que um log emitido dentro da requisição contém trace_id e span_id não nulos e que o texto preserva campos não sensíveis.
7. Verifique métricas no Mimir
Use uma consulta inicial por identidade:
count({service_name="orders-api"})
Confirme métricas HTTP após gerar tráfego e uma métrica customizada conhecida quando a aplicação a emitir.
8. Verifique shutdown
Publique uma nova revisão ou reduza instâncias e acompanhe os logs. O processo deve receber SIGTERM, concluir o flush e sair sem traceback de shutdown.
Importante: Um 2xx do Collector comprova aceite do lote, não persistência no Loki, Tempo ou Mimir. A validação só termina quando os três sinais aparecem no backend correto.
Troubleshooting
O container não inicia ou não escuta a porta
Sintoma. A revisão não fica pronta e o Cloud Run informa que o container não escutou em PORT.
Causa provável. O servidor escuta em 127.0.0.1, usa outra porta ou o import path da aplicação está errado.
Fix.
- Configure
--host 0.0.0.0 --port 8080. - Confirme o
containerPortda revisão. - Rode a imagem localmente e teste
/health. - Verifique o traceback de import no Cloud Logging.
O comando elven-unified-observability não existe
Sintoma. O processo encerra com command not found.
Causa provável. A dependência não foi instalada na etapa final da imagem ou existe mais de um ambiente virtual.
Fix.
- Execute
python -m pip show elven-unified-observability-pyna imagem final. - Execute
python -m pip check. - Confirme que
pipe o comando do container pertencem ao mesmo Python. - Evite criar um virtualenv depois de instalar as dependências globalmente.
O build falha por conflito de httpx ou httpcore
Sintoma. pip retorna ResolutionImpossible.
Causa provável. A aplicação fixa versões anteriores às aceitas pelo interceptor.
Fix.
- Garanta
httpx>=0.24.1,<0.29.0. - Remova o pin direto de
httpcorequando ele não for uma dependência usada pela aplicação. - Regenere o lock.
- Execute os testes da aplicação e
pip checkdentro da imagem.
Logs aparecem no Cloud Logging, mas não no Loki
Sintoma. stdout funciona, mas não existem logs no backend Elven.
Causa provável. Exporter incorreto, endpoint de logs ausente, autenticação inválida, filtro de nível ou CPU limitada antes do flush.
Fix.
- Confirme
OTEL_EXPORTER_OTLP_ENDPOINTcom a URL-base aprovada; a wrapper deriva/v1/logs. Se houver rota exclusiva para logs, confiraOTEL_EXPORTER_OTLP_LOGS_ENDPOINTcompleto. - Remova
LOGS_URL,LOKI_URLeOTEL_LOGS_EXPORTER=nonedo caminho automático. UseLOGS_EXPORTER=otlpsomente se não puder remover uma env legada herdada. - Confirme o secret de headers e a permissão da service account.
- Mantenha
LOGS_SILENT_ERRORS=falsedurante o diagnóstico. - Teste
--no-cpu-throttlingeLOGS_BUFFER_FLUSH_INTERVAL=2000.
Uvicorn ou Gunicorn aparecem, mas logs da aplicação não
Sintoma. Só aparecem access logs ou mensagens de startup.
Causa provável. Bridge do Python desabilitada, nível filtrado ou inicialização depois dos imports da aplicação.
Fix.
- Use a CLI antes do servidor.
- Defina
UO_ENABLE_PYTHON_LOGGING_BRIDGE=true. - Confirme
LOGS_FILTER_LEVELS. - Para
loguruoustructlog, useUO_LOGGING_INTEGRATIONS=autoe o extra[full]. - Não substitua o bootstrap pela simples importação de
logger.
Logs aparecem duplicados
Sintoma. A mesma mensagem chega duas ou mais vezes.
Causa provável. Dois bootstraps, OpenTelemetry Logs ativo junto com o interceptor ou múltiplos handlers equivalentes.
Fix.
- Mantenha somente
elven-unified-observability -- .... - Não use
OTEL_LOGS_EXPORTER=noneno caminho automático: na wrapper0.1.22isso desativa a seleção OTLP. Remova outros agentes/exporters de logs duplicados ou forceLOGS_EXPORTER=otlpse a env for herdada. - Desative
LOGS_AUTO_INITquando estiver definido externamente. - Remova
opentelemetry-instrumentdo comando. - Verifique quantos workers Python existem por instância.
Logs mostram [REDACTED] em campos sensíveis
Sintoma. Valores de token, CPF, e-mail ou credenciais aparecem mascarados.
Causa provável. Sanitização de segurança funcionando conforme configuração.
Fix. Não desative em produção. Se um campo não sensível estiver sendo classificado incorretamente, envie um exemplo sintético para ajuste da regra sem expor dados reais.
Traces não aparecem
Sintoma. Logs chegam, mas Tempo não retorna traces.
Causa provável. Endpoint incorreto, sampling baixo, framework importado antes do bootstrap ou conflito com outro provider.
Fix.
- Confirme
UO_ENABLE_TRACING=trueeOTEL_TRACES_EXPORTER=otlp. - Valide o endpoint
/v1/tracese os headers. - Use temporariamente
OTEL_TRACES_SAMPLER_ARG=1.0em homologação. - Confirme que a CLI precede o Uvicorn ou Gunicorn.
- Remova outro agente OpenTelemetry do processo.
Métricas chegam com atraso ou não aparecem quando o serviço está ocioso
Sintoma. Métricas são exportadas apenas depois de novas requisições.
Causa provável. Billing request-based limita CPU fora das requisições.
Fix.
- Use instance-based billing com
--no-cpu-throttlingquando a exportação periódica for obrigatória. - Reduza
OTEL_METRIC_EXPORT_INTERVALsem criar volume excessivo. - Para jobs curtos, chame
force_flush()antes da saída. - Confirme métricas no backend, não apenas resposta do Collector.
O Collector retorna 401, 404 ou timeout
Sintoma. O interceptor registra falha de exportação.
Causa provável. Header inválido, endpoint com caminho incorreto ou falta de conectividade.
Fix.
401: valide secret, versão do secret, tenant e contrato de autenticação.404: valide os caminhos/v1/logs,/v1/tracese/v1/metrics.- Timeout: valide DNS, egress, VPC Connector, firewall e rota de retorno.
- Não aponte a URL-base OTLP ou o endpoint de logs para
/loki/api/v1/push; essa rota é exclusiva do modo Loki direto.
FAQ
A biblioteca roda como daemon separado no Cloud Run?
Não. Ela roda dentro de cada processo Python da aplicação. Threads internas cuidam de buffers e exportação enquanto a instância está ativa.
Python 3.11.16 é suportado?
Sim, está dentro do requisito publicado Python >=3.10. O Dockerfile deste guia usa python:3.11.16-slim-bookworm. Ainda assim, valide o conjunto completo de dependências da aplicação com pip check e testes de homologação.
Preciso alterar o código da aplicação?
Não no caminho zero-code. Instale o pacote, configure as variáveis e inicie o servidor com elven-unified-observability -- .... Alterações de código são necessárias somente para spans, métricas e logs de negócio customizados.
A biblioteca captura todos os logs do container?
Ela captura logs produzidos pelo processo Python por logging, print(), exceções não tratadas e bridges suportadas. Saída de binários externos, sidecars ou subprocessos não Python continua sob responsabilidade do Cloud Logging ou do Collector.
Preciso definir LOGS_EXPORTER ou LOGS_URL para enviar logs por OTLP?
Não. Com OTEL_EXPORTER_OTLP_ENDPOINT e sem LOGS_URL/LOKI_URL, a wrapper 0.1.22 autodetecta OTLP. Uma URL Loki herdada muda a seleção para Loki; remova-a ou force LOGS_EXPORTER=otlp. Também não defina OTEL_LOGS_EXPORTER=none no caminho automático.
Preciso manter uma instância mínima?
Não para serviços puramente orientados a requisição. Configure min-instances=1 somente quando houver requisito de baixa latência, processamento em background contínuo ou métricas periódicas durante ociosidade. Isso altera o custo.
Posso usar múltiplos workers?
Sim, mas cada worker mantém providers e buffers próprios. Comece com um worker por instância e aumente somente após teste de carga, validação de duplicidade e cardinalidade.
O que acontece se o Collector ficar indisponível?
O interceptor usa timeout, retry, circuit breaker e buffer limitado. Com UO_STRICT=false, uma falha de telemetria não deve impedir a aplicação de iniciar. Falhas continuam visíveis em stderr quando LOGS_SILENT_ERRORS=false.
Posso desativar a redaction?
Tecnicamente, LOGS_FILTER_SANITIZE=false desativa a sanitização dos logs. Não use essa opção em produção sem aprovação formal de segurança e privacidade.