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

# Tracing distribué pour Browser

> Découvrez comment une requête échouée dans le navigateur se connecte à la trace back-end qu'elle a déclenchée, afin que l'erreur et le travail côté serveur qui la sous-tend se lisent comme une seule 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 est une fonctionnalité en beta d'[AppSignal Labs](/labs). Le
  package `@appsignal/browser` est publié sous le tag `beta` sur npm, et sa
  configuration ainsi que son API peuvent encore changer d'une release beta à
  l'autre. Partagez vos retours dans notre
  [communauté Discord](https://discord.gg/EjF6ykYx63).
</Note>

Une page de paiement signale `POST https://api.example.com/orders: HTTP 503`. Vous savez que la requête de commande a échoué, mais pas pourquoi. Le service de commande a peut-être passé quatre secondes à attendre un verrou de base de données avant de renvoyer 503. Le [tracing distribué](/distributed-tracing) vous permet de suivre cette requête du navigateur jusqu'au service de commande.

Pour relier l'erreur du navigateur au travail effectué dans le service de commande, configurez les deux côtés :

1. **Navigateur :** ajoutez vos motifs d'URL d'API à `tracePropagationTargets`. Les requêtes correspondantes portent un en-tête `traceparent`. Une réponse 5xx ou un timeout éligible devient une erreur navigateur.
2. **Service API récepteur :** instrumentez son serveur HTTP pour qu'il lise `traceparent` et rapporte des spans via un collector hébergé AppSignal. Utilisez une intégration prise en charge ou une instrumentation OpenTelemetry pour son framework.

L'étape 1 seule ne rapporte que l'erreur navigateur. Sa chronologie de trace reste vide tant que le service de commande n'est pas instrumenté à l'étape 2, car les spans serveur proviennent de cette instrumentation, pas du SDK navigateur. Les deux étapes sont nécessaires pour voir la requête comme une seule trace.

<Note>
  Le tracing distribué est une fonctionnalité en beta d'[AppSignal Labs](/labs). Le SDK navigateur n'a besoin d'aucun collector. Le service récepteur a besoin d'un [collector hébergé](/collector/hosted-vs-self-hosted#hosted-collector) AppSignal pour ses spans.
</Note>

<h2 id="before-you-start">
  Avant de commencer
</h2>

Choisissez la configuration du service qui reçoit la requête du navigateur. Son intégration de serveur HTTP doit lire `traceparent`, et le service doit envoyer des spans via un [collector hébergé](/collector/hosted-vs-self-hosted#getting-started) AppSignal :

* **FastAPI :** installez [`opentelemetry-instrumentation-fastapi`](/python/instrumentations/fastapi) et utilisez le [mode collector pour Python](/python/configuration/collector).
* **Rails :** utilisez les [gems `appsignal` et `appsignal-opentelemetry`](/ruby/configuration/collector#installing-the-opentelemetry-gems) en mode collector. L'[intégration Rails](/ruby/integrations/rails) lit les traces entrantes.
* **Go ou OpenTelemetry personnalisé :** instrumentez votre serveur HTTP et configurez la propagation du contexte de trace. Consultez [disponibilité et configuration](/distributed-tracing#availability-and-setup).

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

Ajoutez un motif pour chaque hôte et chemin d'API à `tracePropagationTargets`. La liste vide par défaut laisse le tracing désactivé :

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

Les motifs correspondent à l'hôte et au chemin de chaque appel `fetch` et `XMLHttpRequest`. Ils ignorent le schéma et la chaîne de requête. Utilisez `*` à l'intérieur d'un segment de chemin, ou `**` sur plusieurs segments. Indiquez à la fois un hôte et un chemin :

| Motif | Correspond à |
| - | - |
| `api.example.com/**` | Chaque requête vers `api.example.com` sur le port par défaut. |
| `api.example.com:8443/**` | Chaque requête vers `api.example.com` sur le port 8443. Indiquez le port lorsqu'il n'est pas celui par défaut. |
| `*.example.com/**` | Chaque requête vers un sous-domaine de `example.com`. |
| `api.example.com/v1/**` | Les requêtes sous `/v1` sur `api.example.com`. |
| `api.example.com` | Rien. Il n'a pas de chemin, ajoutez donc `/**`. |
| `/api/**` | Rien. Il n'a pas d'hôte. |
| `**/api/**` | Ce chemin sur n'importe quel hôte, y compris des tiers que vous ne vouliez jamais tracer. À éviter. |

Dans la chronologie de trace, `serviceName` étiquette le span d'erreur navigateur. Par exemple, `Checkout UI` identifie les erreurs de votre front-end de paiement. La valeur par défaut est `Browser`. Utilisez un nom différent pour chaque front-end que vous surveillez. Le SDK envoie ce nom avec chaque rapport d'erreur.

Le [flux d'installation du SDK navigateur](https://appsignal.com/redirect-to/organization?to=sites/new/browser) propose **Distributed tracing** comme option. Elle est désactivée par défaut. La sélectionner ajoute `tracePropagationTargets: ["api.example.com/**"]` au snippet navigateur. Remplacez l'hôte d'exemple par votre hôte d'API, puis [instrumentez le service récepteur](#before-you-start). L'assistant n'installe ni ne configure ce service.

Pour vérifier la propagation, chargez une page qui appelle votre API et inspectez la requête dans le panneau Network de votre navigateur. Une requête correspondante doit porter un en-tête `traceparent`. Inspectez ensuite une requête échouée dans AppSignal pour vérifier que les spans back-end apparaissent dans sa trace.

Pour une API cross-origin, comme `api.example.com` appelée depuis `www.example.com`, le navigateur peut envoyer un [preflight CORS](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) avant la requête. Autorisez `traceparent` dans la réponse de votre API au preflight. Sinon, le navigateur risque de bloquer la requête :

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

Le SDK n'ajoute aucun en-tête à une requête effectuée en mode `no-cors`, car le navigateur le retirerait. Ces requêtes ne sont jamais rapportées comme des requêtes échouées.

<h2 id="what-is-reported">
  Ce qui est rapporté
</h2>

Le SDK rapporte ces résultats pour une requête correspondante ayant envoyé un en-tête `traceparent` :

* **Une réponse 5xx** est rapportée comme une `HTTPError`.
* **Un timeout** est rapporté comme une `TimeoutError`. C'est un `fetch` qui échoue avec une `TimeoutError`, comme le fait celui borné par `AbortSignal.timeout()`. C'est aussi un `XMLHttpRequest` dont le `timeout` se déclenche. Le serveur a peut-être reçu et tracé une requête arrivée à expiration.

Le message nomme la requête et son résultat, par exemple `POST https://api.example.com/orders: HTTP 503` ou `GET https://api.example.com/orders: timed out`. En plus de tout ce que porte une [erreur navigateur ordinaire](/browser/error-tracking#what-is-reported), le rapport inclut :

* **La requête**, sous `params.request` : l'`url`, la `method`, le `status` quand une réponse est arrivée, et la `duration_ms`. Les paramètres de requête sont retirés de l'URL selon votre [allowlist](/browser/privacy#urls-and-query-parameters).
* **Le span** : l'ID de trace et l'ID de span issus du `traceparent` de la requête, avec son heure de début et sa durée. AppSignal construit à partir de là le span du navigateur, de sorte qu'il couvre la requête telle que le navigateur l'a vue. Après un timeout, les spans du back-end peuvent durer plus longtemps que le span du navigateur.
* **Le nom de service** que vous avez défini, ou `Browser`.

Rien n'est rapporté pour :

* Une requête réussie. L'en-tête est envoyé, mais le navigateur reste silencieux, de sorte que la trace back-end se suffit à elle-même.
* Une réponse 4xx. Le SDK ne la classe pas comme une requête échouée pour le tracing.
* Une requête que le navigateur n'a pas pu délivrer : refusée, échec DNS, ou bloquée par une extension. Aucun serveur ne l'a traitée, il n'y a donc aucune trace back-end à rejoindre.
* Un timeout alors que l'appareil est hors ligne, ce qui ne dit rien du back-end.
* Une requête que votre code a annulée.

Ces requêtes peuvent tout de même laisser un [breadcrumb réseau](/browser/breadcrumbs#reading-network-breadcrumbs), sauf si elles correspondent à `privacy.networkBlocklist` ou si la collecte de breadcrumbs est désactivée. Un breadcrumb pour une requête ayant propagé le contexte inclut son ID de trace.

Une requête échouée passe par le même pipeline que toute autre erreur. `errors.enabled`, `errors.sampleRate`, les [limites de débit](/browser/error-tracking#rate-limits), et la déduplication des répétitions s'appliquent toutes. `beforeError` la reçoit comme une `HTTPError` ou une `TimeoutError`, avec la requête sous `context.request`. Vous pouvez la supprimer ou l'expurger à cet endroit. Une requête correspondant à `privacy.networkBlocklist` n'est jamais rapportée.

Le SDK évite de rapporter deux fois le même rejet `fetch` lorsqu'il atteint aussi un gestionnaire de rejet non traité ou `captureError()`. Si votre code lève une nouvelle erreur après une réponse 500, cette erreur a sa propre trace. La requête échouée reste un rapport séparé.

<h2 id="reading-it-in-appsignal">
  Le lire dans AppSignal
</h2>

Les requêtes échouées apparaissent dans la vue Errors de la section Browser sous forme d'issues `HTTPError` et `TimeoutError`. Elles sont regroupées par la route sur laquelle se trouvait l'utilisateur, comme toute autre erreur front-end. Pour en savoir plus, consultez [les erreurs front-end dans AppSignal](/browser-monitoring/errors).

Ouvrez une issue pour voir son message, ses breadcrumbs et ses tags. Sur la page complète de l'issue, sélectionnez **Traces**. Sélectionnez ensuite **Fullscreen** dans la carte **Trace timeline** pour ouvrir la vue ci-dessous. Si l'aperçu omet des spans, le bouton affiche **All spans**. Depuis le panneau latéral Browser Errors, **Open full trace page** vous amène à la page de l'issue.

Dans la chronologie en plein écran, `Browser` étiquette le service du span navigateur. Sélectionnez ce span pour voir les détails de la requête et de l'erreur.

Cet exemple montre une page produit où `GET /api/boom/` a renvoyé HTTP 500. Dans la [chronologie de trace](/trace-page#trace-timeline), vous pouvez suivre la requête échouée du navigateur jusqu'au service Django :

* `Browser` montre une `HTTPError` sur `/product/chocolate-stroopwafel` (85 ms). Les détails du span sélectionné montrent l'URL de la requête et la réponse HTTP 500.
* En dessous, `django` montre `GET api/boom/` avec une `RuntimeError` (81 ms).
* La requête Django contient deux spans `SELECT` et un span `POST`, avec leurs durées.

<Frame caption="La requête navigateur échouée et les spans Django associés dans une seule 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="Chronologie de trace reliant une HTTPError navigateur de 85 ms pour GET /api/boom/ (HTTP 500) à une RuntimeError Django de 81 ms, avec des spans enfants SELECT et POST." width="1395" height="874" data-path="assets/images/screenshots/browser/distributed-tracing-trace-timeline.png" />
</Frame>

La [carte des services](/trace-page#service-map) montre la trace entière de bout en bout : l'erreur dans le service Django reliée à la requête échouée dans le navigateur qui l'a déclenchée.

<Frame caption="La carte des services pour la même trace : l'erreur back-end reliée à l'erreur navigateur qui l'a déclenchée.">
  <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="Carte des services de la trace avec deux blocs, Browser et django, tous deux marqués d'une erreur, reliés par une arête de 81 ms." width="1049" height="575" data-path="assets/images/screenshots/browser/distributed-tracing-service-map.png" />
</Frame>

<h2 id="joining-a-trace-your-code-started">
  Rejoindre une trace démarrée par votre code
</h2>

Votre application définit peut-être déjà un `traceparent` valide sur une requête, par exemple via un SDK navigateur OpenTelemetry. AppSignal pour Browser laisse alors cet en-tête intact, et une requête échouée rejoint la trace que votre code a démarrée. Cela vaut aussi bien pour `fetch` que pour `XMLHttpRequest`.

Dans l'onglet **Traces** de l'issue, ouvrez la [chronologie de trace](/trace-page#trace-timeline) en plein écran pour examiner le travail back-end.


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