Sentry-javascript: Knotenvorschlag: Fehler in `unhandledRejection` protokollieren

Erstellt am 19. Feb. 2019  ·  41Kommentare  ·  Quelle: getsentry/sentry-javascript

Paket + Version

  • [ ] @sentry/browser
  • [x] @sentry/node
  • [ ] raven-js
  • [ ] raven-node _(Rabe für Knoten)_
  • [ ] Sonstiges:

Ausführung:

4.6.1

Beschreibung

Standardmäßig protokolliert Node nicht behandelte Versprechensablehnungen. Nach der Initialisierung von Sentry werden diese Protokolle jedoch verschwinden. Dies geschieht, weil Node keine Ablehnungen protokolliert, wenn ein unhandledRejection Handler vorhanden ist und Sentry einen solchen Handler registriert.

Ich würde gerne vorschlagen, dass Sentry seinem Handler Logging hinzufügt, um Parität mit der Erfahrung zu bieten, die sofort einsatzbereit ist. Zumindest sollten die Dokumente dieses Verhalten und die Notwendigkeit erwähnen, manuell einen zusätzlichen Handler hinzuzufügen, um die Protokollierung wiederherzustellen.

Hilfreichster Kommentar

Ich finde es immer noch seltsam, dass uncaughtException und unhandledRejection unterschiedlich gehandhabt werden. Sentry stellt die Protokollierung für uncaughtException warum macht es nicht dasselbe für unhandledRejection ? Benutzer sollten nicht daran denken müssen, dieses Node-Flag zu verwenden. 🤔

Alle 41 Kommentare

Klingt gut, aber ich bin mir nicht sicher, ob das hinter unserer debug: true Flagge steckt.
Am Ende hängen Sie bewusst Fehlerhandler an, die den Fehlerstrom an den Sentry umleiten.

Ich bin mir auch nicht sicher.

Das Aktivieren von Sentry hat nicht die Auswirkung, dass die Protokollierung für nicht abgefangene Ausnahmen deaktiviert wird. Daher sollte das gleiche möglicherweise für nicht behandelte Versprechensablehnungen gelten. (Obwohl dieser Unterschied im Verhalten eher eine Inkonsistenz in Node als in Sentry ist.)

Wenn ich Sentry aktiviere, verstehe ich, dass meine Fehler gemeldet werden, aber ich neige dazu, die Konsolenprotokollierung als separate Sache zu betrachten, insbesondere in der Entwicklung. 🤔

Wir ändern das Standardprotokollierungsverhalten nicht, und bei nicht abgefangenen Ausnahmen ist es der Knoten selbst, der einen Protokollaufruf auslöst.

Ich denke, die beste Lösung hier wäre, es einfach in den Dokumenten zu notieren und zu gehen

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

Snippet, falls jemand die Warnung wieder aktivieren möchte.

Unterlagen würden reichen. Zumindest macht Sentry dann nichts Besonderes. Es ist wirklich Node, das hier das Problem ist.

oder nicht abgefangene Ausnahmen ist es der Knoten selbst, der einen Protokollaufruf auslöst.

Wenn ich darüber nachdenke, bin ich mir nicht sicher, ob das wahr ist.

Sentry registriert einen uncaughtException Handler, der das standardmäßige Node-Verhalten (Log + Exit) deaktiviert.

Der Handler ( defaultOnFatalError ) löst seinen eigenen Log-Aufruf aus: https://github.com/getsentry/sentry-javascript/blob/4.6.3/packages/node/src/handlers.ts#L282.

Wenn wir die Protokollierung für nicht abgefangene Ausnahmen "wiederherstellen", sollten wir meiner Meinung nach dasselbe für unbehandelte Ablehnungen von Zusagen tun.

Können wir das wieder öffnen? Gemäß meinem letzten Kommentar glaube ich jetzt, dass Sentry die Protokollierung für unbehandelte Versprechensablehnungen wiederherstellen sollte, wie dies bei nicht abgefangenen Ausnahmen der Fall ist.

Ich habe dieses Problem gefunden, weil ich Sentry zu verwenden begann und mich fragte, ob ich einen Fehler in meinem Code gemacht hatte, da nur uncaughtException in meinem Protokoll stand und nicht unhandledRejection . Es wäre sehr sinnvoll, diese beiden Fälle gleich zu behandeln.

Also würde ich sagen, entweder beides protokollieren oder keines von beiden protokollieren.

Ich habe einen besseren Weg gefunden, damit umzugehen, als Code aus dem Kern von Node zu kopieren.

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

Es wurde auch deutlich gemacht, indem es auf der Hauptseite der Dokumentation https://github.com/getsentry/sentry-docs/pull/1099 aufgenommen wurde

Ich finde es immer noch seltsam, dass uncaughtException und unhandledRejection unterschiedlich gehandhabt werden. Sentry stellt die Protokollierung für uncaughtException warum macht es nicht dasselbe für unhandledRejection ? Benutzer sollten nicht daran denken müssen, dieses Node-Flag zu verwenden. 🤔

Warum tut es nicht dasselbe für unhandledRejection?

Weil einer kritisch ist ( unhandledException den Prozess) und einer informativ ist (also eine Warnung, kein Fehler).

Wenn wir die Reihenfolge umkehren und die Warnung standardmäßig ausgeben, unterbrechen wir das CLI-Verhalten, indem wir sie ausgeben, obwohl --unhandled-rejections auf none . Im Moment funktioniert laut offizieller Node-Dokumentation alles wie erwartet. Diese Änderung _würde_ sie nicht zum Standard machen.

Sobald Node beschließt, unhandledRejection auch einen Prozess beenden zu lassen (was sie jetzt für 4 Versionen sagen :P), werden wir die Änderung vornehmen, damit sie auch mit der offiziellen Spezifikation übereinstimmt.

Wenn wir die Reihenfolge umkehren und die Warnung standardmäßig ausgeben, unterbrechen wir das CLI-Verhalten

@kamilogorek , aber wenn es mit node wird, protokolliert es unhandledRejection zu console . Ich weiß also nicht, was die offizielle Node-Dokumentation sagt, aber zumindest ist das das Verhalten, das ich bemerke.

@freeall nur, wenn Sie den unhandledRejection Handler nicht anhängen. Wenn Sie den folgenden Code ausführen, wird er auch ohne SDK immer noch nicht protokolliert, daher müssen Sie wissen, welchen Code Sie ausführen.

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

Und das sagen wir hier ganz klar: https://docs.sentry.io/platforms/node/default-integrations/

Systemintegrationen sind standardmäßig aktivierte Integrationen, die mit der Standardbibliothek oder dem Interpreter selbst kombiniert werden. Sie sind dokumentiert, damit Sie sehen können, was sie tun, und dass sie deaktiviert werden können, wenn sie Probleme verursachen.
OnUnhandledRejection
Diese Integration fügt globale nicht behandelte Ablehnungshandler an.

Ich möchte nur das Verhalten von Node nicht ändern, das war's. Und das Verhalten ist: "Wenn es einen Listener gibt, geben Sie ihn nicht aus. Wenn Sie die Warnung trotzdem haben möchten, verwenden Sie Flag." – und genau das tun wir.

@kamilogorek Ich verstehe, woher du kommst. Aber ich denke, Benutzer von Sentry würden erwarten, dass Sentry das Verhalten ihres Programms nicht ändert.

Wenn ich ein unhandledRejection ohne Sentry habe, sehe ich es in meiner Konsole.
Wenn ich ein unhandledRejection mit Sentry habe, sehe ich es nicht in meiner Konsole.

Mir persönlich gefällt es nicht, dass Sentry das Verhalten ändert.

Aber so ist Node.js aufgebaut ¯_(ツ)_/¯
Wenn Sie einen Handler hinzufügen, ist die Warnung verschwunden. Unser SDK fügt einen Handler hinzu, da dies die einzige Möglichkeit ist, nicht behandelte Fehler abzufangen, was der Hauptzweck des SDK ist.

Sie haben natürlich Recht, wie Node aufgebaut ist. Wenn Sie einen Handler anhängen, ist die Warnung weg.
Was die Leute verlangen, ist, dass Sie das Standardverhalten von Node nachahmen und es in der Konsole protokollieren. Ein geändertes Verhalten ist nicht das, was Sie von einem Tool wie Sentry erwarten

Wie auch immer, es scheint, dass Sie auf dieses Verhalten eingestellt sind, also hat es keinen Sinn, die Diskussion am Laufen zu halten. Aber danke, dass du dir die Zeit genommen hast zu antworten :)

@freeall danke auch, es ist immer gut, die beiden Seiten zu sehen :)

Nur zur Klarstellung: Beim Aktivieren von Sentry wird das Verhalten von unhandledException (exit + log) beibehalten, aber das Verhalten von unhandledRejection (log) nicht:

|handler|logs|exits|
|-|-|-|
| unhandledException Standard|ja|ja|
| unhandledException Wache|ja|ja|
| unhandledRejection Standard|ja|nein|
| unhandledRejection Wache|nein|nein|

Im Moment funktioniert laut offizieller Node-Dokumentation alles wie erwartet.

"Wie erwartet" setzt hier voraus, dass der Benutzer versteht, dass Sentry einen Listener für unhandledRejection registriert. Dies ist ein Implementierungsdetail, um das sich Benutzer keine Sorgen machen müssen.

Ich sehe deinen Punkt aber. Sentry sollte auch --unhandled-rejections respektieren, was es nicht tun würde, wenn das Flag auf none und Sentry weiterhin loggen würde.

@freeall Kommentar fasst das ziemlich gut zusammen:

Ich denke, Benutzer von Sentry würden erwarten, dass Sentry das Verhalten ihres Programms nicht ändert.

Nicht eingeholte Versprechensablehnungen sind keine "Fehler zweiter Klasse". Sie können dazu führen, dass Apps wie normale Fehler abbrechen.

Es scheint, als wären mehrere Benutzer auf dieses Problem gestoßen (einschließlich mir), und in Zukunft werden noch mehr darauf stoßen.

Zusammenfassend also: Sentry unterdrückt Fehler von der Konsole. Und ich denke, es ist offensichtlich, wie verwirrend dies ist und wahrscheinlich von den meisten Wachpostenbenutzern nicht beabsichtigt. Sie installieren Sentry nicht, um eine Teilmenge von Fehlern von der Konsole aus zum Schweigen zu bringen.

Also die Begründung (von @kamilogorek )

so ist Node.js konzipiert

Ist mir etwas kryptisch. Wie bestimmt dies das Verhalten der Wachen?

Sollten wir erwarten, dass Benutzer Folgendes wissen:

a) Sentrys Innenleben (registriert Event-Handler)

b) Knoteninneres (das Hinzufügen von Handlern führt dazu, dass Warnungen verschwinden)

Und wenn nicht, dann sollten sie das?

Natürlich haben Sie Recht, wenn Sie sagen "Nun, der Benutzer sollte wissen, was der Code unter der Haube macht", aber die Realität sieht anders aus. Und Sie haben hier die Möglichkeit, den Bedienkomfort der Wache zu erhöhen oder nicht.

Es ist in Ordnung zu sagen: "Dieses spezielle Problem interessiert uns nicht", aber es in einer "Es ist kein Fehler, es ist ein Feature" zu malen, scheint unaufrichtig.

TLDR: IMOH Wenn Sie die Benutzerfreundlichkeit erhöhen und Probleme für Neulinge reduzieren möchten, sollte dies behoben werden.

@OliverJAsh , @freeall
Welche Lösungen haben Sie für dieses Problem verwendet?

@schumannd Ich habe ein Snippet hinzugefügt, wie ich es lade. Und ich stimme Ihnen zu, dass die Antwort "Es ist kein Fehler, es ist ein Feature" nicht erfüllend zu sein scheint. Ich befürchte, dass viele Programmierer einige Fehler in ihrem Programm nicht finden, weil Sentry sie auffrisst. Für mich sollte die erste Priorität eines Tools wie Sentry darin bestehen, Fehler zu erkennen und nicht sie zu erstellen.

...
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)
}
...

Da ich Sentry in einige hackige Dinge tun, um dieses Problem zu beheben. Verwendet jemand React Native und löst dieses Problem auf andere Weise?

@OliverJAsh , @kamilogorek
Können wir das bitte wieder öffnen und reparieren lassen?

Sentry sollte auf keinen Fall mit der Protokollierung von Fehlern in der Konsole herumspielen - und das ist nicht nur bei Node ein Problem, da die Protokollierung der Konsole auch im Browser unterdrückt wird.

Es ist sehr nervig, wenn man versucht, Dinge zu debuggen, und da Sie sich nicht die Mühe gemacht haben, dies in den Dokumenten für JavaScript zu erwähnen, dachte ich tatsächlich, ich hätte keine Fehler, als ich beim Testen eines Staging-Builds in die Konsole schaute, und habe es daher nicht bemerkt hatte Fehler, bis es in der Produktion bereitgestellt wurde. Das ist eine wirklich beschissene Benutzererfahrung für einen Fehlerberichterstattungsdienst, die Sie beheben müssen, wenn Sie zufriedene Kunden haben möchten.

Und wie bereits gesagt, Versprechensablehnungen sind keine Fehler zweiter Klasse - sie können genauso fatal sein wie jeder andere nicht behandelte Fehler und sollten in keiner Weise unterdrückt werden.

Ein wenig Debugging zeigt also, warum die Konsolenprotokollierung unterdrückt wird:

image

Sentry weist window.onunhandledrejection eine Funktion zu, und wie wir hier sehen, gibt diese Funktion false , wodurch die Konsolenprotokollierung explizit unterdrückt wird. Also ja, Sentry _ändert_ das Standardverhalten - das ist nicht cool.

Glücklicherweise speichert es einen Verweis auf eine vorhandene Funktion und ruft diese auf, wenn sie vorhanden ist.
Die hackige Problemumgehung zum erneuten Aktivieren der Konsolenprotokollierung besteht also darin, diese Zeile hinzuzufügen, bevor Sie Sentry initialisieren:

window.onunhandledrejection = () => true;

Bitte korrigiere das jetzt, damit wir das Standardverhalten ohne solche sinnlosen Hacks haben können 🙂

@schumannd bitte Problem erneut öffnen

@thomas-darling Ich stimme der Browseränderung zu, sie sollte auch true für Versprechen zurückgeben und ich kann das ändern.

Bei Node bin ich jedoch aus einem Grund immer noch nicht überzeugt. Es bindet den Code an die aktuelle Node-Implementierung. Wenn wir die Interna kopieren, anstatt uns auf Flags zu verlassen, und sich das Ablehnungsverhalten in v14 ändert, müssen wir erkennen, in welcher Version des Knotens wir uns befinden, und entsprechend handeln.
Es spielt keine Rolle, was wir vom Listener zurückgeben, da Node intern nur nach dem Listeners-Array sucht und nur dann eine Warnung ausgibt, wenn überhaupt keine Listener vorhanden sind und diese Erkennung nicht geändert werden kann - https://github.com/nodejs /node/blob/7cf6f9e964aa00772965391c23acda6d71972a9a/lib/internal/process/promises.js#L163 -L216

Klingt gut, zum Browserwechsel :+1:

Was Node betrifft, wenn Sie die Anmeldung bei Sentry nicht beheben, zwingen Sie im Grunde alle Ihre Benutzer dazu, es selbst zu tun - mit dem zusätzlichen Risiko, dass einige es falsch machen und einige nicht einmal merken, dass sie es brauchen, bis sie es brauchen von einem Produktionsfehler gebissen werden, wie ich es getan habe. Das ist keine gute Entwicklererfahrung...

@thomas-darling wie möchtest du es reparieren lassen? Den gleichen Code reproduzieren, der sich im Code des Knotens befindet?

Ganz oben in unseren Dokumenten befindet sich ein sehr sichtbarer Hinweis, was zu tun ist, um die Standardprotokollierung der Konsole zu erhalten - https://docs.sentry.io/platforms/node/

image

Ich verstehe Ihren Punkt - das Replizieren des Knotenverhaltens wäre ein potenzielles Wartungsproblem, und es hilft, dass dies für Knoten mit einem einfachen Befehlszeilen-Flag gelöst werden kann.

Wenn Sie jedoch das Knotenverhalten nicht replizieren möchten, sollten Sie zumindest eine Warnung in der Konsole protokollieren, wenn dieses Flag nicht angegeben ist, damit Benutzer wissen, dass Fehler unterdrückt werden und wie dies vermieden werden kann.

Dies wird in der nächsten Version von node noch wichtiger, wo unbehandelte Ablehnungen standardmäßig den Prozess zum Absturz bringen - was, wie ich es verstehe, nicht passiert, wenn Sentry seinen Handler hinzufügt.
Benutzer, die sich auf dieses neue Standardverhalten in node verlassen, könnten möglicherweise eine böse Überraschung erleben, wenn sie später Sentry installieren und ihr Prozess dann plötzlich fortgesetzt wird, obwohl ein schwerwiegender Fehler aufgetreten ist.
Das ist die Art von Dingen, die zu Datenverlust oder anderen Katastrophen führen können.

So wie ich es sehe gibt es ein paar Möglichkeiten:

  1. Replizieren Sie die Vorgehensweise von Node.js
  2. Schreiben Sie einfach an console.error wenn es eine unbehandelte Ablehnung gibt
  3. Unterdrücken Sie den Fehler, damit der Entwickler ihn nie sieht

Ich denke, Option 1 oder 2 scheinen beide in Ordnung zu sein. Ihr Kunde sieht den Fehler und kann ihn beheben.
Was Sie auf keinen Fall tun sollten, ist Option 3, bei der Ihr Kunde keine Fehler sieht und Sentry verursacht, dass Fehler in die Produktion gehen (oh, aber die Ironie bei einem Fehlerberichtstool). Das ist das aktuelle Verhalten und das sollte wirklich aufhören! Sentry sollte mir helfen, Fehler zu erkennen und sie nicht noch schlimmer zu machen.

Selbst wenn Sie Option 2 wählen, sehen zumindest die Entwickler die Ablehnung und bemerken, dass sie ein anderes Verhalten (wie einen Absturz) wünschen und können dies implementieren. Aber ohne zu wissen, dass es überhaupt eine Absage gab, können sie nicht viel dagegen tun.

Dies sollte die Arbeit machen. https://github.com/getsentry/sentry-javascript/pull/2312
Ich habe keine Möglichkeit hinzugefügt, Ihren eigenen Rückruf hinzuzufügen, da das Schreiben von Code unten genau den gleichen Effekt hätte:

```js
Sentry.init({
Integrationen: [
new Sentry.Integrations.OnUnhandledRejection({
Modus: 'kein'
})
]
});

process.on('unhandledRejection', (Grund) => {
// dein Rückruf
})

für mich ergibt das TypeError: undefined is not a constructor . Könnte sein, weil ich jetzt das Paket @sentry/react-native . Hat das Paket übrigens das gleiche Problem?

@schumannd @sentry/react-native verwendet nicht @sentry/node , daher hat es diese Integration nicht. Dazu müssen Sie nur eine Version aktualisieren, sobald wir Sentry/Browser freigeben, und es wird gut funktionieren (da die Änderung, true von Handlern zurückzugeben, standardmäßig und nicht konfigurierbar ist).

@kamilogorek sieht für mich gut aus

Vielen Dank, dass Sie dies tun! Könnten Sie hier pingen, sobald dies veröffentlicht wird?

@OliverJAsh ping :)

Nur um zu überprüfen, ob ich richtig verstanden habe: Wenn ich das Flag --unhandled-rejections=strict Node verwende, löst Node die nicht behandelte Ablehnung als Ausnahme aus, und dann fängt Sentry diese Ausnahme ab und meldet sie? Das ist, was ich glaube, zu sehen.

Ich frage, denn als ich versuchte, --unhandled-rejections=strict aktivieren, schien die Integration von OnUnhandledRejections keine Wirkung zu haben – der Ereignis-Listener wurde nie aufgerufen.

Es wäre toll, wenn wir dazu einige Dokumente hinzufügen könnten!

Docs PR läuft bereits https://github.com/getsentry/sentry-docs/pull/1351/

@OliverJAsh diese Änderung hat nichts mit dem cli-Flag zu tun. Sein Verhalten ist unberührt. Die Sache, die sich geändert hat, ist, dass die Integration von OnUnhandledRejection eine neue Option hat, die es Ihnen ermöglicht, sich wie das cli-Flag zu verhalten.

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

ist (konzeptionell) dasselbe wie --unhandled-rejection=none und dasselbe gilt für warn und strict .
Wenn Sie warn (was jetzt die Standardeinstellung ist), werden die Warnung und der Fehler selbst protokolliert, aber der Prozess wird am Leben gehalten.
Wenn Sie strict , wird es protokolliert, das Ereignis erfasst, geleert (wartet, bis es geliefert wird) und beendet den Prozess mit Exitcode 1.

Das macht Sinn. Ich verstehe, dass die Integration das Verhalten des Node-Flags nicht ändert. Kann ich jedoch nur überprüfen, ob ich das Verhalten von Sentry (außerhalb dieser Integration) in Bezug auf das Node-Flag richtig verstanden habe?

Nur um zu überprüfen, ob ich richtig verstanden habe: Wenn ich das Flag --unhandled-rejections=strict von Node verwende, löst Node die unbehandelte Ablehnung als Ausnahme aus, und dann fängt Sentry diese Ausnahme ab und meldet sie? Das ist, was ich glaube, zu sehen.

@schumannd FYI, heute Morgen haben wir @sentry/react-native 1.10.0 [EDIT: Whoops, sollte 1.1.0 ] veröffentlicht, das seine Abhängigkeit aktualisiert, um die neueste Version von @sentry/browser (einschließlich der Rückgabe - true -anstatt- false oben erwähnte Korrektur).

@lobsterkatie die neueste Version von @sentry/react-native scheint 1.3.7 zu sein. .

Der Versuch, 1.10.0 zu installieren, funktioniert also nicht. Wie bekomme ich die Lösung?

@schumannd @lobsterkatie meinte 1.1.0 , da wir zu diesem Zeitpunkt auf 5.9.0 von @sentry/browser aktualisiert haben. Die Handleroption, die die Protokollierungsebene festlegt, sollte auch in der neuesten Version von @sentry/react-native problemlos funktionieren.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

kamilogorek picture kamilogorek  ·  3Kommentare

Nickforall picture Nickforall  ·  3Kommentare

jaylinski picture jaylinski  ·  3Kommentare

THPubs picture THPubs  ·  3Kommentare

nicolezhu picture nicolezhu  ·  3Kommentare