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.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 :
- Navigateur : ajoutez vos motifs d’URL d’API à
tracePropagationTargets. Les requêtes correspondantes portent un en-têtetraceparent. Une réponse 5xx ou un timeout éligible devient une erreur navigateur. - Service API récepteur : instrumentez son serveur HTTP pour qu’il lise
traceparentet rapporte des spans via un collector hébergé AppSignal. Utilisez une intégration prise en charge ou une instrumentation OpenTelemetry pour son framework.
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 liretraceparent, et le service doit envoyer des spans via un collector hébergé AppSignal :
- FastAPI : installez
opentelemetry-instrumentation-fastapiet utilisez le mode collector pour Python. - Rails : utilisez les gems
appsignaletappsignal-opentelemetryen mode collector. L’intégration 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.
Activer
Ajoutez un motif pour chaque hôte et chemin d’API àtracePropagationTargets. La liste vide par défaut laisse le tracing désactivé :
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 :
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êtetraceparent :
- Une réponse 5xx est rapportée comme une
HTTPError. - Un timeout est rapporté comme une
TimeoutError. C’est unfetchqui échoue avec uneTimeoutError, comme le fait celui borné parAbortSignal.timeout(). C’est aussi unXMLHttpRequestdont letimeoutse déclenche. Le serveur a peut-être reçu et tracé une requête arrivée à expiration.
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, lamethod, lestatusquand une réponse est arrivée, et laduration_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
traceparentde 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.
- 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.
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’issuesHTTPError 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 :
Browsermontre uneHTTPErrorsur/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,
djangomontreGET api/boom/avec uneRuntimeError(81 ms). - La requête Django contient deux spans
SELECTet un spanPOST, avec leurs durées.

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

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à untraceparent 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.