Skip to main content
Browser monitoring est une fonctionnalité en beta d’AppSignal 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.
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é 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.
Le tracing distribué est une fonctionnalité en beta d’AppSignal Labs. Le SDK navigateur n’a besoin d’aucun collector. Le service récepteur a besoin d’un collector hébergé AppSignal pour ses spans.

Avant de commencer

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é AppSignal :

Activer

Ajoutez un motif pour chaque hôte et chemin d’API à tracePropagationTargets. La liste vide par défaut laisse le tracing désactivé :
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 : 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 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. 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 avant la requête. Autorisez traceparent dans la réponse de votre API au preflight. Sinon, le navigateur risque de bloquer la requête :
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.

Ce qui est rapporté

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, 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.
  • 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, 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, 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é.

Le lire dans AppSignal

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

La requête navigateur échouée et les spans Django associés dans une seule trace.

La carte des services 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.
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.

La carte des services pour la même trace : l'erreur back-end reliée à l'erreur navigateur qui l'a déclenchée.

Rejoindre une trace démarrée par votre code

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 en plein écran pour examiner le travail back-end.