simpla.fydocs
Obs Normalizer

obs-normalizer

Background service que normaliza eventos de GlitchTip e Alertmanager para um schema canônico ObsEvent e publica no exchange RabbitMQ obs.events.

obs-normalizer

Background service em Node.js que recebe webhooks de observabilidade (GlitchTip, Alertmanager), converte cada payload para o schema canônico ObsEvent, enriquece com sumário de trace (via Tempo) quando aplicável e publica no exchange RabbitMQ obs.events. Não possui UI — apenas endpoints HTTP de ingestão, probes de saúde e métricas Prometheus.

Subprojeto do monorepo simplafy-admin, localizado em apps/obs-normalizer. Runtime Fastify, schema compartilhado pelo pacote @simplafy-admin/obs-schema.

O que faz

  • Recebe webhooks de fontes de observabilidade em endpoints HTTP autenticados.
  • Converte cada payload bruto para o schema canônico ObsEvent usando receivers dedicados (parseGlitchTipWebhook, parseAlertmanagerWebhook).
  • Quando o evento contém correlation.trace_id, busca um trace_summary em Tempo antes de publicar.
  • Valida o ObsEvent resultante via Zod e publica no exchange RabbitMQ configurado.
  • Expõe Swagger UI da API em /docs, spec OpenAPI em /openapi.json e métricas Prometheus em /metrics.

O serviço só atua como ingestor + publisher: o consumo dos eventos normalizados é responsabilidade de outros workers conectados ao mesmo exchange.

Inputs (webhooks)

Dois endpoints POST, cada um com seu próprio esquema de autenticação.

POST /webhooks/glitchtip

Recebe payloads do GlitchTip. A autenticação aceita o segredo por header x-webhook-secret ou query param ?secret=... (o GlitchTip só permite passar o segredo via URL).

curl -X POST https://obs-normalizer/webhooks/glitchtip?secret=$GLITCHTIP_WEBHOOK_SECRET \
  -H "Content-Type: application/json" \
  -d @glitchtip-payload.json

Respostas:

CódigoSignificado
202Aceito; retorna { event_id } do ObsEvent publicado.
400invalid_payload — falha ao parsear o webhook.
401invalid_secret.
500internal_validation_failureObsEvent produzido violou o schema.
503publish_failed — falha ao publicar no RabbitMQ.

Quando o evento normalizado contém correlation.trace_id, o serviço chama Tempo (TEMPO_URL) para anexar um trace_summary antes de publicar.

POST /webhooks/alertmanager

Recebe payloads no formato Alertmanager webhook v4. Autenticação via HTTP Basic (ALERTMANAGER_USERNAME / ALERTMANAGER_PASSWORD).

curl -X POST https://obs-normalizer/webhooks/alertmanager \
  -u "$ALERTMANAGER_USERNAME:$ALERTMANAGER_PASSWORD" \
  -H "Content-Type: application/json" \
  -d @alertmanager-payload.json

Um payload Alertmanager pode gerar múltiplos ObsEvents. O serviço valida todos antes de publicar qualquer um — assim retries não causam publicação parcial.

Respostas:

CódigoSignificado
202Aceito; retorna { count } com o número de eventos publicados.
400invalid_payload.
401unauthorized.
500internal_validation_failure.
503publish_failed.

Erros de publicação retornam 503, sinalizando ao remetente que pode/deve retentar. A validação do schema acontece antes da publicação para evitar mensagens malformadas no exchange.

Outputs (queue)

Os eventos normalizados são publicados no RabbitMQ, no exchange definido por RABBITMQ_EXCHANGE (default obs.events) dentro do vhost RABBITMQ_VHOST (default /obs). A publicação é feita por um ResilientPublisher configurado com a HTTP API do RabbitMQ:

new ResilientPublisher({
  publishOpts: {
    apiUrl: config.RABBITMQ_API_URL,
    user: config.RABBITMQ_USER,
    password: config.RABBITMQ_PASSWORD,
    vhost: config.RABBITMQ_VHOST,
    exchange: config.RABBITMQ_EXCHANGE,
  },
})

Cada mensagem segue o schema ObsEvent exportado por @simplafy-admin/obs-schema. O fluxo conceitual é:

webhook bruto → receiver dedicado → ObsEvent → (opcional) enrich com trace_summary → Zod validate → publish

Consumidores ligam suas filas a este exchange para reagir a eventos canônicos sem precisar conhecer o formato de cada fonte original.

Arquitetura em 1 parágrafo

O serviço é um app Fastify single-process. No bootstrap, instrument.js inicializa OpenTelemetry antes de qualquer outro import, e prom-client coleta métricas default do Node sob o prefixo obs_normalizer_. buildServer registra Swagger/Swagger UI, os health routes (/healthz, /readyz), os webhook routes (/webhooks/glitchtip, /webhooks/alertmanager) e expõe /openapi.json e /metrics. As rotas de webhook recebem um Publisher e um TraceFetcher por injeção de dependência: por padrão usam o ResilientPublisher (RabbitMQ HTTP API) e getTraceSummary (Tempo). Quando executado diretamente, o processo escuta em 0.0.0.0:PORT (default 3002).

Operação (health, metrics)

Health probes

GET /healthz retorna sempre 200 enquanto o processo está vivo, com a versão da app.

{ "status": "ok", "version": "dev" }

Apropriado para liveness probe do Kubernetes.

GET /readyz valida em paralelo se Tempo e RabbitMQ estão alcançáveis (timeout de 1s cada):

  • Tempo: GET {TEMPO_URL}/ready
  • RabbitMQ: GET {RABBITMQ_API_URL}/aliveness-test/{vhost} com Basic auth
{ "status": "ok", "tempo": true, "rabbitmq": true }

Se qualquer dependência falhar, o status passa a degraded (o endpoint ainda responde 200, mas indica a dependência problemática). Use no readiness probe combinado com a inspeção dos campos.

Métricas

GET /metrics expõe as métricas no formato Prometheus, incluindo as default do Node (process_*, nodejs_*) prefixadas com obs_normalizer_.

curl http://obs-normalizer:3002/metrics

Documentação interativa

  • Swagger UI: /docs
  • OpenAPI JSON: /openapi.json

Configuração

Variáveis lidas via Zod (src/config.ts); valores sem default são obrigatórios.

VariávelDefaultObservação
PORT3002Porta HTTP do Fastify.
NODE_ENVdevelopmentdevelopment | staging | production | test.
LOG_LEVELinfodebug | info | warn | error.
TEMPO_URLhttp://tempo.monitoring.svc.cluster.local:3200Base URL do Tempo para enrichment.
TEMPO_TIMEOUT_MS2000Timeout da busca de trace summary.
RABBITMQ_API_URLhttp://localhost:15672/apiHTTP API do RabbitMQ.
RABBITMQ_USERobs-normalizerUsuário do publisher.
RABBITMQ_PASSWORDobrigatórioSenha do publisher.
RABBITMQ_VHOST/obsVhost.
RABBITMQ_EXCHANGEobs.eventsExchange de destino.
GLITCHTIP_WEBHOOK_SECRETobrigatórioSegredo aceito em x-webhook-secret ou ?secret=.
ALERTMANAGER_USERNAMEobs-alertsBasic auth.
ALERTMANAGER_PASSWORDobrigatórioBasic auth.
GLITCHTIP_DSNDSN opcional para auto-instrumentar o próprio serviço.
OTEL_BASIC_AUTHAuth opcional para o exporter OTel.
APP_VERSIONdevExposto em /healthz.

Segredos de produção (RABBITMQ_PASSWORD, GLITCHTIP_WEBHOOK_SECRET, ALERTMANAGER_PASSWORD) são gerenciados no Infisical. Consulte a skill infisical para descobrir o path exato.

On this page