Por que “log e jogar” é considerado um anti-padrão? [fechadas]


89

Esta questão foi gerada por uma discussão em torno deste artigo , onde não recebi nenhuma boa resposta.

Por que registrar sua exceção e, em seguida, lançá-la novamente (preservando o rastreamento de pilha original, é claro) seria uma má ideia se você não pode lidar com isso de outra forma?


Tente pesquisar uma resposta em softwareengineering.stackexchange.com
chharvey

Respostas:


129

Presumo que a resposta seja em grande parte porque você está pegando se não consegue lidar com isso? Por que não deixar quem pode lidar com isso (ou quem fica sem escolha a não ser lidar com isso) registrá-lo, se eles acham que é digno de log?

Se você capturá-lo, registrá-lo e lançá-lo novamente, não haverá como o código upstream saber que você já registrou a exceção e, portanto, a mesma exceção pode ser registrada duas vezes. Ou pior, se todo o código upstream seguir o mesmo padrão, a exceção pode ser registrada um número arbitrário de vezes, uma para cada nível no código que decide capturá-lo, registrá-lo e lançá-lo novamente.

Além disso, alguns podem argumentar que, como lançar e capturar exceções são operações relativamente caras, toda essa captura e relançamento não está ajudando no desempenho do tempo de execução. Nem está ajudando seu código em termos de concisão ou facilidade de manutenção.


para mais detalhes, veja os comentários sobre a resposta de Jeff
Manu

8
Um motivo para registrar e relançar uma exclusão seria restringir o motivo e registrar uma mensagem específica.
Mike Argyriou

12
Resposta: pode haver informações úteis de depuração disponíveis no ponto atual da pilha que não estarão disponíveis em outro ponto no rastreamento da pilha
rtconner

Capturar e relançar às vezes é útil se a nova exceção for mais útil com mais informações ou mais específica.
borjab

1
Para gastar com o que @rtconner comentou: em código assíncrono pode ser que o apanhador não tenha o contexto que está disponível para o lançador.
Nir Alfasi

55

Log-and-throw é um bom padrão se a entidade que captura e relança a exceção tem motivos para acreditar que ela contém informações que não serão registradas posteriormente na pilha de chamadas - pelo menos não da maneira mais desejada. Alguns motivos pelos quais isso pode ocorrer:

  1. A exceção pode ser capturada e relançada em um limite da camada de aplicativo e pode conter informações privilegiadas. Seria ruim para uma camada de banco de dados permitir uma exceção dizendo, por exemplo, "Tentativa de adicionar chave duplicada 'fnord' ao campo 'usuários'" para alcançar a camada de aplicativo externa (que por sua vez pode expô-la a um usuário), mas pode ser útil para partes internas do banco de dados para lançar tal exceção e a interface do aplicativo para capturá-la, registrá-la com segurança e relançar uma exceção um pouco menos descritiva.
  2. A exceção pode ser aquela que a camada externa provavelmente espera controlar sem o registro, mas a camada interna pode saber algo que a camada externa não sabe, o que sugere que o registro pode ser útil. Como um exemplo bruto, uma camada de aplicativo do meio pode ser programada para tentar se conectar a um servidor e, se isso não funcionar, tente outro. Inundar o log do aplicativo com mensagens de 'falha de conexão' enquanto um servidor está fora do ar para manutenção pode não ser útil, especialmente porque - da perspectiva do aplicativo, tudo funcionou bem. Pode ser útil encaminhar informações sobre a falha de conexão para um recurso de registro associado a servidores, que poderia filtrar os registros de modo a produzir um relatório de quando o servidor foi ativado e desativado, em oposição a um registro de cada tentativa de conexão .

4
# 1 é de fato um caso de uso geral sensato, entretanto o OP perguntou explicitamente sobre "relançar (preservando o rastreamento da pilha original, é claro)", então # 1 não é a resposta certa.
Geoffrey Zheng

@GeoffreyZheng: Isso dependeria de o registro seguro do rastreamento da pilha original contaria como "preservação".
supercat

3
Em relação ao nº 1: expor o conteúdo da exceção (como exibir e.getMessage()/ stacktrace na IU, bem como enviá-lo como resposta REST) ​​deve ser tratado como vulnerabilidade em si, pois a exceção de tempo de execução pode conter qualquer tipo de informação sensível. Em relação ao # 2: você pode relançar a exceção adicionando todas as informações que deseja que o cliente saiba (+ causa raiz), sem necessidade de registrar nada.
Nikita Bosik

@NikitaBosik: Se as exceções devem ou não ser expostas do lado do cliente, os aplicativos que o fazem são suficientemente comuns que o princípio de 'segurança em profundidade' sugere que as mensagens de exceção devem ser eliminadas de informações confidenciais. Além disso, se a camada externa não espera descartar um tipo específico de exceção sem registrá-la nem encaminhar informações para uma entidade externa que possa estar interessada, ter uma camada intermediária para adicionar informações que a camada externa irá ignorar não ajudará qualquer coisa.
supercat

20

Eu acho que o motivo mais simples é que você normalmente teria um único manipulador de nível superior fazendo isso para você, então não há necessidade de poluir o código com esse tratamento de exceção.

O argumento das preocupações transversais é basicamente que é uma perda de tempo lidar com erros que não dizem respeito a você. Muito melhor deixar o erro borbulhar na pilha de chamadas até que um manipulador apropriado seja encontrado.

Em minha opinião, a única vez em que você deve capturar uma exceção é quando pode fazer algo útil com os resultados. Pegar simplesmente para registrar não é útil, porque você poderia centralizar esse trabalho mais adiante.


2
Concordo que você deve ter um único manipulador de nível superior fazendo isso para você. Mas, em minha opinião, esse manipulador de nível superior DEVE ser "registrar e lançar" -ing. Portanto, o argumento gira em torno de EM QUE PONTO "registrar e lançar", não se quer ou não fazer isso?!?
Manu de

@Manu, acho que a questão é que, se for um único manipulador (centralizado), tudo bem. Se você está duplicando código, não está bem. Não acho que seja mais do que isso!
Jeff Foster

5
@Manu - O que o manipulador de nível superior está lançando nesse caso? Parece-me que se houver algo disponível para ele lançar, então não é realmente o manipulador de nível superior. E você definitivamente não quer relançar uma exceção para o próprio ambiente de tempo de execução. Isso fará com que a maioria dos aplicativos pare de funcionar.
aroth

1
@aroth: Entendo, o que você está dizendo é "registrar e manipular" (se você for o manipulador de nível superior) ou "não registrar e lançar (ou manipular de outra forma)" se não for. Obrigado por apontar isso.
Manu

9

O registro e lançamento da IMO é uma violação clara do Princípio da Menor Surpresa.

Se a exceção for tratada adequadamente mais acima na pilha de chamadas, pode não valer a pena uma entrada de log de erros. E então é confuso encontrar uma entrada de log de erro.


E os logs de não erros?
Su Zhang

6
@SuZhang Não entendi muito bem sua pergunta. Se não houver erro, não há nada para jogar. Claro que você pode e deve escrever logs de não erros.
Bastian Voigt
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.