Il y a beaucoup de documents sur il ce qui suggère que l' impression de la trace de la pile d'une exception est une mauvaise pratique.
Par exemple, à partir de l'enregistrement RegexpSingleline dans Checkstyle:
Cette vérification peut être utilisée [...] pour trouver des mauvaises pratiques courantes telles que l'appel de ex.printStacktrace ()
Cependant, j'ai du mal à trouver n'importe où qui donne une raison valable, car la trace de la pile est sûrement très utile pour localiser la cause de l'exception. Choses dont je suis conscient:
Une trace de pile ne doit jamais être visible pour les utilisateurs finaux (pour l'expérience utilisateur et à des fins de sécurité)
La génération d'une trace de pile est un processus relativement coûteux (bien que peu susceptible de poser un problème dans la plupart des circonstances `` exceptionnelles '')
De nombreux frameworks de journalisation imprimeront la trace de la pile pour vous (le nôtre ne le fait pas et non, nous ne pouvons pas le changer facilement)
L'impression de la trace de pile ne constitue pas une gestion des erreurs. Il doit être combiné avec d'autres informations d'enregistrement et de gestion des exceptions.
Quelles sont les autres raisons pour éviter d'imprimer une trace de pile dans votre code?
la source
.printStackTrace()
dans votre code :)Réponses:
Throwable.printStackTrace()
écrit la trace de la pile dansSystem.err
PrintStream. LeSystem.err
flux et le flux de sortie standard "erreur" sous-jacent du processus JVM peuvent être redirigés parSystem.setErr()
qui modifie la destination pointée parSystem.err
./dev/null
.En déduisant de ce qui précède, l'invocation
Throwable.printStackTrace()
constitue un comportement de gestion des exceptions valide (pas bon / excellent), uniquementSystem.err
été réaffecté pendant toute la durée de vie de l'application,System.err
(et dans le flux de sortie d'erreur standard de la JVM).Dans la plupart des cas, les conditions ci-dessus ne sont pas satisfaites. Il se peut que l'on ne sache pas que d'autres codes s'exécutent dans la JVM, et que l'on ne peut pas prédire la taille du fichier journal ou la durée d'exécution du processus, et une pratique de journalisation bien conçue tournerait autour de l'écriture de fichiers journaux "analysables par machine" (un caractéristique préférable mais facultative dans un enregistreur) dans une destination connue, pour aider au soutien.
Enfin, il ne faut pas oublier que la sortie de
Throwable.printStackTrace()
serait certainement entrelacée avec un autre contenu écritSystem.err
(et peut-être mêmeSystem.out
si les deux sont redirigés vers le même fichier / périphérique). C'est un désagrément (pour les applications à un seul thread) qu'il faut gérer, car les données autour des exceptions ne sont pas facilement analysables dans un tel événement. Pire encore, il est fort probable qu'une application multithread produise des journaux très déroutants carThrowable.printStackTrace()
non thread-safe .Il n'existe pas de mécanisme de synchronisation pour synchroniser l'écriture de la trace de pile
System.err
lorsque plusieurs threads sont appelésThrowable.printStackTrace()
en même temps. Résoudre ce problème nécessite en fait que votre code se synchronise sur le moniteur associé àSystem.err
(et aussiSystem.out
, si le fichier / périphérique de destination est le même), et c'est un prix assez élevé à payer pour le bon fonctionnement du fichier journal. Pour prendre un exemple, les classesConsoleHandler
etStreamHandler
sont responsables de l'ajout des enregistrements de journal à la console, dans la fonction de journalisation fournie parjava.util.logging
; l'opération réelle de publication des enregistrements de journal est synchronisée - chaque thread qui tente de publier un enregistrement de journal doit également acquérir le verrou sur le moniteur associé auStreamHandler
exemple. Si vous souhaitez avoir la même garantie d'avoir des enregistrements de journal non entrelacés à l'aide deSystem.out
/System.err
, vous devez vous assurer de la même chose - les messages sont publiés sur ces flux de manière sérialisable.Compte tenu de tout ce qui précède et des scénarios très restreints dans lesquels
Throwable.printStackTrace()
est réellement utile, il s'avère souvent que l'invoquer est une mauvaise pratique.En étendant l'argument dans l'un des paragraphes précédents, c'est également un mauvais choix à utiliser
Throwable.printStackTrace
en conjonction avec un enregistreur qui écrit sur la console. Ceci est en partie dû à la raison pour laquelle l'enregistreur se synchroniserait sur un moniteur différent, tandis que votre application se synchroniserait (éventuellement, si vous ne voulez pas d'enregistrements de journal entrelacés) sur un moniteur différent. L'argument est également valable lorsque vous utilisez deux enregistreurs différents qui écrivent vers la même destination, dans votre application.la source
System.out.println
etThrowable.printStackTrace
et bien sûr, le jugement du développeur est nécessaire. J'étais un peu inquiet que la partie sur la sécurité des threads n'ait pas été omise. Si vous regardez la plupart des implémentations de logger, vous remarquerez qu'elles synchronisent la partie où les enregistrements de journal sont écrits (même sur la console), bien qu'elles n'acquièrent pas de moniteurs surSystem.err
ouSystem.out
.Vous abordez plusieurs problèmes ici:
Oui, il doit être accessible pour diagnostiquer les problèmes des utilisateurs finaux, mais l'utilisateur final ne doit pas les voir pour deux raisons:
La génération d'une trace de pile se produit lorsque l'exception est créée / levée (c'est pourquoi la levée d'une exception a un prix), l'impression n'est pas si chère. En fait, vous pouvez remplacer
Throwable#fillInStackTrace()
votre exception personnalisée en faisant de la levée une exception presque aussi bon marché qu'une simple instruction GOTO.Très bon point. Le principal problème ici est le suivant: si le framework enregistre l'exception pour vous, ne faites rien (mais assurez-vous que c'est le cas!) Si vous souhaitez enregistrer l'exception vous-même, utilisez un framework de journalisation comme Logback ou Log4J , pour ne pas les mettre sur la console brute car il est très difficile de le contrôler.
Avec le framework de journalisation, vous pouvez facilement rediriger les traces de pile vers un fichier, une console ou même les envoyer à une adresse e-mail spécifiée. Avec le code en dur,
printStackTrace()
vous devez vivre avec lesysout
.Encore une fois: connectez-vous
SQLException
correctement (avec la trace complète de la pile, en utilisant le cadre de journalisation) et affichez gentil: " Désolé, nous ne sommes actuellement pas en mesure de traiter votre demande ". Pensez-vous vraiment que l'utilisateur est intéressé par les raisons? Avez-vous vu l'écran d'erreur StackOverflow? C'est très humoristique, mais ne révèle aucun détail. Cependant, il garantit à l'utilisateur que le problème sera étudié.Mais il va vous appeler immédiatement et vous devez être en mesure de diagnostiquer le problème. Vous avez donc besoin des deux: une journalisation des exceptions appropriée et des messages conviviaux.
Pour conclure les choses: consignez toujours les exceptions (de préférence en utilisant le cadre de journalisation ), mais ne les exposez pas à l'utilisateur final. Réfléchissez bien et aux messages d'erreur dans votre GUI, affichez les traces de pile uniquement en mode développement.
la source
Premièrement, printStackTrace () n'est pas cher comme vous le dites, car la trace de la pile est remplie lorsque l'exception est créée elle-même.
L'idée est de transmettre tout ce qui va aux journaux via un framework de journalisation, de sorte que la journalisation puisse être contrôlée. Par conséquent, au lieu d'utiliser printStackTrace, utilisez simplement quelque chose comme
Logger.log(msg, exception);
la source
Imprimer la trace de pile de l'exception en soi ne constitue pas une mauvaise pratique, mais imprimer uniquement la trace de stace lorsqu'une exception se produit est probablement le problème ici - souvent, il ne suffit pas d'imprimer une trace de pile.
De plus, il y a une tendance à soupçonner qu'une gestion correcte des exceptions n'est pas effectuée si tout ce qui est effectué dans un
catch
bloc est un fichiere.printStackTrace
. Une mauvaise gestion peut signifier au mieux qu'un problème est ignoré, et au pire un programme qui continue de s'exécuter dans un état indéfini ou inattendu.Exemple
Prenons l'exemple suivant:
Ici, nous voulons effectuer un traitement d'initialisation avant de passer à un traitement qui nécessite que l'initialisation ait eu lieu.
Dans le code ci-dessus, l'exception aurait dû être interceptée et correctement gérée pour empêcher le programme de passer à la
continueProcessingAssumingThatTheStateIsCorrect
méthode que nous pourrions supposer causer des problèmes.Dans de nombreux cas,
e.printStackTrace()
cela indique qu'une exception est en train d'être avalée et que le traitement est autorisé à se dérouler comme si aucun problème ne s'était produit.Pourquoi est-ce devenu un problème?
L'une des principales raisons pour lesquelles une mauvaise gestion des exceptions est devenue plus répandue est probablement la façon dont les IDE tels qu'Eclipse généreront automatiquement du code qui effectuera une
e.printStackTrace
gestion des exceptions:(Ce qui précède est un réel
try-catch
auto-généré par Eclipse pour gérer unInterruptedException
lancé parThread.sleep
.)Pour la plupart des applications, il ne suffira probablement pas d'imprimer la trace de la pile en erreur standard. Une gestion incorrecte des exceptions peut, dans de nombreux cas, conduire une application à s'exécuter dans un état inattendu et entraîner un comportement inattendu et indéfini.
la source
Je pense que votre liste de raisons est assez complète.
Un exemple particulièrement mauvais que j'ai rencontré plus d'une fois est le suivant:
Le problème avec le code ci-dessus est que la gestion consiste entièrement en l'
printStackTrace
appel: l'exception n'est pas vraiment gérée correctement et n'est pas autorisée à s'échapper.D'un autre côté, en règle générale, je consigne toujours la trace de la pile chaque fois qu'il y a une exception inattendue dans mon code. Au fil des ans, cette politique m'a fait gagner beaucoup de temps lors du débogage.
Enfin, sur une note plus légère, la Perfect Exception de Dieu .
la source
printStackTrace()
imprime sur une console. Dans les paramètres de production, personne ne regarde jamais cela. Suraj est correct, devrait transmettre cette information à un enregistreur.la source
Dans les applications serveur, le stacktrace fait exploser votre fichier stdout / stderr. Il peut devenir de plus en plus volumineux et rempli de données inutiles car généralement vous n'avez pas de contexte ni d'horodatage, etc.
par exemple catalina.out lors de l'utilisation de tomcat comme conteneur
la source
Ce n'est pas une mauvaise pratique car quelque chose ne va pas à propos de PrintStackTrace (), mais parce que c'est une "odeur de code". La plupart du temps, l'appel PrintStackTrace () est là parce que quelqu'un n'a pas réussi à gérer correctement l'exception. Une fois que vous avez traité l'exception d'une manière appropriée, vous ne vous souciez généralement plus de StackTrace.
De plus, l'affichage du stacktrace sur stderr n'est généralement utile que lors du débogage, pas en production car très souvent stderr ne mène nulle part. La journalisation a plus de sens. Mais le simple remplacement de PrintStackTrace () par la journalisation de l'exception vous laisse toujours avec une application qui a échoué mais continue de fonctionner comme si de rien n'était.
la source
Comme certains gars l'ont déjà mentionné ici, le problème est à l'exception de la déglutition au cas où vous appelez simplement
e.printStackTrace()
lecatch
bloc. Cela n'arrêtera pas l'exécution du thread et continuera après le bloc try comme dans des conditions normales.Au lieu de cela, vous devez soit essayer de récupérer de l'exception (au cas où elle est récupérable), soit de lancer
RuntimeException
, soit de faire bulle l'exception à l'appelant afin d'éviter des plantages silencieux (par exemple, en raison d'une mauvaise configuration de l'enregistreur).la source
Pour éviter le problème de flux de sortie enchevêtré référencé par @Vineet Reynolds
vous pouvez l'imprimer sur la sortie standard:
e.printStackTrace(System.out);
la source