Skip to main content

Unified Observability Py

Pacote unificado para juntar:

  • elven-logs-interceptor-python
  • elven-opentelemetry-instrumentation-py

com uma experiência única de bootstrap, config por env e API manual em Python.

Instalação

Base:

pip install elven-unified-observability-py

Com extras de performance/logging, sem forçar frameworks da aplicação:

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

O extra full não instala nem atualiza fastapi, django, flask ou celery. Mantenha esses frameworks versionados no requirements da própria aplicação.

Para desenvolvimento:

pip install -e ".[dev]"

O que a lib entrega

  • init(...) manual com config Python-first
  • init_from_env() para bootstrap por ambiente
  • logger, tracer e metrics reexportados como proxies seguros
  • preload zero-code via sitecustomize
  • CLI elven-unified-observability -- <command>
  • CLI usa exec, então não fica um daemon/wrapper pai rodando no container
  • shutdown e flush coordenados
  • auto-bridge para libs de logging suportadas (loguru, structlog)
  • fallback LOKI_* para LOGS_*
  • aliases legados ENABLE_LOGGING, ENABLE_METRICS, ENABLE_TRACING

Quick Start Manual

from elven_unified_observability import init, logger, metrics, tracer

handle = init(
    {
        "service": {
            "serviceName": "billing-service",
            "serviceVersion": "1.2.3",
            "environment": "production",
        },
        "logging": {
            "transport": {
                "url": "https://loki.example.com/loki/api/v1/push",
                "tenantId": "tenant-a",
                "authToken": "token",
                "compression": "gzip",
            },
            "interceptConsole": True,
        },
        "telemetry": {
            "metrics": {"exportIntervalMillis": 15000},
            "privacy": {"redactDbStatement": True},
        },
        "enableLogging": True,
        "enableMetrics": True,
        "enableTracing": True,
    }
)

logger.info("service started", {"service": "billing-service"})
metrics.increment("bootstrap.success", 1)
tracer.with_span("startup", lambda span: span.set_attribute("boot.ready", True))

handle.force_flush()
handle.shutdown()

O logger também aceita padrões comuns do logging nativo durante migração:

logger.info("payload criado", {"request_id": "req-1"})
logger.info("payload criado: %s", payload)
logger.info("payload criado: %(id)s", {"id": payload_id})
logger.info("payload criado: {}", payload_id)
logger.info("payload criado: %s", payload_id, extra={"request_id": "req-1"})
logger.exception("falha ao criar payload: %s", payload_id)

Quando a wrapper intercepta o logging padrão do Python, extra={...} é capturado em context.extra:

logging.getLogger(__name__).info(
    "payload criado",
    extra={"payload": payload},
)

Aliases suportados: warning(...), exception(...) e critical(...).

Campos sensíveis como cpf, cnpj, cpfCnpj, documento, numeroDocumento, taxId, apiKey, clientSecret, senha, password, token, authorization, cartao/cartão, chavePix e campos relacionados a credenciais são mascarados por padrão. Em mensagens, a lib mascara apenas o fragmento/valor sensível e mantém o restante do log. Em extra/contexto estruturado, chaves sensíveis mascaram o valor inteiro. O matcher normaliza variações comuns em snake_case, camelCase, kebab-case, nomes com ponto e acentos. Para desligar, use LOGS_FILTER_SANITIZE=false, LOGS_SANITIZE=false ou UO_LOGS_SANITIZE=false apenas quando o envio do dado sensível em texto puro for realmente necessário e aprovado.

Quick Start Zero-Code

  1. Crie um .env com a identidade do serviço e os endpoints.
  2. Rode a app com a CLI:
elven-unified-observability -- python app.py

Também funciona com:

elven-unified-observability -- uvicorn app:app
elven-unified-observability -- celery -A worker.app worker
elven-unified-observability -- python -m my_service

Como a precedence funciona

  1. Config explícita passada para init(...)
  2. Env da wrapper (UO_*)
  3. Env dos componentes (LOGS_*, LOKI_*, OTEL_*)
  4. Defaults das libs-base

Variáveis da wrapper

Variável Descrição
UO_ENABLED Liga/desliga tudo por default
UO_ENABLE_LOGGING Override unificado para logs
UO_ENABLE_METRICS Override unificado para métricas
UO_ENABLE_TRACING Override unificado para tracing
UO_STRICT Falha o bootstrap se qualquer componente falhar
UO_LOAD_DOTENV Controla leitura de .env no preload/CLI
UO_DOTENV_PATH Caminho alternativo para o .env
UO_LOGGING_INTEGRATIONS Auto-instala bridges de logging: auto, logging, loguru, structlog, none
UO_LOGGING_EXCLUDE_PREFIXES Prefixos globais de bibliotecas barulhentas para ignorar nos bridges
UO_ENABLE_PYTHON_LOGGING_BRIDGE Override específico para bridge agressivo do logging padrão
UO_PYTHON_LOGGING_EXCLUDE_PREFIXES Prefixos extras para ignorar especificamente no bridge de logging
UO_ENABLE_LOGURU_BRIDGE Override específico para bridge de loguru
UO_ENABLE_STRUCTLOG_BRIDGE Override específico para bridge de structlog
UO_LOGURU_LEVEL Nível do sink loguru instalado pela wrapper
UO_LOGURU_ENQUEUE Ativa enqueue no sink loguru
UO_LOGURU_BACKTRACE Ativa backtrace no sink loguru
UO_LOGURU_DIAGNOSE Ativa diagnose no sink loguru
UO_LOGURU_EXCLUDE_PREFIXES Prefixos extras para ignorar especificamente no bridge de loguru
UO_TRACING_MAX_SPANS_PER_TRACE Máximo de spans gravados por trace neste processo. Desligado quando ausente
UO_TRACING_RATIO Ratio do SmartSampler. Quando definido, tem precedência sobre OTEL_TRACES_SAMPLER

Aliases legados suportados:

  • ENABLE_LOGGING
  • ENABLE_METRICS
  • ENABLE_TRACING

Identidade unificada

A identidade do serviço é sempre derivada nesta ordem:

  1. OTEL_SERVICE_NAME
  2. LOGS_APP_NAME ou LOKI_APP_NAME
  3. default unknown-service

Versão:

  1. OTEL_SERVICE_VERSION
  2. LOGS_APP_VERSION ou LOKI_APP_VERSION
  3. default 1.0.0

Ambiente:

  1. OTEL_DEPLOYMENT_ENVIRONMENT
  2. LOGS_ENVIRONMENT ou LOKI_ENVIRONMENT
  3. ENVIRONMENT
  4. APP_ENV
  5. default development

Logging

Prefixo principal: LOGS_*

Fallback suportado: LOKI_*

Exemplos mais usados:

LOGS_URL=https://loki.example.com/loki/api/v1/push
LOGS_TENANT=my-tenant
LOGS_TOKEN=secret
LOGS_COMPRESSION=gzip
LOGS_ENABLE_STRUCTURED_METADATA=false
LOGS_BUFFER_MAX_SIZE=500
LOGS_FILTER_LEVELS=info,warn,error
LOGS_INTERCEPT_CONSOLE=true
LOGS_ENABLE_METRICS=true

Modo recomendado para clientes com OpenTelemetry Collector:

LOGS_EXPORTER=otlp
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://collector:4318/v1/logs
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp

Com LOGS_EXPORTER=otlp, a wrapper envia logs para OTEL_EXPORTER_OTLP_LOGS_ENDPOINT. Se o endpoint explícito de logs não existir, a wrapper deriva /v1/logs de OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ou OTEL_EXPORTER_OTLP_ENDPOINT. Nesse modo, LOGS_URL, LOKI_URL, LOGS_TENANT e LOGS_TOKEN deixam de ser obrigatórios pela lib. LOGS_URL é ignorado de propósito em collector mode para evitar enviar payload OTLP para um endpoint Loki direto. Qualquer tenant ou autenticação deve ficar nos headers do collector/gateway.

LOGS_ENABLE_METRICS controla apenas as métricas internas do logger. Se ele não estiver definido, o pacote usa o valor unificado de UO_ENABLE_METRICS.

LOGS_ENABLE_STRUCTURED_METADATA fica false por default para compatibilidade com Loki que não permite structured metadata. Habilite apenas quando o tenant/cluster aceitar limits_config.allow_structured_metadata.

Logging Bridges

Quando a aplicação usa bibliotecas de logging além do logging padrão do Python, a wrapper pode instalar bridges automaticamente no bootstrap.

Hoje os bridges suportados são:

  • loguru
  • logging padrão do Python
  • structlog

No caso de loguru, a wrapper também reaplica o bridge automaticamente quando a aplicação chama logger.configure(...) ou logger.remove(), evitando perder o sink da observabilidade durante o bootstrap da app.

No caso de logging, a wrapper captura diretamente os LogRecord criados pelo Python, inclusive quando a aplicação usa logging.getLogger(__name__), troca handlers, ou define propagate=False.

Habilitar autodetecção para todas as bibliotecas suportadas:

UO_LOGGING_INTEGRATIONS=auto

Filtros padrão já silenciam bibliotecas barulhentas como httpx, httpcore, urllib3, h11, h2, hpack e opentelemetry.

Adicionar/forçar loguru explicitamente:

UO_LOGGING_INTEGRATIONS=loguru

Desligar o bridge agressivo do logging padrão, se realmente necessário:

UO_ENABLE_PYTHON_LOGGING_BRIDGE=false

Forçar override granular:

UO_ENABLE_LOGURU_BRIDGE=true
UO_ENABLE_STRUCTLOG_BRIDGE=false

Refinar exclusões globais:

UO_LOGGING_EXCLUDE_PREFIXES=httpx,httpcore,urllib3,h11,h2,hpack,opentelemetry

Adicionar exclusões extras só para loguru:

UO_LOGURU_EXCLUDE_PREFIXES=botocore,boto3

Para apps loguru-first, a recomendação é manter o bridge ligado e usar LOGS_INTERCEPT_CONSOLE=false quando você não quiser capturar print() da aplicação.

Telemetry

A wrapper reaproveita os OTEL_* já suportados pela lib-base.

Mais comuns:

OTEL_SERVICE_NAME=billing-service
OTEL_SERVICE_VERSION=1.2.3
OTEL_DEPLOYMENT_ENVIRONMENT=production
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_METRIC_EXPORT_INTERVAL=15000
OTEL_PRIVACY_REDACT_DB_STATEMENT=true
OTEL_INSTR_FASTAPI=true
OTEL_INSTR_REQUESTS=true

Sampling e limite de spans por trace

Samplers padrão

OTEL_TRACES_SAMPLER e OTEL_TRACES_SAMPLER_ARG são respeitados e chegam ao TracerProvider antes de qualquer tracer ser criado, inclusive no modo zero-code. Valores suportados: always_on, always_off, traceidratio, parentbased_always_on, parentbased_always_off, parentbased_traceidratio.

OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.10

Precedência de sampling:

  1. sampler explícito em telemetry.tracing.sampler
  2. UO_TRACING_RATIO ou telemetry.tracing.ratio / rules
  3. OTEL_TRACES_SAMPLER + OTEL_TRACES_SAMPLER_ARG
  4. Default compatível (ParentBased(SmartSampler(ratio=1.0)))

UO_TRACING_RATIO fica sem valor por default justamente para que os samplers padrão possam decidir. Defini-lo desliga o uso de OTEL_TRACES_SAMPLER.

Limite de spans por trace

UO_TRACING_MAX_SPANS_PER_TRACE limita quantos spans gravados um único trace pode iniciar neste processo. O alias de componente é ELVEN_OTEL_MAX_SPANS_PER_TRACE.

UO_TRACING_MAX_SPANS_PER_TRACE=500

Precedência: config explícita > UO_TRACING_MAX_SPANS_PER_TRACE > ELVEN_OTEL_MAX_SPANS_PER_TRACE > desligado. O default é desligado, para não truncar traces de ninguém silenciosamente. Valores não positivos ou inválidos mantêm o guardrail desligado.

O limitador envolve o sampler efetivo no topo, então vale para todos os spans, inclusive filhos de um pai já amostrado. A decisão do sampler delegado é avaliada primeiro e nunca é promovida: só spans que seriam gravados consomem orçamento, e um trace não amostrado continua não amostrado. O span raiz conta dentro do limite — com 500, o raiz mais 499 filhos são gravados e o restante do trace é descartado. Spans descartados preservam o tracestate do pai.

O limite é por processo, não distribuído. Cada worker Gunicorn/Uvicorn e cada serviço no caminho da requisição tem seu próprio contador.

Não é a correção arquitetural. Processamento em chunks dentro de uma requisição HTTP ainda precisa virar um trace raiz independente por chunk — Context() sem o pai atual mais um Link para o contexto HTTP original — ou ir para job assíncrono com resposta 202. Criar apenas um span filho por chunk mantém tudo no mesmo trace. Tail sampling no collector reduz quantos traces são armazenados, mas não torna seguro um trace amostrado gigante.

Trocando o sampler em runtime

Não atribua em provider.sampler, provider._sampler ou provider._delegate depois da inicialização. TracerProvider.get_tracer() entrega o sampler ao Tracer no momento da construção, então tracers já criados continuam com o sampler antigo. init() é idempotente e não refaz a configuração. Para trocar, use shutdown() seguido de novo init(), ou configure antes do bootstrap zero-code.

Framework examples

FastAPI

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

Flask

elven-unified-observability -- flask --app app run

Celery

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

API pública

  • init(config=None)
  • init_from_env(strict=None)
  • load_config_from_env(env=None)
  • get_handle()
  • is_initialized()
  • force_flush()
  • shutdown()
  • logger
  • tracer
  • metrics

Build e publish

Validação local:

ruff check .
pyright
pytest
python -m build
python -m twine check dist/*

Publish local:

./publish.sh --repository testpypi --dry-run
./publish.sh --repository testpypi
./publish.sh --repository pypi

Tokens esperados:

  • TEST_PYPI_API_TOKEN
  • PYPI_API_TOKEN

Segurança

  • Não versione .env real
  • Não grave token em arquivo
  • Use secrets de CI ou variáveis de ambiente locais

Metadata

Release files for elven-unified-observability-py 0.1.22

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for elven-unified-observability-py 0.1.22
File Size Uploaded
elven_unified_observability_py-0.1.22.tar.gz 33.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for elven-unified-observability-py 0.1.22
File Interpreter ABI Platform
elven_unified_observability_py-0.1.22-py3-none-any.whl Python 3 none any Details

Total release size: 59.3 kB

Release files / elven_unified_observability_py-0.1.22.tar.gz

Download URL elven_unified_observability_py-0.1.22.tar.gz
Size 33.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a18f4a6019942749e94eb12eba6ae39f639439d9b3fa495260215b9999ff9707
BLAKE2b-256 checksum
How to use checksums
51ea241bc847df1571c2b2b1b7ace5d1a0fa9c4d6c21c6b13550144c1d5d7744
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.16

Release files / elven_unified_observability_py-0.1.22-py3-none-any.whl

Download URL elven_unified_observability_py-0.1.22-py3-none-any.whl
Size 25.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0c45d05533b83d26f861c21bf29586f8879345d2dadaf23d6d659a0ee2885e5e
BLAKE2b-256 checksum
How to use checksums
ac76799dd68e47534e59aa0b10cc1fd778f5b7b44f0580da3646434c649f20a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.16

Release history Release notifications | RSS feed

This release

0.1.22 This release

2 release files

0.1.21

2 release files

0.1.20

2 release files

0.1.19

2 release files

0.1.18

2 release files

0.1.17

2 release files

0.1.16

2 release files

0.1.15

2 release files

0.1.14

2 release files

0.1.13

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page