Sentry-javascript: Suggestion de nœud : enregistrer les erreurs dans `unhandledRejection`

Créé le 19 févr. 2019  ·  41Commentaires  ·  Source: getsentry/sentry-javascript

Forfait + Version

  • [ ] @sentry/browser
  • [x] @sentry/node
  • [ ] raven-js
  • [ ] raven-node _(corbeau pour nœud)_
  • [ ] autre:

Version:

4.6.1

La description

Dès la sortie de la boîte, Node enregistrera les refus de promesses non gérées. Cependant, après avoir initialisé Sentry, ces journaux disparaîtront. Cela se produit parce que Node ne consignera pas les rejets si un gestionnaire unhandledRejection existe et que Sentry enregistre un tel gestionnaire.

Je voudrais suggérer que Sentry ajoute la journalisation à son gestionnaire, pour assurer la parité avec l'expérience fournie par défaut. À tout le moins, la documentation doit mentionner ce comportement et la nécessité d'ajouter manuellement un gestionnaire supplémentaire pour restaurer la journalisation.

Commentaire le plus utile

Je trouve toujours étrange que uncaughtException et unhandledRejection soient traités différemment. Sentry restaure la journalisation pour uncaughtException pourquoi ne fait-il pas la même chose pour unhandledRejection ? Les utilisateurs ne devraient pas avoir à se souvenir d'utiliser cet indicateur de nœud. ??

Tous les 41 commentaires

Cela semble bien, cependant, je ne sais pas si cela devrait être derrière notre drapeau debug: true .
En fin de compte, vous attachez consciemment des gestionnaires d'erreurs, qui redirigent le flux d'erreurs vers Sentry.

Je ne suis pas sûr non plus.

L'activation de Sentry n'a pas pour effet de désactiver la journalisation des exceptions non interceptées, il devrait donc en être de même pour les rejets de promesses non gérées. (Bien que cette différence de comportement soit plus une incohérence dans Node que Sentry.)

Lorsque j'active Sentry, je comprends qu'il signale mes erreurs, mais j'ai tendance à considérer la journalisation de la console comme une chose distincte, en particulier dans dev. ??

Nous ne modifions pas le comportement de journalisation par défaut, et pour les exceptions non détectées, c'est le nœud lui-même qui déclenche un appel de journal.

Je pense que la meilleure solution ici serait de simplement en faire une note dans la documentation et de laisser

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at:', p, 'reason:', reason);
});

extrait au cas où quelqu'un voudrait réactiver l'avertissement.

Des docs suffiraient. Au moins, Sentry ne fait rien de spécial. C'est vraiment Node qui est le problème ici.

ou exceptions non interceptées, c'est le nœud lui-même qui déclenche un appel de journal.

À la réflexion, je ne suis pas sûr que ce soit vrai.

Sentry enregistre un gestionnaire uncaughtException qui désactive le comportement par défaut du nœud (log + exit).

Le gestionnaire ( defaultOnFatalError ) déclenche son propre appel de journal : https://github.com/getsentry/sentry-javascript/blob/4.6.3/packages/node/src/handlers.ts#L282.

Si nous « restaurons » la journalisation des exceptions non interceptées, je pense que nous devrions faire la même chose pour les refus de promesse non gérés.

Pouvons-nous rouvrir ceci? Selon mon dernier commentaire, je pense maintenant que Sentry devrait restaurer la journalisation pour les rejets de promesse non gérés, comme il le fait pour les exceptions non interceptées.

J'ai trouvé ce problème parce que je commençais à utiliser Sentry et je me demandais si j'avais fait une erreur dans mon code puisque seulement uncaughtException était dans mon journal et non unhandledRejection . Il serait très logique que ces deux cas soient traités de la même manière.

Je dirais donc soit connectez les deux, soit ne connectez aucun.

J'ai trouvé un meilleur moyen de gérer cela, que de copier le code du noyau de Node.

λ: node --unhandled-rejections=warn app.js

Cela a également été évident en incluant sur la page principale de la documentation https://github.com/getsentry/sentry-docs/pull/1099

Je trouve toujours étrange que uncaughtException et unhandledRejection soient traités différemment. Sentry restaure la journalisation pour uncaughtException pourquoi ne fait-il pas la même chose pour unhandledRejection ? Les utilisateurs ne devraient pas avoir à se souvenir d'utiliser cet indicateur de nœud. ??

pourquoi ne fait-il pas la même chose pour unhandledRejection

Parce que l'un est critique ( unhandledException tue le processus), et l'autre est informatif (c'est donc un avertissement, pas une erreur).

Si nous inversons l'ordre et émettons l'avertissement par défaut, nous interromprons le comportement de la CLI en les émettant bien que --unhandled-rejections soit défini sur none . À l'heure actuelle, tout fonctionne comme prévu selon la documentation officielle du nœud. Ce changement le rendrait non standard.

Une fois que Node décide de faire que unhandledRejection tue également un processus (ce qu'ils disent pour 4 versions maintenant :P), nous ferons également le changement pour être conforme à la spécification officielle.

Si nous inversons l'ordre et émettons l'avertissement par défaut, nous interromprons le comportement de la CLI

@kamilogorek , mais lors de l'exécution avec node il enregistre unhandledRejection à console . Je ne sais donc pas ce que dit la documentation officielle du nœud, mais au moins c'est le comportement que je remarque.

@freeall uniquement si vous n'attachez pas le gestionnaire unhandledRejection . Si vous exécutez le code ci-dessous, même sans le SDK, il ne se connectera toujours pas, vous devez donc savoir quel code vous exécutez.

process.on('unhandledRejection', () => `¯\_(ツ)_/¯`);

Et nous indiquons très clairement ici que nous le faisons : https://docs.sentry.io/platforms/node/default-integrations/

Les intégrations système sont des intégrations activées par défaut qui se combinent dans la bibliothèque standard ou dans l'interpréteur lui-même. Ils sont documentés afin que vous puissiez voir ce qu'ils font et qu'ils peuvent être désactivés s'ils causent des problèmes.
OnUnhandledRejet
Cette intégration attache des gestionnaires de rejet globaux non gérés.

Je ne veux tout simplement pas changer le comportement du nœud, c'est tout. Et le comportement est : "s'il y a un écouteur, n'émettez pas. Si vous voulez toujours l'avertissement, utilisez flag." - et c'est exactement ce que nous faisons.

@kamilogorek Je comprends d'où vous venez. Mais je pense que les utilisateurs de Sentry s'attendraient à ce que Sentry ne modifie pas le comportement de leur programme.

Si j'ai un unhandledRejection sans Sentry, je le vois dans ma console.
Si j'ai un unhandledRejection avec Sentry, je ne le vois pas dans ma console.

Personnellement, je n'aime pas que Sentry modifie le comportement.

Mais c'est ainsi que Node.js est conçu ¯_(ツ)_/¯
Si vous ajoutez un gestionnaire, l'avertissement disparaît. Notre SDK ajoute un gestionnaire, car c'est le seul moyen de détecter les erreurs non gérées, ce qui est l'objectif principal du SDK.

Vous avez bien sûr raison sur la façon dont le nœud est conçu. Lorsque vous attachez un gestionnaire, l'avertissement disparaît.
Ce que les gens demandent, c'est d'imiter le comportement par défaut du nœud et de le consigner dans la console. Un changement de comportement n'est pas ce que vous attendez d'un outil comme Sentry

Quoi qu'il en soit, il semble que vous soyez fixé sur ce comportement, donc inutile de poursuivre la discussion. Mais merci d'avoir pris le temps de répondre :)

@freeall merci aussi, c'est toujours bon de voir les deux côtés :)

Juste pour clarifier : lors de l'activation de Sentry, le comportement de unhandledException (exit + log) est conservé, mais le comportement de unhandledRejection (log) ne l'est pas :

|gestionnaire|journaux|sorties|
|-|-|-|
| unhandledException par défaut|oui|oui|
| unhandledException Sentinelle|oui|oui|
| unhandledRejection par défaut|oui|non|
| unhandledRejection Sentinelle|non|non|

À l'heure actuelle, tout fonctionne comme prévu selon la documentation officielle du nœud.

"Comme prévu" ici suppose que l'utilisateur comprend que Sentry enregistre un auditeur pour unhandledRejection . C'est un détail d'implémentation dont les utilisateurs ne devraient pas avoir à se soucier.

Je vois votre point cependant. Sentry doit également respecter --unhandled-rejections , ce qu'il ne ferait pas si le drapeau était défini sur none et que Sentry continuait à se connecter.

Le commentaire de

Je pense que les utilisateurs de Sentry s'attendraient à ce que Sentry ne modifie pas le comportement de leur programme.

Les refus de promesses non prises ne sont pas des "erreurs de seconde classe". Ils peuvent provoquer la panne des applications, tout comme les erreurs normales.

Il semble que plusieurs utilisateurs aient rencontré ce problème (y compris moi), et d'autres le rencontreront à l'avenir.

Donc en résumé : Sentry fait taire les erreurs de la console. Et je pense qu'il est évident à quel point cela est déroutant, et probablement pas prévu par la plupart des utilisateurs de sentinelles. Ils n'installent pas sentinelle pour faire taire certains sous-ensembles d'erreurs de la console.

Donc le raisonnement (par @kamilogorek )

c'est ainsi que Node.js est conçu

C'est un peu énigmatique pour moi. Comment cela dicte-t-il la façon dont la sentinelle doit se comporter ?

Doit-on s'attendre à ce que les utilisateurs connaissent :

a) le fonctionnement interne de sentrys (enregistre les gestionnaires d'événements)

b) fonctionnement interne du nœud (l'ajout de gestionnaires fait disparaître les avertissements)

Et s'ils ne le font pas, eh bien ils devraient ?

Bien sûr, vous avez raison de dire "Eh bien, l'utilisateur doit savoir ce que le code fait sous le capot", mais la réalité est différente. Et vous avez ici la possibilité d'augmenter la facilité d'utilisation de sentinelle, ou non.

C'est bien de dire "nous ne nous soucions pas de ce problème particulier", mais le peindre d'une manière "ce n'est pas un bug, c'est une fonctionnalité" semble peu sincère.

TLDR : IMOH Si vous souhaitez augmenter la facilité d'utilisation et réduire les problèmes pour les utilisateurs débutants, cela devrait être corrigé.

@OliverJAsh , @freeall
Quelles solutions avez-vous utilisées pour ce problème ?

@schumannd J'ai ajouté un extrait de la façon dont je le charge. Et je suis d'accord avec vous pour dire que la réponse "ce n'est pas un bug, c'est une fonctionnalité" ne semble pas satisfaisante. Je crains que de nombreux programmeurs n'attrapent pas certains bogues dans leur programme parce que Sentry les mange. Pour moi, la première priorité d'un outil comme Sentry devrait être d'attraper les bogues, et non de les créer.

...
if (isUsingSentry) {
  // Log to console because Sentry overwrites standard behavior. https://github.com/getsentry/sentry-javascript/issues/1909.
  // Note that it doesn't overwrite for uncaughtException.
  process.on('unhandledRejection', console.error)
}
...

Comme j'utilise sentinelle dans React Native, il semble que j'aurais besoin de faire quelques trucs pour résoudre ce problème. Est-ce que quelqu'un utilise React Native et résout ce problème d'une manière différente ?

@OliverJAsh , @kamilogorek
Pouvons-nous s'il vous plaît faire rouvrir et réparer cela?

Sentry ne devrait absolument pas déranger la façon dont les erreurs sont enregistrées dans la console - et ce n'est pas seulement un problème avec Node, car la journalisation de la console est également supprimée dans le navigateur.

C'est super ennuyeux d'essayer de déboguer des choses, et comme vous n'avez pas pris la peine de le mentionner dans la documentation de JavaScript, je pensais en fait que je n'avais pas d'erreurs lorsque j'ai regardé dans la console tout en testant une version intermédiaire, et je ne m'en suis donc pas rendu compte avait des erreurs, jusqu'à ce qu'il ait été déployé en production. C'est une expérience utilisateur vraiment merdique pour un service de rapport d'erreurs, et vous devez la corriger si vous voulez des clients satisfaits.

Et comme dit précédemment, les refus de promesses ne sont pas des erreurs de seconde classe - ils peuvent être tout aussi fatals que toute autre erreur non gérée, et ne doivent en aucun cas être supprimés.

Ainsi, un peu de débogage révèle la raison pour laquelle la journalisation de la console est supprimée :

image

Sentry attribue une fonction à window.onunhandledrejection , et comme nous le voyons ici, cette fonction renvoie false , supprimant ainsi explicitement la journalisation de la console. Alors oui, Sentry _change_ le comportement par défaut - ce n'est pas cool.

Heureusement, il stocke une référence à toute fonction existante et l'appelle si elle existe.
Ainsi, la solution de contournement pour réactiver la journalisation de la console consiste à ajouter cette ligne avant d'initialiser Sentry :

window.onunhandledrejection = () => true;

Maintenant, veuillez corriger cela, afin que nous puissions avoir le comportement par défaut sans ces hacks inutiles 🙂

@schumannd s'il vous plaît rouvrir le problème

@thomas-darling Je suis d'accord avec le changement de navigateur, il devrait également renvoyer true pour les promesses et je peux changer cela.

Cependant, pour le nœud, je ne suis toujours pas convaincu pour une raison. Il lie le code à l'implémentation actuelle de Node. Si nous copions les éléments internes au lieu de nous fier aux indicateurs et que le comportement de rejet de la promesse changera dans la v14, nous devrons détecter dans quelle version du nœud nous nous trouvons et agir en conséquence.
Peu importe ce que nous retournons de l'auditeur, car en interne, le nœud vérifie simplement le tableau des auditeurs et n'émet un avertissement que s'il n'y a aucun auditeur, et cette détection ne peut pas être modifiée - https://github.com/nodejs /node/blob/7cf6f9e964aa00772965391c23acda6d71972a9a/lib/internal/process/promises.js#L163 -L216

Ça a l'air bien, concernant le changement de navigateur :+1:

En ce qui concerne Node, si vous ne corrigez pas la connexion à Sentry, vous forcez simplement tous vos utilisateurs à le faire eux-mêmes - avec le risque supplémentaire que certains le fassent mal, et certains ne réaliseront même pas qu'ils en ont besoin, jusqu'à ce qu'ils se faire piquer par un bug de production, comme je l'ai fait. Ce n'est pas une bonne expérience de développeur...

@thomas-darling, comment voudriez-vous le faire réparer ? Reproduire le même code qui se trouve dans le code du nœud ?

Tout en haut de nos documents, il y a une note très visible sur ce qu'il faut faire pour obtenir la journalisation de la console par défaut - https://docs.sentry.io/platforms/node/

image

Je vois votre point - devoir reproduire le comportement du nœud serait un problème de maintenance potentiel, et cela aide que cela puisse, pour le nœud, être résolu avec un simple indicateur de ligne de commande.

Mais si vous ne souhaitez pas reproduire le comportement du nœud, enregistrez au moins un avertissement sur la console lorsque cet indicateur n'est pas spécifié, afin que les utilisateurs sachent que les erreurs sont supprimées et comment les éviter.

Cela devient encore plus important dans la prochaine version de node, où les rejets non gérés entraîneront, par défaut, le blocage du processus - ce qui, si j'ai bien compris, ne se produira pas lorsque Sentry ajoutera son gestionnaire.
Les utilisateurs qui s'appuient sur ce nouveau comportement par défaut dans le nœud pourraient avoir une mauvaise surprise s'ils installent ultérieurement Sentry et que leur processus se poursuit soudainement, malgré une erreur fatale.
C'est le genre de chose qui pourrait entraîner une perte de données ou d'autres catastrophes.

Comme je le vois, il y a quelques options:

  1. Répliquez la façon de procéder de Node.js
  2. Écrivez simplement à console.error lorsqu'il y a un rejet non géré
  3. Supprimez l'erreur afin que le développeur ne la voie jamais

Je pense que l'option 1 ou 2 semble bien. Votre client voit l'erreur et peut la corriger.
Ce que vous ne devriez absolument pas faire, c'est l'option 3, où votre client ne voit pas d'erreurs et Sentry provoque des erreurs dans la production (oh, mais l'ironie pour un outil de rapport d'erreurs). C'est le comportement actuel et cela devrait vraiment s'arrêter ! Sentry devrait m'aider à détecter les erreurs, pas à les aggraver.

Même si vous choisissez l'option 2, au moins les développeurs verront le rejet et remarqueront qu'ils voulaient un comportement différent (comme un plantage), et pourront l'implémenter. Mais sans savoir qu'il y a même eu un rejet, ils ne peuvent pas y faire grand-chose.

Cela devrait faire le travail. https://github.com/getsentry/sentry-javascript/pull/2312
Je n'ai pas ajouté de moyen d'ajouter votre propre rappel, car écrire le code ci-dessous aurait exactement le même effet :

```js
Sentinelle.init({
intégrations : [
new Sentry.Integrations.OnUnhandledRejection({
mode : 'aucun'
})
]
});

process.on('unhandledRejection', (raison) => {
// votre rappel
})

pour moi, cela donne TypeError: undefined is not a constructor . Peut-être, parce que j'utilise maintenant le package @sentry/react-native . Au fait, ce paquet a-t-il le même problème ?

@schumannd @sentry/react-native n'utilise pas @sentry/node , il n'a donc pas cette intégration. Pour cela, vous aurez juste besoin de mettre à jour une version une fois que nous aurons publié Sentry/browser et cela fonctionnera très bien (car la modification pour renvoyer true des gestionnaires est par défaut et non configurable).

@kamilogorek me va bien 👍

Merci d'avoir fait ça! Pourriez-vous envoyer un ping ici une fois celui-ci publié ?

@OliverJAsh ping :)

Juste pour vérifier si j'ai bien compris : si j'utilise le drapeau --unhandled-rejections=strict Node, Node lèvera le rejet non géré comme une exception, puis Sentry interceptera cette exception et la signalera ? C'est ce que je pense voir.

Je demande parce que lorsque j'ai essayé d'activer --unhandled-rejections=strict , il semblait que l'intégration de OnUnhandledRejections n'avait eu aucun effet - l'écouteur d'événement n'a jamais été appelé.

Ce serait génial si nous pouvions ajouter des documents à ce sujet !

Docs PR est déjà en cours https://github.com/getsentry/sentry-docs/pull/1351/

@OliverJAsh ce changement n'a rien à voir avec le drapeau cli. Son comportement est intact. La chose qui a changé est que l'intégration de OnUnhandledRejection a une nouvelle option qui vous permet de la faire se comporter comme l'indicateur cli.

Sentry.init({
  integrations: [
    new Sentry.Integrations.OnUnhandledRejection({
      mode: 'none'
    })
  ]
});

est (conceptuellement) identique à --unhandled-rejection=none et il en va de même pour warn et strict .
Lorsque vous utilisez warn (qui est la valeur par défaut maintenant), il enregistre l'avertissement et l'erreur lui-même, mais le processus sera maintenu en vie.
Lorsque vous utilisez strict , il enregistre, capture l'événement, le vide (attend sa livraison) et tue le processus avec le code de sortie 1.

Ça a du sens. Je comprends que l'intégration ne change pas le comportement du drapeau Node. Cependant, puis-je simplement vérifier que je comprends correctement le comportement de Sentry (en dehors de cette intégration) en ce qui concerne le drapeau Node ?

Juste pour vérifier si j'ai bien compris : si j'utilise l'indicateur --unhandled-rejections=strict de Node, Node lèvera le rejet non géré comme une exception, puis Sentry interceptera cette exception et la signalera ? C'est ce que je pense voir.

@schumannd Pour info , ce matin, nous avons publié @sentry/react-native 1.10.0 [EDIT: whoops, should be 1.1.0 ], qui met à jour sa dépendance pour utiliser la dernière version de @sentry/browser (qui inclut le retour - true -au lieu-de- false correctif mentionné ci-dessus).

@lobsterkatie la dernière version de @sentry/react-native semble être la 1.3.7. .

Donc essayer d'installer 1.10.0 ne fonctionne pas. Comment obtenir le correctif ?

@schumannd @lobsterkatie signifiait 1.1.0 , car c'est à ce moment-là que nous avons mis à jour 5.9.0 de @sentry/browser . L'option de gestionnaire qui définit le niveau de journalisation devrait également fonctionner correctement dans la version récente de @sentry/react-native .

Cette page vous a été utile?
0 / 5 - 0 notes