Sentry-javascript: Sugerencia de nodo: registrar errores en `unhandledRejection`

Creado en 19 feb. 2019  ·  41Comentarios  ·  Fuente: getsentry/sentry-javascript

Paquete + Versión

  • [] @sentry/browser
  • [x] @sentry/node
  • [] raven-js
  • [] raven-node _ (cuervo por nodo) _
  • [ ] otro:

Versión:

4.6.1

Descripción

Fuera de la caja, Node registrará los rechazos de promesas no controladas. Sin embargo, después de inicializar Sentry, estos registros desaparecerán. Esto sucede porque Node no registrará rechazos si existe un controlador

Me gustaría sugerir que Sentry agregue el registro a su controlador, para brindar paridad con la experiencia provista de fábrica. Como mínimo, los documentos deberían mencionar este comportamiento y la necesidad de agregar manualmente un controlador adicional para restaurar el registro.

Comentario más útil

Todavía me parece extraño que uncaughtException y unhandledRejection se manejen de manera diferente. Sentry restaura el registro de uncaughtException ¿Por qué no hace lo mismo con unhandledRejection ? Los usuarios no deberían tener que recordar usar ese indicador de nodo. 🤔

Todos 41 comentarios

Suena bien, sin embargo, no estoy seguro de si esto debería estar detrás de nuestra bandera debug: true .
Al final, está adjuntando conscientemente controladores de errores, que redirigen el flujo de errores al Sentry.

Yo tampoco estoy seguro.

Habilitar Sentry no tiene el efecto de deshabilitar el registro para excepciones no detectadas, por lo que tal vez lo mismo debería ser cierto para los rechazos de promesas no controladas. (Aunque esta diferencia de comportamiento es más una inconsistencia en Node que en Sentry).

Cuando habilito Sentry, entiendo que está informando mis errores, pero tiendo a pensar en el registro de la consola como algo separado, especialmente en dev. 🤔

No modificamos el comportamiento de registro predeterminado y, para las excepciones no detectadas, es el propio nodo el que activa una llamada de registro.

Creo que la mejor solución aquí sería simplemente anotarlo en los documentos y dejar

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

fragmento en caso de que alguien quiera volver a habilitar la advertencia.

Docs sería suficiente. Al menos entonces Sentry no está haciendo nada especial. Realmente es Node el problema aquí.

o excepciones no detectadas, es el propio nodo lo que desencadena una llamada de registro.

Pensándolo bien, no estoy seguro de que eso sea cierto.

Sentry registra un controlador uncaughtException que deshabilita el comportamiento predeterminado del nodo (registro + salida).

El controlador ( defaultOnFatalError ) activa su propia llamada de registro: https://github.com/getsentry/sentry-javascript/blob/4.6.3/packages/node/src/handlers.ts#L282.

Si estamos "restaurando" el registro para las excepciones no detectadas, creo que deberíamos hacer lo mismo para los rechazos de promesas no controladas.

¿Podemos volver a abrir esto? Según mi último comentario, ahora creo que Sentry debería restaurar el registro para los rechazos de promesas no controladas, como lo hace para las excepciones no detectadas.

Encontré este problema porque estaba comenzando a usar Sentry y me preguntaba si había cometido un error en mi código, ya que solo uncaughtException estaba en mi registro y no unhandledRejection . Tendría mucho sentido que estos dos casos se manejen de la misma manera.

Así que diría que registre ambos o no registre ninguno.

Encontré una mejor manera de manejar esto, que copiar el código del núcleo de Node.

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

También lo hizo obvio al incluirlo en la página principal de documentos https://github.com/getsentry/sentry-docs/pull/1099

Todavía me parece extraño que uncaughtException y unhandledRejection se manejen de manera diferente. Sentry restaura el registro de uncaughtException ¿Por qué no hace lo mismo con unhandledRejection ? Los usuarios no deberían tener que recordar usar ese indicador de nodo. 🤔

¿Por qué no hace lo mismo con el rechazo no controlado?

Porque uno es crítico ( unhandledException mata el proceso) y otro es informativo (por lo tanto, es una advertencia, no un error).

Si invertimos el orden y emitimos la advertencia de forma predeterminada, romperemos el comportamiento de CLI, emitiéndolas a pesar de que --unhandled-rejections esté configurado en none . En este momento, todo funciona como se esperaba de acuerdo con la documentación oficial del nodo. Este cambio _lo haría_ no estándar.

Una vez que Node decida hacer que unhandledRejection también elimine un proceso (que dicen ahora para 4 versiones: P), haremos el cambio para que también esté en línea con la especificación oficial.

Si invertimos el orden y emitimos la advertencia de forma predeterminada, romperemos el comportamiento de CLI

@kamilogorek , pero cuando se ejecuta con node registra unhandledRejection en console . Entonces no sé qué dice la documentación oficial del nodo, pero al menos ese es el comportamiento que noto.

@freeall solo si no adjunta unhandledRejection handler. Si ejecuta el código a continuación, incluso sin el SDK, aún no se registrará, por lo que debe saber qué código está ejecutando.

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

Y dejamos muy claro aquí que lo hacemos: https://docs.sentry.io/platforms/node/default-integrations/

Las integraciones del sistema son integraciones habilitadas por defecto que se combinan en la biblioteca estándar o en el propio intérprete. Están documentados para que pueda ver lo que hacen y que pueden desactivarse si causan problemas.
OnUnhandledRejection
Esta integración adjunta controladores de rechazo no controlados globales.

Simplemente no quiero cambiar el comportamiento del nodo, eso es todo. Y el comportamiento es: "si hay un oyente, no emitas. Si aún quieres la advertencia, usa la bandera". - y esto es exactamente lo que hacemos.

@kamilogorek Entiendo de dónde vienes. Pero creo que los usuarios de Sentry esperarían que Sentry no altere el comportamiento de su programa.

Si tengo un unhandledRejection sin Sentry, lo veo en mi consola.
Si tengo un unhandledRejection con Sentry, no lo veo en mi consola.

Personalmente, no me gusta que Sentry altere el comportamiento.

Pero así es como está diseñado Node.js ¯_ (ツ) _ / ¯
Si agrega un controlador, la advertencia desaparece. Nuestro SDK agrega un controlador, porque es la única forma de detectar errores no controlados, que es el objetivo principal del SDK.

Por supuesto, tiene razón sobre cómo está diseñado el nodo. Cuando adjunta un controlador, la advertencia desaparece.
Lo que la gente pregunta es que imite el comportamiento predeterminado del nodo y lo registre en la consola. Un comportamiento modificado no es lo que espera de una herramienta como Sentry

De todos modos, parece que está decidido a este comportamiento, por lo que no tiene sentido mantener la discusión. Pero gracias por tomarse el tiempo para responder :)

@freeall gracias también, siempre es bueno ver los dos lados :)

Solo para aclarar: al habilitar Sentry, el comportamiento de unhandledException (salida + registro) se conserva, pero el comportamiento de unhandledRejection (registro) no es:

| manipulador | registros | salidas |
| - | - | - |
| unhandledException predeterminado | sí | sí |
| unhandledException Centinela | sí | sí |
| unhandledRejection predeterminado | sí | no |
| unhandledRejection Centinela | no | no |

En este momento, todo funciona como se esperaba de acuerdo con la documentación oficial del nodo.

"Como se esperaba" aquí supone que el usuario comprende que Sentry está registrando un oyente por unhandledRejection . Ese es un detalle de implementación del que los usuarios no deberían tener que preocuparse.

Sin embargo, veo tu punto. Sentry también debería respetar --unhandled-rejections , lo que no haría si la bandera estuviera configurada en none y Sentry continuara registrando.

El comentario de

Creo que los usuarios de Sentry esperarían que Sentry no altere el comportamiento de su programa.

Los rechazos de promesas no detectados no son "errores de segunda clase". Pueden hacer y hacen que las aplicaciones se rompan al igual que lo hacen los errores normales.

Parece que varios usuarios se han encontrado con este problema (incluyéndome a mí), y más se encontrarán con él en el futuro.

Entonces, en resumen: Sentry silencia los errores de la consola. Y creo que es obvio lo confuso que es esto, y probablemente la mayoría de los usuarios centinelas no pretenden hacerlo. No instalan centinela para silenciar algunos subconjuntos de errores desde la consola.

Entonces el razonamiento (por @kamilogorek )

así es como está diseñado Node.js

Es un poco críptico para mí. ¿Cómo dicta esto la forma en que debe comportarse el centinela?

¿Deberíamos esperar que los usuarios sepan acerca de:

a) funcionamiento interno de los centinelas (registra los controladores de eventos)

b) funcionamiento interno del nodo (agregar controladores hace que las advertencias desaparezcan)

Y si no lo hacen, ¿deberían?

Por supuesto que tiene razón al decir "bueno, el usuario debería saber qué hace el código bajo el capó", pero la realidad se ve diferente. Y aquí tienes la oportunidad de aumentar la facilidad de uso de centinela, o no.

Está bien decir "no nos importa este tema en particular", pero pintarlo de una manera "no es un error, es una característica" parece poco sincero.

TLDR: IMOH Si desea aumentar la facilidad de uso y reducir los problemas para los usuarios novatos, esto debería solucionarse.

@OliverJAsh , @freeall
¿Qué soluciones usaste para este problema?

@schumannd He agregado un fragmento de cómo lo cargo. Y estoy de acuerdo con usted en que la respuesta "no es un error, es una característica" no parece satisfactoria. Me temo que muchos programadores no detectarán algunos errores en su programa porque Sentry se los come. Para mí, la primera prioridad de una herramienta como Sentry debería ser detectar errores y no crearlos.

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

Como estoy usando sentry en react native, parece que necesitaría hacer algunas cosas hacky para solucionar este problema. ¿Alguien está usando React Native y está resolviendo este problema de una manera diferente?

@OliverJAsh , @kamilogorek
¿Podemos reabrir y arreglar esto?

Sentry absolutamente no debería meterse con la forma en que se registran los errores en la consola, y esto no es solo un problema con Node, ya que el registro de la consola también está suprimido en el navegador.

Es muy molesto intentar depurar cosas, y como no te molestaste en mencionar esto en los documentos para JavaScript, en realidad pensé que no tenía errores cuando miré en la consola mientras probaba una compilación de prueba y, por lo tanto, no me di cuenta. tuvo errores, hasta después de que se implementó en producción. Esa es una experiencia de usuario realmente horrible para un servicio de informes de errores, y una que debe solucionar si desea clientes satisfechos.

Y como se dijo antes, los rechazos de promesas no son errores de segunda clase; pueden ser tan fatales como cualquier otro error no manejado y no deben suprimirse de ninguna manera.

Entonces, un poco de depuración revela la razón por la que se suprime el registro de la consola:

image

Sentry asigna una función a window.onunhandledrejection , y como vemos aquí, esa función devuelve false , suprimiendo explícitamente el registro de la consola. Así que sí, Sentry _es_ cambia el comportamiento predeterminado, eso no está bien.

Afortunadamente, almacena una referencia a cualquier función existente y la llama si existe.
Entonces, la solución hacky para volver a habilitar el registro de la consola es agregar esta línea, antes de inicializar Sentry:

window.onunhandledrejection = () => true;

Ahora, corrija esto, para que podamos tener el comportamiento predeterminado sin tales trucos inútiles 🙂

@schumannd , vuelva a abrir el problema

@ thomas-darling Estoy de acuerdo con el cambio de navegador, debería devolver true para las promesas y puedo cambiar eso.

Sin embargo, para el nodo, todavía no estoy convencido por una razón. Vincula el código a la implementación actual de Node. Si copiamos los componentes internos en lugar de confiar en las banderas, y el comportamiento de rechazo de la promesa cambiará en la v14, tendremos que detectar en qué versión del nodo estamos y actuar en consecuencia.
No importa lo que devolvamos del oyente, ya que internamente el nodo solo verifica la matriz de oyentes y emite una advertencia solo si no hay oyentes, y esta detección no se puede modificar: https://github.com/nodejs /node/blob/7cf6f9e964aa00772965391c23acda6d71972a9a/lib/internal/process/promises.js#L163 -L216

Suena bien, con respecto al cambio de navegador: +1:

En cuanto a Node, si no arregla el inicio de sesión en Sentry, básicamente solo obliga a todos sus usuarios a hacerlo ellos mismos, con el riesgo adicional de que algunos lo hagan mal y algunos ni siquiera se den cuenta de que lo necesitan, hasta después de que lo hagan. ser mordido por un error de producción, como yo. Esa no es una buena experiencia para desarrolladores ...

@ thomas-darling, ¿cómo te gustaría arreglarlo? ¿Reproduce el mismo código que está dentro del código del nodo?

En la parte superior de nuestros documentos hay una nota muy visible sobre qué hacer para obtener el registro predeterminado de la consola: https://docs.sentry.io/platforms/node/

image

Entiendo su punto: tener que replicar el comportamiento del nodo sería un posible problema de mantenimiento, y ayuda que esto pueda, para el nodo, resolverse con una simple marca de línea de comando.

Pero si no desea replicar el comportamiento del nodo, al menos registre una advertencia en la consola cuando no se especifique ese indicador, para que los usuarios sepan que los errores se están suprimiendo y cómo evitarlos.

Esto se vuelve aún más importante en la próxima versión de node, donde los rechazos no manejados, por defecto, bloquearán el proceso, lo que, según tengo entendido, no sucederá cuando Sentry agregue su controlador.
Los usuarios que confían en ese nuevo comportamiento predeterminado en el nodo, podrían tener una sorpresa desagradable si luego instalan Sentry y su proceso continúa repentinamente, a pesar de que se haya producido un error fatal.
Ese es el tipo de cosas que podrían provocar la pérdida de datos u otros desastres.

Como lo veo, hay algunas opciones:

  1. Replica la forma de hacerlo de Node.js
  2. Simplemente escriba a console.error cuando haya un rechazo no controlado
  3. Suprime el error para que el desarrollador nunca lo vea

Creo que la opción 1 o 2 parecen estar bien. Su cliente ve el error y puede solucionarlo.
Lo que absolutamente no debe hacer es la opción 3, donde su cliente no ve errores y Sentry hace que los errores entren en producción (oh, pero la ironía de una herramienta de informe de errores). ¡Este es el comportamiento actual y esto realmente debería detenerse! Sentry debería ayudarme a detectar errores, no empeorar las cosas.

Incluso si elige la opción 2, al menos los desarrolladores verán el rechazo y notarán que querían un comportamiento diferente (como un bloqueo) y pueden implementarlo. Pero sin saber siquiera que hubo un rechazo, no pueden hacer mucho al respecto.

Esto debería hacer el trabajo. https://github.com/getsentry/sentry-javascript/pull/2312
No agregué una forma de agregar su propia devolución de llamada, ya que escribir el código a continuación tendría exactamente el mismo efecto:

`` js
Sentry.init ({
integraciones: [
new Sentry.Integrations.OnUnhandledRejection ({
modo: 'ninguno'
})
]
});

process.on ('unhandledRejection', (motivo) => {
// tu devolución de llamada
})

para mí eso resulta en TypeError: undefined is not a constructor . Podría ser, porque ahora estoy usando el paquete @sentry/react-native . Por cierto, ¿ese paquete tiene el mismo problema?

@schumannd @sentry/react-native no usa @sentry/node , por lo que no tiene esta integración. Para eso, solo necesitará actualizar una versión una vez que lancemos sentry / browser y funcionará bien (ya que el cambio para devolver true de los controladores es predeterminado y no configurable).

@kamilogorek me queda bien 👍

¡Gracias por hacer esto! ¿Podrías hacer ping aquí una vez que se publique?

@OliverJAsh ping :)

Solo para verificar que entiendo correctamente: si uso la bandera --unhandled-rejections=strict Node, Node generará el rechazo no controlado como una excepción, y luego Sentry interceptará esa excepción y la informará. Eso es lo que creo que estoy viendo.

Pregunto porque cuando intenté habilitar --unhandled-rejections=strict , parecía que la integración OnUnhandledRejections no tuvo ningún efecto; nunca se llamó al detector de eventos.

¡Sería genial si pudiéramos agregar algunos documentos sobre esto!

Docs PR ya está en progreso https://github.com/getsentry/sentry-docs/pull/1351/

@OliverJAsh este cambio no tiene nada que ver con la bandera cli. Su comportamiento está intacto. Lo que cambió es que la integración OnUnhandledRejection tiene una nueva opción que le permite hacer que se comporte como la bandera cli.

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

es (conceptualmente) igual que --unhandled-rejection=none y lo mismo ocurre con warn y strict .
Cuando usa warn (que es el valor predeterminado ahora), registrará la advertencia y el error en sí, pero el proceso se mantendrá vivo.
Cuando use strict , registrará, capturará el evento, lo eliminará (esperará hasta que se entregue) y terminará el proceso con el código de salida 1.

Eso tiene sentido. Entiendo que la integración no cambia el comportamiento de la bandera de nodo. Sin embargo, ¿puedo comprobar si entiendo correctamente cómo se comporta Sentry (fuera de esta integración) con respecto a la bandera de nodo?

Solo para verificar que entiendo correctamente: si uso la marca --unhandled-rejections = estric de Node, Node generará el rechazo no controlado como una excepción, y luego Sentry interceptará esa excepción y la informará. Eso es lo que creo que estoy viendo.

@schumannd FYI, esta mañana lanzamos @sentry/react-native 1.10.0 [EDIT: whoops, should be 1.1.0 ], que actualiza su dependencia para usar la última versión de @sentry/browser (que incluye la devolución - true -en lugar de- false arreglo mencionado anteriormente).

@lobsterkatie, la última versión de @ sentry / react-native parece ser la 1.3.7. .

Entonces, intentar instalar 1.10.0 no funciona. ¿Cómo obtengo la solución?

@schumannd @lobsterkatie significaba 1.1.0 , ya que aquí es cuando actualizamos a 5.9.0 de @sentry/browser . La opción de controlador que establece el nivel de registro también debería funcionar bien en la versión reciente de @sentry/react-native .

¿Fue útil esta página
0 / 5 - 0 calificaciones