
OpenTelemetry dans une app Vue : ce qui marche aujourd'hui, et ce qui reste expérimental (2026)
- vuetelemetry
- Guides
- 9 min de lecture
OpenTelemetry sait tracer une app Vue du chargement du document jusqu'à l'appel fetch, mais le volet navigateur est bien moins stabilisé que le volet serveur. Quels paquets sont stables, ce que l'auto-instrumentation capture vraiment, le trou côté Vue que personne ne comble, et où finissent les données.
Votre app Vue tourne sur la machine de quelqu'un d'autre, sur un réseau que vous ne maîtrisez pas, dans une version de navigateur que vous n'avez pas choisie. Les logs serveur vous disent qu'une requête est arrivée et qu'une réponse est partie ; ils ne vous disent rien des quatre secondes passées par l'utilisateur devant un spinner. OpenTelemetry est le standard neutre qui comble ce trou : une seule façon de produire traces, métriques et logs, et n'importe quel backend qui parle le protocole peut les recevoir.
Le gain, c'est une trace unique qui commence dans le navigateur et finit dans votre base. Un span de chargement du document, puis le fetch que la page déclenche, puis le span serveur provoqué par ce fetch, le tout recousu par le contexte de trace propagé dans les en-têtes HTTP. Voilà ce que ni les devtools Vue ni l'agent serveur de votre APM ne donnent seuls, et c'est bien pour ça qu'on va chercher OpenTelemetry côté front.
SDK stable, terrain mouvant

Passons à la partie honnête, celle qu'on escamote régulièrement. Le SDK de tracing navigateur, `@opentelemetry/sdk-trace-web`, est marqué stable dans le dépôt OpenTelemetry JS. Mais la documentation officielle est franche sur le tableau d'ensemble : « Client instrumentation for the browser is experimental and mostly unspecified. » Ces deux affirmations sont vraies en même temps et ne se contredisent pas. La tuyauterie qui crée et exporte les spans est stabilisée ; les conventions sur ce que devrait contenir un span de navigateur, et sur les signaux qu'un front devrait émettre, ne le sont pas.
Il existe aussi un chantier plus récent qu'il vaut mieux connaître avant de bâtir sur des suppositions. Le dépôt `open-telemetry/opentelemetry-browser` publie `@opentelemetry/browser-instrumentation`, dont le statut est indiqué comme expérimental. Son approche diffère des paquets plus anciens : il émet des enregistrements de log structurés pour la performance du navigateur et les interactions utilisateur, en complément des instrumentations à base de spans maintenues ailleurs. Si vous démarrez aujourd'hui, bâtissez sur la voie stable des spans et considérez la voie événementielle comme un sujet à suivre, pas comme une dépendance.
Les paquets et le montage
Le jeu de paquets utile est court. `@opentelemetry/api` fournit l'interface tracer, `@opentelemetry/sdk-trace-web` le provider navigateur, `@opentelemetry/sdk-trace-base` les processeurs de spans et l'exporteur console, `@opentelemetry/context-zone` le gestionnaire de contexte, et `@opentelemetry/instrumentation` l'utilitaire d'enregistrement. Les instrumentations individuelles se livrent à part, tout comme les exporteurs OTLP. Rien ici n'est spécifique à Vue, ce qui est déjà un indice sur la suite.
- `@opentelemetry/sdk-trace-web` est stable, mais la documentation officielle indique que l'instrumentation client pour le navigateur est expérimentale et largement non spécifiée
- Trois appels pour le monter : créer `WebTracerProvider` avec ses processeurs de spans, `provider.register()` avec `ZoneContextManager`, puis `registerInstrumentations()`
- La couverture prête à l'emploi, c'est chargement du document, interactions utilisateur, XHR et fetch - regroupés dans `@opentelemetry/auto-instrumentations-web`
- Il n'existe pas d'instrumentation Vue officielle : les spans de composants et de router sont du code que vous écrivez et maintenez vous-même
- `@opentelemetry/browser-instrumentation` (dépôt opentelemetry-browser, plus récent) est expérimental et émet des enregistrements de log structurés plutôt que des spans
- `SimpleSpanProcessor` avec la console pour le développement, `BatchSpanProcessor` avec un exporteur OTLP pour la production
Le montage tient en trois appels. On crée le provider avec ses processeurs de spans, par exemple `new WebTracerProvider({ spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] })`. On l'enregistre avec un gestionnaire de contexte, `provider.register({ contextManager: new ZoneContextManager() })`. Puis on enregistre ses instrumentations avec `registerInstrumentations({ instrumentations: [new DocumentLoadInstrumentation()] })`. La console et `SimpleSpanProcessor` sont faits pour le développement ; en production on veut `BatchSpanProcessor` et un exporteur OTLP, pour que les spans partent par lots plutôt qu'une requête par span.
Ce que capture l'auto-instrumentation
Ce que capturent réellement les instrumentations toutes faites est plus étroit qu'on ne l'imagine. `@opentelemetry/instrumentation-document-load` produit des spans pour le chargement du document et le navigation timing. `@opentelemetry/instrumentation-user-interaction` trace les interactions utilisateur, les clics par exemple. `@opentelemetry/instrumentation-xml-http-request` et son équivalent fetch couvrent les requêtes sortantes. `@opentelemetry/auto-instrumentations-web` les regroupe pour n'en enregistrer qu'une au lieu de quatre. Au total vous obtenez le chargement de page, les clics et les appels réseau : une vraie couverture, mais une couverture du navigateur, pas de vos composants.
Le gestionnaire de contexte mérite un arrêt. `ZoneContextManager` existe parce que le contexte asynchrone ne se propage pas tout seul dans un navigateur : sans lui, un span ouvert avant un await perd fréquemment son parent, et votre trace se fragmente en orphelins. Il repose sur zone.js, ce qui implique d'embarquer et d'exécuter cette bibliothèque dans votre bundle. C'est un coût réel en poids et en globals patchés, et c'est typiquement le compromis qu'il vaut mieux mesurer que supposer, en particulier sur une stack qui travaille ses Core Web Vitals.
Le trou en forme de Vue
Venons-en au trou. Il n'existe pas d'instrumentation Vue officielle. Ni dans le dépôt principal, ni dans les paquets contrib. Ce qui circule sous le nom d'« instrumentation Vue » dans les billets de blog et les guides d'éditeurs, c'est du code écrit à la main : des spans ouverts dans les hooks du cycle de vie, des spans enroulés autour des gardes de navigation du router, un plugin qui démarre un span par rendu de composant. C'est parfaitement raisonnable à construire et cela peut vraiment servir, mais sachez que vous l'écrivez et le maintenez vous-même, sans convention sémantique à respecter et sans amont dont hériter les correctifs.
Où vont les données est la dernière décision, et celle qui détermine si tout cela paie. L'exporteur parle OTLP en HTTP vers un collecteur ou directement vers un backend ; à partir de là le choix de l'outil vous appartient, précisément parce que le standard est neutre. Commencez plus petit que prévu : `ConsoleSpanExporter` jusqu'à ce que les spans aient l'air corrects dans les devtools, puis document-load et fetch vers un vrai backend, puis décidez si les spans au niveau composant méritent leur place. Tout instrumenter dès le premier jour, c'est ainsi que les projets d'observabilité front finissent en bruit que personne ne lit.



Le gestionnaire de contexte mérite un arrêt. `ZoneContextManager` existe parce que le contexte asynchrone ne se propage pas tout seul dans un navigateur : sans lui, un span ouvert avant un await perd fréquemment son parent, et votre trace se fragmente en orphelins. Il repose sur zone.js, ce qui implique d'embarquer et d'exécuter cette bibliothèque dans votre bundle. C'est un coût réel en poids et en globals patchés, et c'est typiquement le compromis qu'il vaut mieux mesurer que supposer, en particulier sur une stack qui travaille ses Core Web Vitals.