> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Distributed tracing para Browser

> Veja como uma requisição com falha no navegador se conecta ao trace de back-end que ela iniciou, para que o erro e o trabalho do lado do servidor por trás dele se leiam como um único trace.

export const Compatibility = ({versions = [], label = "Available in"}) => {
  if (!Array.isArray(versions) || versions.length === 0) {
    return null;
  }
  const defaultPillStyle = {
    borderColor: "#d4d4d8",
    background: "#f4f4f5",
    color: "#3f3f46"
  };
  const pillStyles = {
    "AppSignal for Elixir": {
      background: "#f3e8ff",
      borderColor: "#d8b4fe",
      color: "#6b21a8"
    },
    "AppSignal for Front-end": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Go": {
      background: "#ccfbf1",
      borderColor: "#5eead4",
      color: "#115e59"
    },
    "AppSignal for JavaScript": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Node.js": {
      background: "#dcfce7",
      borderColor: "#86efac",
      color: "#166534"
    },
    "AppSignal for Python": {
      background: "#dbeafe",
      borderColor: "#93c5fd",
      color: "#1e40af"
    },
    "AppSignal for Ruby": {
      background: "#fee2e2",
      borderColor: "#fca5a5",
      color: "#991b1b"
    },
    "AppSignal for Rust": {
      background: "#ffedd5",
      borderColor: "#fdba74",
      color: "#9a3412"
    }
  };
  const getPillStyle = name => ({
    ...defaultPillStyle,
    ...pillStyles[name] || ({})
  });
  return <div className="not-prose my-4 rounded-lg border border-zinc-200 bg-zinc-50 px-4 py-3 text-sm dark:border-white/10 dark:bg-white/5">
      <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
        <span className="font-semibold text-zinc-700 dark:text-zinc-200">
          {label}:
        </span>
        {versions.map((v, i) => <span key={`${v.name}-${v.version}-${i}`} className="inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium" style={getPillStyle(v.name)}>
            <span>{v.name}</span>
            <span className="opacity-70">
              {v.version}
              {v.exact ? "" : "+"}
            </span>
          </span>)}
      </div>
    </div>;
};

<Compatibility versions={[{ name: "AppSignal for Browser", version: "1.0.0-beta.7" }]} />

<Note>
  Browser monitoring é uma funcionalidade em beta do [AppSignal Labs](/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](https://discord.gg/EjF6ykYx63).
</Note>

<a id="product-page-example" />

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](/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](/distributed-tracing#availability-and-setup) funciona da mesma forma.

O [mapa de serviços](/trace-page#service-map) mostra os dois lados desse trace:

<Frame caption="O mapa de serviços para este trace: o erro de back-end conectado ao erro de navegador que o iniciou.">
  <img src="https://mintcdn.com/appsignal-715f5a51/Dd6j9BLrZGGvnmnD/assets/images/screenshots/browser/distributed-tracing-service-map.png?fit=max&auto=format&n=Dd6j9BLrZGGvnmnD&q=85&s=34693ed41ff4344c9a80827fbd60f3fd" alt="Mapa de serviços do trace com duas caixas, Browser e django, ambas marcadas com um erro, conectadas por uma aresta de 81 ms." width="1049" height="575" data-path="assets/images/screenshots/browser/distributed-tracing-service-map.png" />
</Frame>

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.

<Note>
  Distributed tracing é uma funcionalidade em beta do [AppSignal Labs](/labs). O SDK do navegador não precisa de collector. O serviço receptor precisa de um [collector hospedado](/collector/hosted-vs-self-hosted#hosted-collector) do AppSignal para seus spans.
</Note>

<h2 id="before-you-start">
  Antes de começar
</h2>

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](#product-page-example) 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"](https://appsignal.com/redirect-to/organization?to=admin/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](/python/configuration/collector#configuring-the-collector) e [Ruby](/ruby/configuration/collector#configuring-the-collector), defina a URL como a opção `collector_endpoint`. O Ruby também precisa da [gem `appsignal-opentelemetry`](/ruby/configuration/collector#installing-the-opentelemetry-gems).
* **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:
  * [Python](/python/configuration/options#option-service_name), [Ruby](/ruby/configuration/options#option-service_name) e [PHP](/php/configuration/options#option-service_name): a opção `service_name`.
  * [Go](/go/configuration/options#option-service.name) e [Java](/java/configuration/options#option-service.name): o atributo de recurso `service.name`.
  * [Outras configurações OpenTelemetry](/opentelemetry/configuration/options#service-name): o atributo de recurso `service.name`.
* **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](/go/installation#configure-opentelemetry-in-your-application) 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](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) antes da requisição. Permita `traceparent` na resposta do back-end ao preflight. Caso contrário, o navegador pode bloquear a requisição:

<CodeGroup>
  ```http HTTP theme={null}
  Access-Control-Allow-Headers: content-type, traceparent
  ```
</CodeGroup>

<Warning>
  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.
</Warning>

<h2 id="enable-it">
  Ativar
</h2>

Adicione um padrão para cada host e caminho de back-end em `tracePropagationTargets`. A lista vazia padrão deixa o tracing desligado:

<CodeGroup>
  ```js appsignal.js theme={null}
  import { init } from "@appsignal/browser";

  init({
    key: "<YOUR_FRONTEND_API_KEY>",
    endpoint: "https://appsignal-endpoint.net",
    appVersion: "<YOUR_APP_REVISION>",
    // Your API hosts, matched against host + pathname
    tracePropagationTargets: ["api.example.com/**"],
    // How this front end is named in a trace. Defaults to "Browser"
    serviceName: "Checkout UI",
  });
  ```
</CodeGroup>

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:

| Padrão | Corresponde a |
| - | - |
| `api.example.com/**` | Toda requisição para `api.example.com` na porta padrão. |
| `api.example.com:8443/**` | Toda requisição para `api.example.com` na porta 8443. Inclua a porta quando ela não for a padrão. |
| `*.example.com/**` | Toda requisição para um subdomínio de `example.com`. |
| `api.example.com/v1/**` | Requisições sob `/v1` em `api.example.com`. |
| `api.example.com` | Nada. Não tem caminho, então adicione `/**`. |
| `/api/**` | Nada. Não tem host. |
| `**/api/**` | Esse caminho em qualquer host, incluindo terceiros que você nunca quis rastrear. Evite. |

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](https://appsignal.com/redirect-to/organization?to=sites/new/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](#before-you-start). 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.

<h2 id="what-is-reported">
  O que é relatado
</h2>

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](/browser/error-tracking#what-is-reported) 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](/browser/privacy#urls-and-query-parameters).
* **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](/browser/breadcrumbs#reading-network-breadcrumbs), 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](/browser/error-tracking#rate-limits) 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.

<h2 id="reading-it-in-appsignal">
  Lendo no AppSignal
</h2>

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](/browser-monitoring/errors).

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](#product-page-example), `GET /api/boom/` retornou HTTP 500. Na [linha do tempo do trace](/trace-page#trace-timeline), 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.

<Frame caption="A requisição com falha do navegador e os spans relacionados do Django em um único trace.">
  <img src="https://mintcdn.com/appsignal-715f5a51/Dd6j9BLrZGGvnmnD/assets/images/screenshots/browser/distributed-tracing-trace-timeline.png?fit=max&auto=format&n=Dd6j9BLrZGGvnmnD&q=85&s=7bee604479952a0a8d48422852810a59" alt="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." width="1395" height="874" data-path="assets/images/screenshots/browser/distributed-tracing-trace-timeline.png" />
</Frame>

<h2 id="joining-a-trace-your-code-started">
  Juntando-se a um trace que seu código iniciou
</h2>

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](/trace-page#trace-timeline) em tela cheia para inspecionar o trabalho de back-end.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.