Hay una gran cantidad de material de salir hay que sugiere que la impresión de la traza de la pila de una excepción es una mala práctica.
Por ejemplo, de la verificación RegexpSingleline en Checkstyle:
Esta verificación se puede utilizar [...] para encontrar malas prácticas comunes, como llamar a ex.printStacktrace ()
Sin embargo, estoy luchando por encontrar cualquier lugar que proporcione una razón válida por la cual, seguramente, el seguimiento de la pila es muy útil para rastrear qué causó la excepción. Cosas de las que soy consciente:
Un seguimiento de la pila nunca debe ser visible para los usuarios finales (para la experiencia del usuario y con fines de seguridad)
Generar un seguimiento de la pila es un proceso relativamente costoso (aunque es poco probable que sea un problema en la mayoría de las circunstancias 'excepcionales')
Muchos marcos de registro imprimirán el seguimiento de la pila por usted (el nuestro no y no, no podemos cambiarlo fácilmente)
Imprimir el seguimiento de la pila no constituye un manejo de errores. Debe combinarse con otro registro de información y manejo de excepciones.
¿Qué otras razones hay para evitar imprimir una traza de pila en su código?
fuente
.printStackTrace()
en tu código :)Respuestas:
Throwable.printStackTrace()
escribe el seguimiento de la pila enSystem.err
PrintStream. LaSystem.err
secuencia y la secuencia de salida de "error" estándar subyacente del proceso JVM pueden ser redirigidas porSystem.setErr()
que cambia el destino señalado porSystem.err
./dev/null
.Inferir de lo anterior, invocar
Throwable.printStackTrace()
constituye un comportamiento de manejo de excepciones válido (no bueno / excelente), soloSystem.err
sido reasignado durante toda la vida útil de la aplicación,System.err
(y el flujo de salida de error estándar de la JVM).En la mayoría de los casos, las condiciones anteriores no se cumplen. Es posible que no se tenga conocimiento de otro código que se ejecuta en la JVM, y no se puede predecir el tamaño del archivo de registro o la duración del tiempo de ejecución del proceso, y una práctica de registro bien diseñada girará en torno a la escritura de archivos de registro "procesables por máquina" (un característica preferible pero opcional en un registrador) en un destino conocido, para ayudar en el soporte.
Finalmente, uno debería recordar que la salida de
Throwable.printStackTrace()
definitivamente se intercalaría con otro contenido escritoSystem.err
(y posiblemente inclusoSystem.out
si ambos se redirigen al mismo archivo / dispositivo). Esta es una molestia (para aplicaciones de subproceso único) con la que uno debe lidiar, ya que los datos en torno a las excepciones no se pueden analizar fácilmente en tal caso. Peor aún, es muy probable que una aplicación multiproceso produzca registros muy confusos yaThrowable.printStackTrace()
que no es segura para subprocesos .No existe un mecanismo de sincronización para sincronizar la escritura del seguimiento de la pila
System.err
cuando se invocan varios subprocesosThrowable.printStackTrace()
al mismo tiempo. Resolver esto realmente requiere que su código se sincronice en el monitor asociado conSystem.err
(y tambiénSystem.out
, si el archivo / dispositivo de destino es el mismo), y ese es un precio bastante alto a pagar por la sanidad del archivo de registro. Para tomar un ejemplo, las clasesConsoleHandler
yStreamHandler
son responsables de agregar registros de registro a la consola, en la instalación de registro proporcionada porjava.util.logging
; la operación real de publicación de registros de registro está sincronizada: cada subproceso que intente publicar un registro de registro también debe adquirir el bloqueo en el monitor asociado con elStreamHandler
ejemplo. Si desea tener la misma garantía de tener registros de registros no intercalados utilizandoSystem.out
/System.err
, debe asegurarse de lo mismo: los mensajes se publican en estas transmisiones de manera serializable.Teniendo en cuenta todo lo anterior, y los escenarios muy restringidos en los que
Throwable.printStackTrace()
es realmente útil, a menudo resulta que invocarlo es una mala práctica.Extendiendo el argumento en uno de los párrafos anteriores, también es una mala elección usar
Throwable.printStackTrace
junto con un registrador que escribe en la consola. Esto se debe en parte a que el registrador se sincronizaría en un monitor diferente, mientras que su aplicación (posiblemente, si no desea registros de registros intercalados) se sincronizaría en un monitor diferente. El argumento también es válido cuando utiliza dos registradores diferentes que escriben en el mismo destino, en su aplicación.fuente
System.out.println
eThrowable.printStackTrace
y, por supuesto, se requiere un juicio desarrollador. Estaba un poco preocupado de que se perdiera la parte sobre la seguridad del hilo. Si observa la mayoría de las implementaciones de registradores, notará que sincronizan la parte donde se escriben los registros de registro (incluso en la consola), aunque no adquieren monitores enSystem.err
oSystem.out
.Estás tocando múltiples problemas aquí:
Sí, debería ser accesible para diagnosticar problemas de los usuarios finales, pero el usuario final no debería verlos por dos razones:
La generación de un seguimiento de pila ocurre cuando se crea / lanza la excepción (es por eso que lanzar una excepción tiene un precio), la impresión no es tan costosa. De hecho, puede anular
Throwable#fillInStackTrace()
su excepción personalizada haciendo que lanzar una excepción sea casi tan barato como una simple declaración GOTO.Muy buen punto. El problema principal aquí es: si el marco registra la excepción por usted, no haga nada (¡pero asegúrese de que lo haga!) Si desea registrar la excepción usted mismo, use el marco de registro como Logback o Log4J , para no ponerlos en la consola sin procesar porque es muy difícil controlarlo.
Con el marco de registro, puede redirigir fácilmente los rastros de la pila a un archivo, consola o incluso enviarlos a una dirección de correo electrónico específica. Con hardcoded
printStackTrace()
tienes que vivir con elsysout
.Nuevamente: inicie sesión
SQLException
correctamente (con el seguimiento completo de la pila, utilizando el marco de registro) y muestre un mensaje agradable: " Lo sentimos, actualmente no podemos procesar su solicitud ". ¿Realmente crees que el usuario está interesado en los motivos? ¿Has visto la pantalla de error StackOverflow? Es muy gracioso, pero no revela ningún detalle. Sin embargo, asegura al usuario que el problema será investigado.Pero él lo llamará de inmediato y usted debe poder diagnosticar el problema. Por lo tanto, necesita ambos: registro de excepciones adecuado y mensajes fáciles de usar.
Para concluir: siempre registre excepciones (preferiblemente utilizando el marco de registro ), pero no las exponga al usuario final. Piense detenidamente y sobre los mensajes de error en su GUI, muestre los rastros de la pila solo en modo de desarrollo.
fuente
Lo primero que printStackTrace () no es costoso como dice , porque el seguimiento de la pila se llena cuando se crea la excepción.
La idea es pasar cualquier cosa que vaya a los registros a través de un marco de registro, de modo que el registro se pueda controlar. Por lo tanto, en lugar de usar printStackTrace, simplemente use algo como
Logger.log(msg, exception);
fuente
Imprimir el seguimiento de la pila de la excepción en sí mismo no constituye una mala práctica, pero solo imprimir el seguimiento de la ubicación cuando ocurre una excepción es probablemente el problema aquí; a menudo, simplemente imprimir un seguimiento de la pila no es suficiente.
Además, hay una tendencia a sospechar que no se está realizando un manejo de excepciones adecuado si todo lo que se realiza en un
catch
bloque es ae.printStackTrace
. Un manejo incorrecto podría significar que, en el mejor de los casos, se ignora un problema y, en el peor, un programa que continúa ejecutándose en un estado indefinido o inesperado.Ejemplo
Consideremos el siguiente ejemplo:
Aquí, queremos hacer un procesamiento de inicialización antes de continuar con algún procesamiento que requiera que la inicialización haya tenido lugar.
En el código anterior, la excepción debería haberse detectado y manejado adecuadamente para evitar que el programa continúe con el
continueProcessingAssumingThatTheStateIsCorrect
método que podríamos suponer que causaría problemas.En muchos casos,
e.printStackTrace()
es una indicación de que se está tragando alguna excepción y se permite que el procesamiento continúe como si no ocurriera ningún problema.¿Por qué esto se ha convertido en un problema?
Probablemente, una de las principales razones por las que el manejo de excepciones deficiente se ha vuelto más frecuente se debe a cómo IDE como Eclipse generará automáticamente el código que realizará un
e.printStackTrace
para el manejo de excepciones:(Lo anterior es un
try-catch
autogenerado real por Eclipse para manejar unInterruptedException
lanzamientoThread.sleep
).Para la mayoría de las aplicaciones, simplemente imprimir el seguimiento de la pila al error estándar probablemente no sea suficiente. El manejo inadecuado de excepciones podría en muchos casos llevar a que una aplicación se ejecute en un estado inesperado y podría conducir a un comportamiento inesperado e indefinido.
fuente
Creo que su lista de razones es bastante completa.
Un ejemplo particularmente malo que he encontrado más de una vez es el siguiente:
El problema con el código anterior es que el manejo consiste completamente en la
printStackTrace
llamada: la excepción realmente no se maneja correctamente ni se le permite escapar.Por otro lado, como regla, siempre registro el seguimiento de la pila cada vez que hay una excepción inesperada en mi código. Con los años, esta política me ha ahorrado mucho tiempo de depuración.
Finalmente, en una nota más ligera, la Excepción Perfecta de Dios .
fuente
printStackTrace()
imprime en una consola. En entornos de producción, nadie está mirando eso. Suraj es correcto, debe pasar esta información a un registrador.fuente
En aplicaciones de servidor, el stacktrace explota su archivo stdout / stderr. Puede hacerse cada vez más grande y está lleno de datos inútiles porque generalmente no tiene contexto ni marca de tiempo, etc.
p. ej. catalina.out cuando se usa tomcat como contenedor
fuente
No es una mala práctica porque hay algo "incorrecto" en PrintStackTrace (), sino porque es "olor a código". La mayoría de las veces la llamada PrintStackTrace () está ahí porque alguien no pudo manejar adecuadamente la excepción. Una vez que maneja la excepción de manera adecuada, generalmente ya no le importa StackTrace.
Además, mostrar el stacktrace en stderr generalmente solo es útil cuando se depura, no en producción porque muy a menudo stderr no va a ninguna parte. Iniciar sesión tiene más sentido. Pero solo reemplazando PrintStackTrace () con el registro, la excepción aún te deja con una aplicación que falló pero sigue funcionando como si nada hubiera pasado.
fuente
Como algunos tipos ya mencionaron aquí, el problema es con la excepción de tragarse en caso de que simplemente llame
e.printStackTrace()
alcatch
bloque. No detendrá la ejecución del hilo y continuará después del bloque try como en condiciones normales.En lugar de eso, debe intentar recuperarse de la excepción (en caso de que sea recuperable), o lanzar
RuntimeException
, o hacer burbujear la excepción a la persona que llama para evitar bloqueos silenciosos (por ejemplo, debido a una configuración incorrecta del registrador).fuente
Para evitar el problema de flujo de salida enredado referido por @Vineet Reynolds
puedes imprimirlo en el stdout:
e.printStackTrace(System.out);
fuente