Acesso eficiente a HttpServletRequest para impressões de depuração
-
14-09-2020 - |
Pergunta
Para depurar solicitações com falha, gostaria de imprimir todas as informações provenientes de HttpServletRequest.
Agora, é possível que uma solicitação falhe parcialmente (por ex.Várias correspondências foram bem-sucedidas, mas uma falhou) e nesse caso eu gostaria de capturar a exceção no método interno que falhou, imprimir o erro + ServletUtil.toStringHttpServletRequest() e continuar fornecendo serviço (degradado, mas ainda útil vs.falha completa da solicitação).
Nossa implementação atual captura a exceção e imprime informações idiotas ("getRules failed") ou lança a exceção até doGet() (cancelando efetivamente o serviço para o usuário) onde, como em doGet(), tenho acesso a HttpServletRequest onde posso imprima as informações de depuração relevantes (cabeçalhos, parâmetros...).
Passar HttpServletRequest para todas as funções chamadas durante a solicitação que podem falhar parece um pouco feio. Farei isso se nenhuma outra solução elegante aparecer.
Fazer um before head ServletUtil.toStringHttpServletRequest() e armazená-lo em um mapa ThreadLocal seria um desperdício tanto de memória quanto de tempo de CPU.Por alguma razão, parece errado armazenar o objeto HttpServletRequest em ThreadLocal (corrija se eu estiver errado).
As informações de depuração são gravadas no log da máquina local e enviadas por e-mail diretamente aos desenvolvedores (ótimo trabalho log4j TLSSMTPAppender), então fazer login em vários lugares não será prático (será necessário montar vários e-mails para entender o que está acontecendo) e fazer ssh no servidor é velhice :) (estamos todos nublados aqui...o servidor pode não existir no momento em que eu ver o erro)
Então, minha solução é obter acesso a um "PrintErrorUtility" (TODO:melhor nomeá-lo).Isso receberá (String errorMsg, Throwable t, HttpServletRequest) que imprimirá o erro junto com todas as informações relevantes ...Isso será chamado a partir de blocos try {} catch internos que notificarão sobre o erro, mas não cancelarão a solicitação por causa disso.
Obviamente estou falando de servidores em execução em produção.
Comentários?Por favor, avise.
Obrigado, Máximo.
Solução
Faça esta tarefa em um Filter
depois o FilterChain#doFilter()
chamar.O ServletRequest
objeto já está lá.No código de negócios onde esta exceção deve ser suprimida normalmente, armazene a exceção como um atributo de solicitação e deixe o Filter
verifique/capte-o da solicitação.
Atualizar:conforme os comentários, aqui está um exemplo:
public class Context {
private static ThreadLocal<Context> instance = new ThreadLocal<Context>();
private HttpServletRequest request;
private List<Exception> exceptions = new ArrayList<Exception>();
private Context(HttpServletRequest request) {
this.request = request;
this.request.setAttribute("exceptions", exceptions);
}
public static Context getCurrentInstance() {
return instance.get();
}
public static Context newInstance(HttpServletRequest request) {
Context context = new Context(request);
instance.set(context);
return context;
}
public void release() {
instance.remove();
}
public void addException(Exception exception) {
exceptions.add(exception);
}
}
E aqui está como usá-lo em seu servlet controlador:
Context context = Context.newInstance(request);
try {
executeBusinessCode();
} finally {
context.release();
}
E aqui está como você pode usá-lo no código comercial executado:
} catch (Exception e) {
Context.getCurrentInstance().addException(e);
}