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.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:

O mapa de serviços para este trace: o erro de back-end conectado ao erro de navegador que o iniciou.
- Navegador: adicione os padrões de URL da sua API a
tracePropagationTargets. As requisições correspondentes carregam um cabeçalhotraceparent. Uma resposta 5xx ou um timeout qualificado vira um erro de navegador. - Back-end receptor: instrumente o serviço que trata essas requisições. A instrumentação lê
traceparente reporta spans por um collector hospedado do AppSignal. Use uma integração suportada ou instrumentação OpenTelemetry para o framework dele.
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 gemappsignal-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
traceparentnas 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 comotel.SetTextMapPropagator. - Permitir
traceparententre origens. Um back-end pode estar em outra origem, comoapi.example.comchamado a partir dewww.example.com. O navegador pode então enviar um preflight CORS antes da requisição. Permitatraceparentna resposta do back-end ao preflight. Caso contrário, o navegador pode bloquear a requisição:
Ativar
Adicione um padrão para cada host e caminho de back-end emtracePropagationTargets. A lista vazia padrão deixa o tracing desligado:
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çalhotraceparent:
- Uma resposta 5xx é relatada como
HTTPError. - Um timeout é relatado como
TimeoutError. Isso é umfetchque rejeita com umTimeoutError, como o que é limitado porAbortSignal.timeout(). Também é umXMLHttpRequestcujotimeoutdispara. O servidor pode ter recebido e rastreado uma requisição que expirou.
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: aurl, omethod, ostatusquando uma resposta chegou, e aduration_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
traceparentda 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.
- 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.
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 issuesHTTPError 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:
Browsermostra umaHTTPErrorem/product/chocolate-stroopwafel(85 ms). Os detalhes do span selecionado mostram a URL da requisição e a resposta HTTP 500.- Abaixo,
djangomostraGET api/boom/com umRuntimeError(81 ms). - A requisição Django contém dois spans
SELECTe um spanPOST, com suas durações.

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 umtraceparent 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.