evobits

evobits · guia · aplicações · navegador

Páginas web: carga, Web Vitals e erros de JavaScript

Um serviço do tipo navegador recebe o que a sua página manda pelo SDK Web oficial do OpenTelemetry com a biblioteca web-vitals. O evobits não tem pacote próprio para o navegador.

Instala com
SDK Web do OpenTelemetry e web-vitals
Token
Público (evn_...), por origem permitida
Rede
Só saída para otlp.evobits.com.br:443
Onde no painel
Aplicações > Serviços > Novo serviço (tipo Navegador)

Copia esta página inteira em Markdown, com o texto para IA, para colar no Claude Code, no ChatGPT, no Gemini ou no assistente que vocês usam.

Exemplo de prompt
Preciso medir carga, Web Vitals e erros de JavaScript da nossa página no evobits.
Siga o guia que vou colar abaixo.

Nossa stack: (descreva aqui: empacotador, framework, arquivo de entrada).

Leia o guia inteiro e execute a seção "Texto para IA".
O token nunca vai escrito em arquivo: só a variável EVOBITS_TOKEN.

<COLE AQUI O TEXTO COPIADO PELO BOTÃO "COPIAR PARA IA">

01O que é monitorado

  • Carga completa da página (o span documentLoad).
  • Web Vitals: LCP (maior conteúdo visível), INP (resposta ao toque) e CLS (página pulando), em p75, por página, por versão e por navegador.
  • Erros de JavaScript e promessas rejeitadas, agrupados como os erros do backend, com a pilha resolvida pelo source map.
  • Não é monitorado: cliques, digitação, gravação de sessão, conteúdo da página, endereço IP do visitante.

02Como funciona

  • O token do navegador (evn_prd_...) é público por natureza: vai no código da página. Por isso ele só vale:
    • vindo de uma origem permitida (lista do serviço, até 20, sem caminho, por exemplo https://portal.exemplo.com.br);
    • para traces e logs (nunca métricas, nunca source map);
    • com pedido até 1 MB (4 MB descomprimido);
    • com taxa menor: 10 pedidos por segundo por token (rajada de 50) e 1 por segundo por visitante (rajada de 20).
  • O navegador manda OTLP por HTTP em JSON. O evobits responde ao CORS só para as origens da lista; de outra origem o navegador nem envia.
  • Token de backend (eva_) vindo de um navegador é recusado: segredo de servidor não vai para página.
  • Página é a rota, não a URL: o evobits usa url.template quando o SDK manda, senão o caminho da URL com os trechos que parecem id trocados por :id (/pedidos/123 vira /pedidos/:id); busca e âncora saem. Roteador por âncora (/#/pedidos/12) também vira rota.
  • A instância é o navegador ("Chrome Android", "Safari iOS"), lido do user agent.
  • A máscara roda no evobits antes de gravar (não há pacote no navegador). A amostragem e a cota são as mesmas dos outros serviços.

03Onde aparece

Serviço > Páginas: cartões de LCP, INP e CLS com as faixas do Google (bom até 2,5 s, 200 ms e 0,1; ruim acima de 4 s, 500 ms e 0,25), carga completa com o número de visitas e a taxa de erro de JavaScript, comparação entre as duas últimas versões, tabela por página e por navegador. Serviço > Erros e Aplicações > Erros. O serviço navegador não tem Rotas, Dependências nem Instâncias; tem Visão geral, Páginas, Erros e Configuração. No Dashboard, o widget "Web Vitals".

04Alertas

"Erro novo em produção" e "Regressão de erro" valem para erros da frente (origem navegador). Sensor de contagem de log pelo Explorador de logs (por exemplo, erros de JavaScript de uma página).

05Limites e privacidade

  • O que um token vazado permite: mandar logs e traces falsos para este serviço, gastando a cota da empresa, dentro dos tetos de taxa acima. Ele não lê nada, não manda source map e não alcança outro serviço. Se isso acontecer, gere outro token na Configuração e revogue o antigo (vale na hora).
  • O evobits nunca grava o IP do visitante (ele só existe em memória para a taxa).
  • Até 200 combinações de página e versão por serviço a cada 10 s; acima disso o resto vira "(outras)".
  • Nome de pessoa e endereço na URL não estão na máscara fixa: crie uma regra extra.

06Como instalar

1. Crie o serviço em Aplicações > Serviços > Novo serviço, tipo Navegador, com as origens onde a página abre (uma por linha). Copie o token evn_....

2. Instale os pacotes no projeto da página:

npm install @opentelemetry/api @opentelemetry/sdk-trace @opentelemetry/sdk-logs \
  @opentelemetry/exporter-trace-otlp-http @opentelemetry/exporter-logs-otlp-http \
  @opentelemetry/instrumentation @opentelemetry/instrumentation-document-load \
  @opentelemetry/resources web-vitals

3. Ponha o token e a versão nas variáveis do build, não no código: o token é público na página publicada, mas não precisa morar no git. No Vite:

VITE_EVOBITS_TOKEN=evn_prd_...    # no ambiente do build (CI ou .env.local, fora do git)
VITE_VERSAO=1.4.2                  # a versão do deploy; a mesma do envio do source map

**4. Crie src/telemetria.js:**

import { logs, trace, SeverityNumber } from '@opentelemetry/api';
import { TracerProvider, BatchSpanProcessor } from '@opentelemetry/sdk-trace';
import { LoggerProvider, BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
import { defaultResource, resourceFromAttributes } from '@opentelemetry/resources';
import { onCLS, onINP, onLCP } from 'web-vitals';

const endereco = 'https://otlp.evobits.com.br';
const headers = { authorization: `Bearer ${import.meta.env.VITE_EVOBITS_TOKEN}` };
const resource = defaultResource().merge(
  resourceFromAttributes({
    'service.name': 'meu-servico',
    'service.version': import.meta.env.VITE_VERSAO ?? '0.0.0',
    'user_agent.original': navigator.userAgent,
  }),
);

const traces = new TracerProvider({
  resource,
  spanProcessors: [new BatchSpanProcessor({ exporter: new OTLPTraceExporter({ url: `${endereco}/v1/traces`, headers }) })],
});
trace.setGlobalTracerProvider(traces);
const registros = new LoggerProvider({
  resource,
  processors: [new BatchLogRecordProcessor({ exporter: new OTLPLogExporter({ url: `${endereco}/v1/logs`, headers }) })],
});
logs.setGlobalLoggerProvider(registros);
registerInstrumentations({ instrumentations: [new DocumentLoadInstrumentation()] });

const log = logs.getLogger('evobits');
const vital = (m) =>
  log.emit({
    eventName: 'browser.web_vital',
    attributes: { 'browser.web_vital.name': m.name, 'browser.web_vital.value': m.value, 'url.full': location.href },
  });
onLCP(vital);
onINP(vital);
onCLS(vital);

const erro = (e) =>
  log.emit({
    severityNumber: SeverityNumber.ERROR,
    body: String(e?.message ?? e),
    attributes: {
      'exception.type': e?.name ?? 'Error',
      'exception.message': String(e?.message ?? e),
      'exception.stacktrace': e?.stack ?? '',
      'url.full': location.href,
    },
  });
addEventListener('error', (ev) => erro(ev.error ?? ev.message));
addEventListener('unhandledrejection', (ev) => erro(ev.reason));
addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    traces.forceFlush();
    registros.forceFlush();
  }
});

Fora do Vite, troque import.meta.env.VITE_... pelo mecanismo do seu empacotador (process.env.NEXT_PUBLIC_... no Next.js, define no esbuild, DefinePlugin no webpack). Se o roteador sabe o molde da rota (/pedidos/:id), mande-o como atributo url.template nos logs: a página fica exata.

5. Uma linha, antes de tudo: a primeira linha do arquivo de entrada da página (src/main.js):

import './telemetria.js';

6. Publique e abra a página numa origem permitida. 7. Mande os source maps de cada deploy (guia "Source maps"), com a chave da API, nunca com o token do navegador.

07Como conferir

  1. 1Abra a página numa origem da lista e navegue um pouco; troque de aba (o envio final sai quando a página fica oculta).
  2. 2O cartão Primeiro dado mostra "está mandando dados", com o navegador ("Chrome desktop") e a versão.
  3. 3Na aba Páginas, aparecem carga e Web Vitals da página (as medidas chegam quando a página fica oculta ou depois da primeira interação, no caso do INP).
  4. 4Force um erro numa página de teste: ele aparece em Erros com a pilha.
  5. 5No console do navegador, nenhuma linha "blocked by CORS policy" para otlp.evobits.com.br.

08Problemas comuns

SintomaO que fazer
Console: "Access to fetch at '.../v1/logs' ... has been blocked by CORS policy"a origem da página não está na lista do serviço (confira esquema, www e porta)
401 no /v1/tracestoken do build vazio ou errado (VITE_EVOBITS_TOKEN não chegou ao build)
403 "token de backend não é aceito vindo do navegador"usou o token eva_ de um serviço backend; crie um serviço do tipo navegador
429muitos envios de um visitante só; normal em teste de carga
Web Vitals não aparecemas medidas só saem quando a página fica oculta; troque de aba ou feche
Página aparece como /:id/... estranhaa URL tem trechos que parecem id; mande url.template
Erro sem arquivo e linha do fontefalta o source map da versão (ou a versão do build difere da do envio)

09Texto para IA

Para pedir a instalação a um assistente de código (Claude Code ou afins) aberto no projeto da página. Troque os marcadores entre < >; o token fica só na variável EVOBITS_TOKEN.

# Tarefa: medir carga, Web Vitals e erros de JavaScript da página <nome do serviço> no evobits

## Objetivo
Fazer a aplicação web deste projeto mandar ao evobits o tempo de carga, LCP, INP, CLS e os erros de JavaScript, pelo
SDK Web oficial do OpenTelemetry com a biblioteca web-vitals, sem gravar sessão nem cliques.

## Contexto
- Destino: https://otlp.evobits.com.br (caminhos /v1/traces e /v1/logs), OTLP por HTTP em JSON, cabeçalho
  `authorization: Bearer <token do navegador>`.
- O token do navegador (`evn_...`) é público e só vale das origens cadastradas no evobits. Mesmo assim ele NÃO vai
  escrito no código-fonte: entra pelo ambiente do build (no Vite, `import.meta.env.VITE_EVOBITS_TOKEN`), definido no
  CI ou num `.env.local` fora do git. Para esta tarefa, trate-o como EVOBITS_TOKEN do build.
- A versão do deploy vai em `service.version` (no Vite, `import.meta.env.VITE_VERSAO`) e tem de ser a mesma usada
  no envio do source map.
- Pacotes: @opentelemetry/api @opentelemetry/sdk-trace @opentelemetry/sdk-logs
  @opentelemetry/exporter-trace-otlp-http @opentelemetry/exporter-logs-otlp-http @opentelemetry/instrumentation
  @opentelemetry/instrumentation-document-load @opentelemetry/resources web-vitals.
- O arquivo de telemetria: TracerProvider com BatchSpanProcessor e OTLPTraceExporter ({url: endereço + '/v1/traces',
  headers}); LoggerProvider com BatchLogRecordProcessor e OTLPLogExporter ({url: endereço + '/v1/logs', headers});
  resource com `service.name` = '<nome do serviço>', `service.version` e `user_agent.original` = navigator.userAgent;
  DocumentLoadInstrumentation registrada; onLCP, onINP e onCLS emitindo um log com `eventName: 'browser.web_vital'` e
  atributos `browser.web_vital.name`, `browser.web_vital.value` e `url.full`; os eventos `error` e
  `unhandledrejection` emitindo um log de nível ERROR com `exception.type`, `exception.message`,
  `exception.stacktrace` e `url.full`; e `forceFlush` dos dois provedores quando `document.visibilityState` vira
  `hidden`. Na versão 3 do SDK, o processador recebe `{ exporter }` (objeto), não o exportador direto.

## Passos
1. Descubra o empacotador (Vite, Next.js, webpack, esbuild), o arquivo de entrada da página e se há roteador.
2. Instale os pacotes da lista com o gerenciador do projeto.
3. Crie `src/telemetria.js` (ou `.ts`) como no contexto, com o endereço https://otlp.evobits.com.br, lendo token e versão das
   variáveis de build do empacotador do projeto.
4. Importe `./telemetria.js` como a primeira linha do arquivo de entrada.
5. Se o roteador expõe o molde da rota (por exemplo `/pedidos/:id`), acrescente o atributo `url.template` nos logs.
6. Documente `VITE_EVOBITS_TOKEN=` e `VITE_VERSAO=` (ou os nomes do seu empacotador) SEM valor no `.env.example`.
7. Gere source maps no build (no Vite, `build.sourcemap: true`) e confira que os arquivos `.map` não são publicados
   junto com o site, se o projeto não quiser expô-los.

## Regras
- Nunca escreva o token em arquivo versionado nem na resposta.
- Não grave cliques, digitação, conteúdo da página nem gravação de sessão.
- Não mude nada além do pedido; rode o build e os testes do projeto depois.

## Como saber que deu certo
1. O build passa e o bundle publicado contém o endereço https://otlp.evobits.com.br.
2. Aberta numa origem permitida, a página faz POST em /v1/logs e /v1/traces com resposta 200, sem erro de CORS no console.
3. No painel do evobits, o cartão "Primeiro dado" do serviço <nome do serviço> mostra o navegador e a versão, e a aba
   Páginas mostra a carga e os Web Vitals da página.