01O que é monitorado
- Requisições recebidas: cada requisição HTTP vira um span de servidor com método, rota (
GET /pedidos/:id), código de resposta e duração. Fastify, Express e NestJS informam a rota. - Chamadas de saída:
http,httpsefetch(undici), com método e destino; o contexto do trace segue para o serviço chamado. - Banco, cache e filas:
pg(e Sequelize por cima dele), Redis (iorediseredis), MongoDB e socket.io. - Logs que você emite pela API de logs reexportada pelo pacote.
- Exceções: erro lançado numa rota (vira evento de exceção no span e grupo de erro) e exceção não tratada do processo.
- Recurso: versão do
package.json, ambiente (do token), instância (nome da máquina), versão do Node e framework detectado (Fastify, Express, NestJS, Koa, Hapi ou Restify).
Desligado por padrão: o corpo das requisições nunca é lido; os spans de ruído pg-pool.connect e os spans request e handler do Fastify não são gravados (a rota continua no span do servidor); o pacote não manda métricas nem lê a linha de comando do processo.
02Como funciona
- O pacote inicia o SDK do OpenTelemetry com as instrumentações acima e um exportador próprio: OTLP/HTTP em protobuf com gzip para
https://otlp.evobits.com.br, porta 443. - Antes de enviar, ele aplica a mesma máscara do evobits (telefone, CPF e CNPJ, e-mail, tokens, senhas, corpo de mensagem). O evobits mascara de novo ao receber.
- Falha de rede, 429 ou 5xx: até 3 tentativas, depois o lote é descartado. Token recusado (401 ou 403): um aviso no console, no máximo um por minuto. A telemetria nunca derruba nem segura o serviço.
- Cota estourada: a resposta traz
X-Evobits-Corte; o pacote para de enviar por 10 minutos, descarta o que sairia nesse prazo (não guarda em memória) e tenta de novo. - Exceção não tratada: o pacote grava um log FATAL com
exception.type,exception.messageeexception.stacktrace, descarrega a fila (até 3 s) e deixa o Node sair com código 1, como sempre. Se o serviço já tem tratador deuncaughtException, o pacote só registra e descarrega. - SIGTERM: o pacote descarrega a fila (até 3 s) e reenvia o sinal. Se o seu serviço trata o SIGTERM, chame
await parar()no seu tratador. - Sem
EVOBITS_TOKEN(ou comEVOBITS_DESLIGADO=1), o serviço roda normal, sem telemetria.
03Onde aparece
Aplicações > Serviços > meu-servico: Visão geral, Rotas, Erros, Traces, Dependências e Instâncias; Aplicações > Logs; Aplicações > Mapa. O subtítulo do serviço mostra "Node 22 · Fastify · 3 instâncias".
04Alertas
Sensor de rota (latência p50, p95, p99 ou taxa de erro) pela aba Rotas, sensor de contagem de log pelo Explorador de logs, e as regras "Erro novo em produção" e "Regressão de erro" (nascem desligadas, ligue em Alertas > Regras).
05Limites e privacidade
- Node.js 22.12 ou mais novo (testado no 22.22). O pacote é ESM e funciona com
requireno Node 22.12+. - Lote recusado acima de 8 MB; linha de log ou span acima de 256 kB é recusado sozinho.
- A máscara roda no pacote e de novo no evobits. Por isso o cartão "O que a máscara trocou" fica perto de zero em serviço com o pacote: o dado já saiu trocado.
- Nome de pessoa, endereço, CEP e IP não são mascarados: crie uma regra extra na Configuração do serviço.
- A versão 1.0.1 usa
@opentelemetry/sdk-node0.300.0,@opentelemetry/sdk-logs3.0.0 e@opentelemetry/api1.10.0, travadas.
06Como instalar
1. Instale o pacote.
npm install @evobits/node
2. Ponha o token no ambiente do processo (no .env que não vai para o git, no pm2, no systemd, no segredo do contêiner), nunca no código:
EVOBITS_TOKEN=eva_prd_...
3. Uma linha, antes de tudo. A primeira linha do arquivo de entrada, antes de carregar o framework.
ESM ("type": "module" ou .mjs):
import '@evobits/node/iniciar';
import Fastify from 'fastify';
CommonJS:
require('@evobits/node/iniciar');
const express = require('express');
4. Express em ESM e NestJS 12 precisam de mais um passo. Nesses dois casos o Express é carregado por import, e a rota só é lida com o gancho de módulos do OpenTelemetry registrado antes de o programa começar. Sem ele, os dados chegam, mas a rota aparece só como GET. Crie registrar.mjs ao lado do arquivo de entrada:
import { register } from 'node:module';
register('@opentelemetry/instrumentation/hook.mjs', import.meta.url);
e inicie o processo com --import:
node --import ./registrar.mjs servidor.js
(No pm2: node_args: '--import ./registrar.mjs'; no Docker: no CMD.) Fastify (ESM e CommonJS), Express em CommonJS e NestJS até a versão 11 compilado para CommonJS não precisam disso.
5. Reinicie o serviço. O primeiro dado chega em segundos, com a primeira requisição.
Express
require('@evobits/node/iniciar');
const express = require('express');
const app = express();
app.get('/clientes/:id', (req, res) => res.json({ id: req.params.id }));
app.listen(3000);
Erro lançado numa rota vira grupo de erro (o span do servidor fica com erro e evento de exceção).
Fastify
import '@evobits/node/iniciar';
import Fastify from 'fastify';
const app = Fastify();
app.get('/pedidos/:id', async (req) => ({ id: req.params.id }));
await app.listen({ port: 3000 });
NestJS
No main.ts (ou main.js), a primeira linha:
import '@evobits/node/iniciar';
import { NestFactory } from '@nestjs/core';
No NestJS 12, inicie com node --import ./registrar.mjs dist/main.js (passo 4).
Logs
Use a API de logs que o pacote reexporta, nunca outra instalação de @opentelemetry/api: duas cópias criam dois registros globais e os logs somem sem erro.
import { logs, SeverityNumber } from '@evobits/node';
const log = logs.getLogger('pedidos');
log.emit({ severityNumber: SeverityNumber.WARN, severityText: 'WARN', body: 'pedido criado sem frete', attributes: { 'pedido.id': 42 } });
Corpo em JSON (body: JSON.stringify({...})) vira atributos sozinho na busca. Para levar um erro tratado como erro agrupado, mande os atributos exception.type, exception.message e exception.stacktrace no log.
Opções no código
import { iniciar, parar } from '@evobits/node';
iniciar({ token: process.env.EVOBITS_TOKEN, versao: '2.14.1' });
// no seu tratador de SIGTERM:
await parar();
Variáveis
| Variável | Opção de iniciar() | Padrão |
|---|---|---|
EVOBITS_TOKEN | token | sem token, sem telemetria |
EVOBITS_ENDPOINT | endpoint | https://otlp.evobits.com.br |
EVOBITS_AMBIENTE | ambiente | o do token (prd, hml, dev), depois NODE_ENV |
EVOBITS_VERSAO | versao | version do package.json |
EVOBITS_INSTANCIA | instancia | nome da máquina |
OTEL_SERVICE_NAME | servico | name do package.json (só atributo: o token decide o serviço) |
EVOBITS_DESLIGADO=1 | desligado: true | ligado |
A partir da versão 1.0.1 o pacote também entende as variáveis padrão do OpenTelemetry. Elas valem só quando a opção do código e a variável EVOBITS_* correspondente não existem:
| Variável padrão | Equivale a | Observação |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT | EVOBITS_ENDPOINT | endereço base |
OTEL_EXPORTER_OTLP_HEADERS | EVOBITS_TOKEN | lê o cabeçalho authorization=Bearer <token> (o espaço pode vir como %20) |
OTEL_RESOURCE_ATTRIBUTES | EVOBITS_VERSAO, EVOBITS_AMBIENTE, EVOBITS_INSTANCIA | lê service.version, deployment.environment.name e service.instance.id |
Para mandar a uma sonda coletora, use EVOBITS_ENDPOINT=http://<ip-da-sonda>:4318 ou OTEL_EXPORTER_OTLP_ENDPOINT=http://<ip-da-sonda>:4318.
Código compilado (TypeScript, esbuild, webpack)
Mande o source map de cada deploy para a pilha do erro mostrar o arquivo e a linha do seu código-fonte (guia "Source maps"). Se o serviço roda com node --enable-source-maps, a pilha já sai resolvida e o envio é dispensável.
07Como conferir
- 1Faça uma requisição ao serviço.
- 2O cartão Primeiro dado do Novo serviço muda para "meu-servico está mandando dados", com instância e versão.
- 3Em Rotas, a rota aparece com o caminho do framework (
GET /pedidos/:id), não sóGET. - 4Um trace sem erro pode não aparecer na lista de Traces: a amostragem guarda 10 % deles. Para conferir, suba a amostragem para 100 % na Configuração e volte depois.
- 5No console do serviço, nenhuma linha
[evobits] o evobits recusou o token.
08Problemas comuns
| Sintoma | O que fazer |
|---|---|
[evobits] o evobits recusou o token (HTTP 401) | confira EVOBITS_TOKEN (inteiro, sem espaço, não revogado) |
HTTP 403 | o módulo Aplicações está desligado ou sem aceite; fale com um proprietário |
[evobits] sem conexão com o evobits | o processo precisa de saída para otlp.evobits.com.br:443; rede fechada usa a sonda coletora |
Rota aparece só como GET | Express em ESM ou NestJS 12: passo 4 |
| Logs não aparecem, traces sim | o log foi emitido por outra cópia de @opentelemetry/api; importe logs de @evobits/node |
| Nada chega | a linha do pacote não é a primeira do arquivo de entrada, ou o processo não foi reiniciado |
| O serviço demora até 3 s para sair no deploy | é o envio final no SIGTERM, com teto de 3 s |
| Faixa de corte em Aplicações | cota do mês atingida; o pacote pausa sozinho por 10 min de cada vez |
09Texto para IA
Para pedir a instalação a um assistente de código (Claude Code ou afins) aberto no projeto do serviço. Troque os marcadores entre < >; o token fica só na variável EVOBITS_TOKEN.
# Tarefa: ligar o evobits (logs, traces e erros) no serviço Node.js <nome do serviço>
## Objetivo
Instrumentar este serviço Node.js com o pacote `@evobits/node`, para ele mandar logs, traces e erros ao evobits no
ambiente <ambiente>, sem mudar o comportamento do serviço.
## Contexto
- O pacote `@evobits/node` (npm) liga o OpenTelemetry com uma linha: `import '@evobits/node/iniciar'` em ESM ou
`require('@evobits/node/iniciar')` em CommonJS, como PRIMEIRA linha do arquivo de entrada, antes do framework.
- Ele lê o token da variável de ambiente EVOBITS_TOKEN (ou, na versão 1.0.1, do cabeçalho de OTEL_EXPORTER_OTLP_HEADERS). Sem token, o serviço roda sem telemetria.
- Endereço padrão: https://otlp.evobits.com.br (não precisa configurar). Versão vem do package.json; ambiente, do token.
- Instrumenta http, fetch, Express, Fastify, NestJS, pg, Sequelize, Redis, MongoDB e socket.io. Não lê corpo de
requisição. Mascara telefone, CPF, e-mail, tokens e senhas antes de enviar.
- Exige Node.js 22.12 ou mais novo.
- Express carregado por `import` (projeto ESM) e NestJS 12 precisam de um gancho: um arquivo `registrar.mjs` com
`import { register } from 'node:module'; register('@opentelemetry/instrumentation/hook.mjs', import.meta.url);`
e o processo iniciado com `node --import ./registrar.mjs <arquivo de entrada>`. Sem isso a rota vira só `GET`.
- Logs da aplicação: `import { logs, SeverityNumber } from '@evobits/node'` e
`logs.getLogger('<nome>').emit({ severityNumber, severityText, body, attributes })`. Nunca importar `logs` de outra
cópia de `@opentelemetry/api`.
## Passos
1. Leia o package.json: confirme Node 22.12+ (campo engines, .nvmrc, Dockerfile ou o runtime de deploy), ESM ou
CommonJS, o framework e o arquivo de entrada (campo main, script start, Dockerfile, ecosystem do pm2).
2. Rode `npm install @evobits/node` (ou o equivalente do gerenciador do projeto).
3. Ponha `import '@evobits/node/iniciar';` (ESM) ou `require('@evobits/node/iniciar');` (CommonJS) como primeira
linha do arquivo de entrada.
4. Se o projeto é ESM e usa Express, ou usa NestJS 12, crie `registrar.mjs` como no contexto e ajuste o comando de
início (script start, Dockerfile, pm2 `node_args`) para `node --import ./registrar.mjs ...`.
5. Se o serviço já trata SIGTERM, acrescente `await parar()` (de `@evobits/node`) no tratador, antes de sair.
6. Documente no README ou no exemplo de variáveis (`.env.example`) a variável `EVOBITS_TOKEN=` SEM valor.
7. Se houver logger próprio que grave nome de pessoa, endereço, CEP ou IP, liste esses pontos para mim (a máscara
fixa não cobre; eu crio uma regra extra no painel).
## Regras
- O token fica só na variável de ambiente EVOBITS_TOKEN. Nunca escreva o valor em arquivo versionado, em
`.env.example`, em Dockerfile, em log ou na resposta. Se precisar dele para testar, peça que eu exporte a variável.
- Não mexa em nada além do pedido: sem atualizar outras dependências, sem refatorar, sem trocar o logger.
- Não leia nem envie corpo de requisição.
- Rode os testes do projeto depois da mudança.
## Como saber que deu certo
1. Com `EVOBITS_TOKEN` exportado, suba o serviço e faça uma requisição a uma rota com parâmetro.
2. O console não mostra `[evobits] o evobits recusou o token` nem `[evobits] sem conexão`.
3. No painel do evobits, o cartão "Primeiro dado" do serviço <nome do serviço> diz que ele está mandando dados, e a aba
Rotas mostra a rota com o caminho do framework (por exemplo `GET /pedidos/:id`), não só `GET`.
4. Os testes do projeto continuam verdes e, sem a variável, o serviço sobe normal.