Há um monte de material de fora há o que sugere que a impressão do rastreamento de pilha de uma exceção é uma prática ruim.
Por exemplo, da verificação RegexpSingleline no Checkstyle:
Essa verificação pode ser usada para [...] encontrar más práticas comuns, como chamar ex.printStacktrace ()
No entanto, estou lutando para encontrar um lugar que dê uma razão válida porque, certamente, o rastreamento de pilha é muito útil para rastrear o que causou a exceção. Coisas que eu conheço:
Um rastreamento de pilha nunca deve estar visível para os usuários finais (para fins de experiência e segurança do usuário)
Gerar um rastreamento de pilha é um processo relativamente caro (embora seja improvável que seja um problema na maioria das circunstâncias "excepcionais")
Muitas estruturas de log imprimirão o rastreamento de pilha para você (o nosso não e não, não podemos alterá-lo facilmente)
Imprimir o rastreamento da pilha não constitui tratamento de erros. Deve ser combinado com outro registro de informações e tratamento de exceções.
Quais outros motivos existem para evitar a impressão de um rastreamento de pilha no seu código?
fonte
.printStackTrace()
em seu código :)Respostas:
Throwable.printStackTrace()
grava o rastreamento de pilha noSystem.err
PrintStream. OSystem.err
fluxo e o fluxo de saída "erro" padrão subjacente do processo da JVM podem ser redirecionados porSystem.setErr()
que altera o destino apontado porSystem.err
./dev/null
.Inferindo-se ao exposto, invocar
Throwable.printStackTrace()
constitui um comportamento válido (não bom / ótimo) de manipulação de exceção, apenasSystem.err
sido reatribuído ao longo da vida útil do aplicativo,System.err
(e o fluxo de saída de erro padrão da JVM).Na maioria dos casos, as condições acima não são satisfeitas. Pode-se não estar ciente de outro código em execução na JVM e não se pode prever o tamanho do arquivo de log ou a duração do processo em tempo de execução, e uma prática de log bem projetada giraria em torno da gravação de arquivos de log "analisáveis por máquina" (um recurso preferível mas opcional em um registrador) em um destino conhecido, para ajudar no suporte.
Finalmente, deve-se lembrar que a saída de
Throwable.printStackTrace()
seria definitivamente intercalada com outro conteúdo gravadoSystem.err
(e possivelmente mesmoSystem.out
se ambos forem redirecionados para o mesmo arquivo / dispositivo). É um aborrecimento (para aplicativos de thread único) com o qual é preciso lidar, pois os dados em torno das exceções não são facilmente analisáveis em um evento como esse. Pior, é altamente provável que um aplicativo multithread produza logs muito confusos, poisThrowable.printStackTrace()
não é seguro para threads .Não há mecanismo de sincronização para sincronizar a gravação do rastreamento de pilha
System.err
quando vários encadeamentos são invocadosThrowable.printStackTrace()
ao mesmo tempo. Para resolver isso, na verdade, é necessário sincronizar o código no monitor associadoSystem.err
(e tambémSystem.out
, se o arquivo / dispositivo de destino for o mesmo), e esse é um preço bastante alto a pagar pela integridade do arquivo de log. Para dar um exemplo, as classesConsoleHandler
eStreamHandler
são responsáveis por anexar registros de log ao console, no recurso de registro fornecido porjava.util.logging
; a operação real de publicação dos registros de log é sincronizada - todo encadeamento que tenta publicar um registro de log também deve adquirir o bloqueio no monitor associado aoStreamHandler
instância. Se você deseja ter a mesma garantia de ter registros de log não intercalados usandoSystem.out
/System.err
, deverá garantir o mesmo - as mensagens são publicadas nesses fluxos de maneira serializável.Considerando todos os itens acima, e os cenários muito restritos nos quais
Throwable.printStackTrace()
é realmente útil, muitas vezes acontece que invocá-lo é uma má prática.Estendendo o argumento de um dos parágrafos anteriores, também é uma má escolha usar
Throwable.printStackTrace
em conjunto com um criador de logs que grava no console. Isso ocorre em parte devido ao motivo pelo qual o criador de logs sincronizaria em um monitor diferente, enquanto o aplicativo (possivelmente, se você não quiser registros de log intercalados) sincronizaria em um monitor diferente. O argumento também é válido quando você usa dois registradores diferentes que gravam no mesmo destino, em seu aplicativo.fonte
System.out.println
eThrowable.printStackTrace
, é claro, é necessário o julgamento do desenvolvedor. Fiquei um pouco preocupado com a falta de parte da segurança do thread. Se você observar a maioria das implementações do criador de logs, notará que elas sincronizam a parte em que os registros de log são gravados (até no console), embora não adquiram monitores noSystem.err
ouSystem.out
.Você está abordando vários problemas aqui:
Sim, ele deve estar acessível para diagnosticar problemas dos usuários finais, mas o usuário final não deve vê-los por dois motivos:
Gerar um rastreamento de pilha acontece quando a exceção está sendo criada / lançada (é por isso que lançar uma exceção tem um preço), a impressão não é tão cara. Na verdade, você pode substituir
Throwable#fillInStackTrace()
sua exceção personalizada efetivamente, tornando a exceção quase tão barata quanto uma simples instrução GOTO.Muito bom ponto. A questão principal aqui é: se o quadro registra a exceção para você, não fazer nada (mas certifique-se que ele faz!) Se você quiser registrar a exceção mesmo, estrutura de log uso como Logback ou Log4J , não para colocá-los no console cru porque é muito difícil controlá-lo.
Com a estrutura de log, você pode redirecionar facilmente os rastreamentos de pilha para arquivo, console ou até enviá-los para um endereço de email especificado. Com codificado
printStackTrace()
você tem que viver com osysout
.Novamente: efetue log
SQLException
corretamente (com o rastreamento de pilha completo, usando a estrutura de log) e mostre nice: " Desculpe, no momento não podemos processar sua solicitação ". Você realmente acha que o usuário está interessado nos motivos? Você viu a tela de erro do StackOverflow? É muito bem-humorado, mas não revela quaisquer pormenores. No entanto, garante ao usuário que o problema será investigado.Mas ele ligará para você imediatamente e você precisará diagnosticar o problema. Portanto, você precisa de ambos: log de exceção adequado e mensagens amigáveis.
Para finalizar: sempre registre exceções (de preferência usando a estrutura de log ), mas não as exponha ao usuário final. Pense com cuidado e nas mensagens de erro em sua GUI, mostre rastreamentos de pilha apenas no modo de desenvolvimento.
fonte
A primeira coisa que printStackTrace () não é cara como você afirma, porque o rastreamento de pilha é preenchido quando a exceção é criada.
A idéia é passar tudo o que for enviado aos logs por meio de uma estrutura de logger, para que o log possa ser controlado. Portanto, em vez de usar o printStackTrace, basta usar algo como
Logger.log(msg, exception);
fonte
A impressão do rastreamento de pilha da exceção por si só não constitui uma prática recomendada, mas apenas a impressão do rastreamento stace quando ocorre uma exceção é provavelmente o problema aqui - muitas vezes, apenas imprimir um rastreamento de pilha não é suficiente.
Além disso, há uma tendência a suspeitar que o tratamento adequado de exceções não está sendo executado se tudo o que está sendo executado em um
catch
bloco é ae.printStackTrace
. O manuseio inadequado pode significar, na melhor das hipóteses, que um problema está sendo ignorado e, na pior, um programa que continua executando em um estado indefinido ou inesperado.Exemplo
Vamos considerar o seguinte exemplo:
Aqui, queremos fazer algum processamento de inicialização antes de continuar com algum processamento que requer que a inicialização tenha ocorrido.
No código acima, a exceção deveria ter sido capturada e tratada adequadamente para impedir que o programa prossiga para o
continueProcessingAssumingThatTheStateIsCorrect
método que poderíamos assumir que causaria problemas.Em muitos casos,
e.printStackTrace()
é uma indicação de que alguma exceção está sendo engolida e o processamento é permitido continuar como se nenhum problema ocorresse.Por que isso se tornou um problema?
Provavelmente, uma das maiores razões pelas quais o tratamento inadequado de exceções se tornou mais prevalente se deve à maneira como IDEs, como o Eclipse, geram automaticamente código que executará um
e.printStackTrace
para o tratamento de exceções:(O exemplo acima é um real
try-catch
gerado automaticamente pelo Eclipse para lidar com umInterruptedException
lançamentoThread.sleep
.)Para a maioria dos aplicativos, apenas imprimir o rastreamento da pilha com erro padrão provavelmente não será suficiente. O tratamento inadequado de exceções pode, em muitos casos, levar a um aplicativo sendo executado em um estado inesperado e levar a um comportamento inesperado e indefinido.
fonte
Penso que a sua lista de razões é bastante abrangente.
Um exemplo particularmente ruim que encontrei mais de uma vez é o seguinte:
O problema com o código acima é que o tratamento consiste inteiramente na
printStackTrace
chamada: a exceção não é realmente tratada adequadamente nem é permitida a fuga.Por outro lado, como regra, eu sempre registro o rastreamento de pilha sempre que há uma exceção inesperada no meu código. Ao longo dos anos, essa política me salvou muito tempo de depuração.
Finalmente, em uma nota mais clara, a Exceção Perfeita de Deus .
fonte
printStackTrace()
imprime em um console. Nas configurações de produção, ninguém está assistindo a isso. Suraj está correto, deve passar essas informações para um criador de logs.fonte
Em aplicativos de servidor, o stacktrace explode seu arquivo stdout / stderr. Ele pode se tornar cada vez maior e é preenchido com dados inúteis, porque geralmente você não tem contexto nem carimbo de data e hora e assim por diante.
por exemplo catalina.out ao usar o tomcat como contêiner
fonte
Não é uma prática ruim porque algo está 'errado' em PrintStackTrace (), mas porque é 'cheiro de código'. Na maioria das vezes, a chamada PrintStackTrace () ocorre porque alguém falha ao manipular corretamente a exceção. Depois que você lida com a exceção de maneira adequada, geralmente não se importa mais com o StackTrace.
Além disso, exibir o rastreamento de pilha no stderr geralmente é útil apenas na depuração, não na produção, porque muitas vezes o stderr não leva a lugar algum. Registrá-lo faz mais sentido. Mas apenas substituir PrintStackTrace () pelo log da exceção ainda deixa você com um aplicativo que falhou, mas continua sendo executado como se nada tivesse acontecido.
fonte
Como alguns caras já mencionaram aqui, o problema é com a exceção de deglutição, caso você apenas ligue
e.printStackTrace()
nocatch
bloco. Não interromperá a execução do encadeamento e continuará após o bloco try, como em condições normais.Em vez disso, você precisa tentar se recuperar da exceção (no caso de ser recuperável), ou lançar
RuntimeException
ou enviar a exceção para o chamador para evitar falhas silenciosas (por exemplo, devido à configuração incorreta do criador de logs).fonte
Para evitar o problema do fluxo de saída emaranhado referido por @Vineet Reynolds
você pode imprimi-lo no stdout:
e.printStackTrace(System.out);
fonte