Skip to main content
Browser monitoring é uma funcionalidade em beta do AppSignal Labs. O pacote @appsignal/browser é publicado sob a tag beta no npm, e sua configuração e API ainda podem mudar entre releases beta. Compartilhe seu feedback na nossa comunidade no Discord.
Uma página de produto relata uma requisição GET /api/boom/ com falha: HTTP 500. Você sabe que a requisição falhou, mas não o motivo. O distributed tracing segue essa requisição do navegador até o back-end que a tratou e lançou um RuntimeError. Neste exemplo, esse é um app Django. Qualquer back-end que suporte distributed tracing funciona da mesma forma. O mapa de serviços mostra os dois lados desse trace:
Mapa de serviços do trace com duas caixas, Browser e django, ambas marcadas com um erro, conectadas por uma aresta de 81 ms.

O mapa de serviços para este trace: o erro de back-end conectado ao erro de navegador que o iniciou.

Para conectar o erro do navegador ao trabalho no back-end, configure os dois lados:
  1. Navegador: adicione os padrões de URL da sua API a tracePropagationTargets. As requisições correspondentes carregam um cabeçalho traceparent. Uma resposta 5xx ou um timeout qualificado vira um erro de navegador.
  2. Back-end receptor: instrumente o serviço que trata essas requisições. A instrumentação lê traceparent e reporta spans por um collector hospedado do AppSignal. Use uma integração suportada ou instrumentação OpenTelemetry para o framework dele.
A etapa 1 sozinha só relata o erro de navegador. A linha do tempo do trace permanece vazia até que o back-end seja instrumentado na etapa 2, porque os spans do servidor vêm dessa instrumentação, não do SDK do navegador. As duas etapas são necessárias para ver a requisição como um único trace.
Distributed tracing é uma funcionalidade em beta do AppSignal Labs. O SDK do navegador não precisa de collector. O serviço receptor precisa de um collector hospedado do AppSignal para seus spans.

Antes de começar

Seu front-end precisa apenas do SDK do Browser. O resto da configuração fica no back-end: o serviço que trata as requisições do seu front-end. No exemplo acima, esse é o serviço Django. Pode ser uma API em seu próprio host, ou o mesmo app que serve suas páginas. Configure-o primeiro, para que seus spans apareçam no trace quando uma requisição falhar:
  • Reportar por um collector hospedado. Na página “Hosted Collectors” nas configurações da sua organização, abra um collector e copie sua Collector URL. Envie os dados do serviço para essa URL. Se a lista estiver vazia, crie um collector lá primeiro. O distributed tracing só funciona por um collector hospedado. Em Python e Ruby, defina a URL como a opção collector_endpoint. O Ruby também precisa da gem appsignal-opentelemetry.
  • Definir um nome de serviço. Dê ao serviço seu próprio nome. O trace o usa para diferenciar o serviço do navegador e de outros serviços. Onde você o define depende da linguagem do back-end:
  • Instrumentar o servidor HTTP dele. Use uma integração para o framework dele que leia traceparent nas requisições recebidas. É assim que o serviço se junta ao trace do navegador em vez de iniciar o seu próprio. No Go, também registre um propagator com otel.SetTextMapPropagator.
  • Permitir traceparent entre origens. Um back-end pode estar em outra origem, como api.example.com chamado a partir de www.example.com. O navegador pode então enviar um preflight CORS antes da requisição. Permita traceparent na resposta do back-end ao preflight. Caso contrário, o navegador pode bloquear a requisição:
Node.js e Elixir ainda não são suportados. Com um back-end Node.js, como Express ou rotas de API do Next.js, requisições com falha ainda são relatadas como erros de navegador. Os traces delas não mostram spans de back-end.

Ativar

Adicione um padrão para cada host e caminho de back-end em tracePropagationTargets. A lista vazia padrão deixa o tracing desligado:
Os padrões correspondem ao host e ao caminho de cada chamada fetch e XMLHttpRequest. O SDK se conecta a essas APIs do navegador. Por isso, a configuração é a mesma em React, Vue ou JavaScript puro. Isso inclui bibliotecas construídas sobre eles, como axios. Os padrões ignoram o esquema e a query string. Uma URL relativa é resolvida em relação ao endereço da página. Por isso, uma chamada para /api/orders a partir de www.example.com corresponde a www.example.com/api/**. Use * dentro de um segmento de caminho, ou ** por vários segmentos. Inclua tanto um host quanto um caminho: Na linha do tempo do trace, serviceName identifica o span de erro do navegador. Por exemplo, Checkout UI identifica erros do seu front-end de checkout. O padrão é Browser. Use um nome diferente para cada front-end que você monitora. O SDK envia o nome com todo relatório de erro. O fluxo de instalação do SDK do Browser oferece Distributed tracing como opção. Está desligada por padrão. Selecioná-la adiciona tracePropagationTargets: ["api.example.com/**"] ao snippet do navegador. Substitua o host de exemplo pelo host do seu back-end e, depois, instrumente o serviço receptor. O assistente não instala nem configura esse serviço. Para verificar a propagação, carregue uma página que chama sua API e inspecione a requisição no painel Network do seu navegador. Uma requisição correspondente deve carregar um cabeçalho traceparent. Depois, inspecione uma requisição com falha no AppSignal para conferir se os spans de back-end aparecem no trace dela. O SDK não adiciona nenhum cabeçalho a uma requisição feita no modo no-cors, porque o navegador o removeria. Essas requisições nunca são relatadas como requisições com falha.

O que é relatado

O SDK relata esses resultados para uma requisição correspondente que enviou um cabeçalho traceparent:
  • Uma resposta 5xx é relatada como HTTPError.
  • Um timeout é relatado como TimeoutError. Isso é um fetch que rejeita com um TimeoutError, como o que é limitado por AbortSignal.timeout(). Também é um XMLHttpRequest cujo timeout dispara. O servidor pode ter recebido e rastreado uma requisição que expirou.
A mensagem nomeia a requisição e seu resultado, por exemplo POST https://api.example.com/orders: HTTP 503 ou GET https://api.example.com/orders: timed out. Além de tudo que um erro de navegador comum carrega, o relatório inclui:
  • A requisição, como params.request: a url, o method, o status quando uma resposta chegou, e a duration_ms. Os parâmetros de query são removidos da URL conforme sua allowlist.
  • O span: o ID de trace e o ID de span a partir do traceparent da requisição, com sua hora de início e duração. O AppSignal constrói o span do navegador a partir deles, então ele cobre a requisição como o navegador a viu. Depois de um timeout, os spans do back-end podem durar mais do que o span do navegador.
  • O nome de serviço que você definiu, ou Browser.
Nada é relatado para:
  • Uma requisição bem-sucedida. O cabeçalho é enviado, mas o navegador fica em silêncio, então o trace de back-end se sustenta sozinho.
  • Uma resposta 4xx. O SDK não a classifica como uma requisição com falha para o tracing.
  • Uma requisição que o navegador não conseguiu entregar: recusada, falha de DNS, ou bloqueada por uma extensão. Nenhum servidor a tratou, então não há trace de back-end para se juntar.
  • Um timeout enquanto o dispositivo está offline, o que não diz nada sobre o back-end.
  • Uma requisição que seu código cancelou.
Essas requisições ainda podem deixar um breadcrumb de rede, a menos que correspondam a privacy.networkBlocklist ou a coleta de breadcrumbs esteja desativada. Um breadcrumb de uma requisição que propagou contexto inclui seu ID de trace. Uma requisição com falha passa pelo mesmo pipeline que qualquer outro erro. errors.enabled, errors.sampleRate, os limites de taxa e a deduplicação de repetições se aplicam todos. beforeError a recebe como HTTPError ou TimeoutError, com a requisição em context.request. Você pode descartá-la ou redigi-la ali. Uma requisição que corresponde a privacy.networkBlocklist nunca é relatada. O SDK evita relatar a mesma rejeição de fetch duas vezes quando ela também chega a um handler de rejeição não tratada ou a captureError(). Se seu código lançar um novo erro depois de uma resposta 500, esse erro tem seu próprio trace. A requisição com falha permanece um relatório separado.

Lendo no AppSignal

Requisições com falha aparecem na visualização Errors da seção Browser como issues HTTPError e TimeoutError. Elas são agrupadas pela rota em que o usuário estava, como qualquer outro erro de front-end. Leia mais em erros de front-end no AppSignal. Abra uma issue para ver sua mensagem, breadcrumbs e tags. Na página completa da issue, selecione Traces. Depois selecione Fullscreen no card Trace timeline para abrir a visualização abaixo. Se a prévia omitir spans, o botão mostra All spans. No painel lateral do Browser Errors, Open full trace page leva você até a página da issue. Na linha do tempo em tela cheia, Browser identifica o serviço do span do navegador. Selecione esse span para ver os detalhes da requisição e do erro. No exemplo da página de produto, GET /api/boom/ retornou HTTP 500. Na linha do tempo do trace, você pode seguir a requisição com falha do navegador até o serviço Django:
  • Browser mostra uma HTTPError em /product/chocolate-stroopwafel (85 ms). Os detalhes do span selecionado mostram a URL da requisição e a resposta HTTP 500.
  • Abaixo, django mostra GET api/boom/ com um RuntimeError (81 ms).
  • A requisição Django contém dois spans SELECT e um span POST, com suas durações.
Linha do tempo do trace ligando uma HTTPError de navegador de 85 ms para GET /api/boom/ (HTTP 500) a uma RuntimeError do Django de 81 ms, com spans filhos SELECT e POST.

A requisição com falha do navegador e os spans relacionados do Django em um único trace.

Juntando-se a um trace que seu código iniciou

Sua aplicação pode já definir um traceparent válido em uma requisição, por exemplo através de um SDK de navegador OpenTelemetry. O AppSignal para Browser então deixa esse cabeçalho intacto, e uma requisição com falha se junta ao trace que seu código iniciou. Isso vale tanto para fetch quanto para XMLHttpRequest. Na aba Traces da issue, abra a linha do tempo do trace em tela cheia para inspecionar o trabalho de back-end.