Pergunta

Como muitos usuários log4j, muitas vezes temos registro de nível de depuração que é caro para avaliar. Então, nós proteger esses casos com um código como:

if( _logger.isDebugEnabled )
  _logger.debug("Interesting, my foojes are goofed up: " + getFullDetails())

No entanto, isto é mais feio do que uma chamada _logger.debug simples, e às vezes o programador não percebe a avaliação poderia ser caro.

Parece que ele deve ser bastante simples para escrever um programa que leva um frasco compilado e guardas todas as chamadas _logger.debug com a verificação isDebugEnabled. Nós provavelmente seria dispostos a aceitar a sobrecarga extra de verificar isDebugEnabled em todos os casos.

Alguém já experimentou esta abordagem, ou pós-processamento semelhante feito de um frasco?

Foi útil?

Solução

Você olhou para AspectJ ? Isto suporta aspectos utilizando bytecode tecelagem, e pode interceptações em um arquivo .jar compilada anteriormente .

Outras dicas

Ao invés de olhar para modificar o pote, eu procurar uma solução usando Bytecode Instrumentação . O problema será identificar as partes do código que você deseja quebrar dentro de um .isDebugEnabled() -. Você terá que identificar objetos que são usados ??apenas para chamadas log4j

Eu acredito que uma boa solução seria a de que o código seria eficiente quanto é .

Considere que log4j é obsoleto. Seu autor em si deixou-o como é, para evitar quebrar a compatibilidade, mas ele criou um novo, SLF4J ( http: // www .slf4j.org / ). Ele fornece uma fachada e uma implementação, de acordo com a distinção commons-logging / log4j, mas sem as falhas de cada um ...

Eu acredito que, neste novo recurso de log, você pode enviar parâmetros de objeto para a extração de madeira, e que o nível é avaliado antes de converter os objetos (como String ou não). A idéia é usar uma seqüência de formato, e os parâmetros.


O nosso código não usa slf4j, mas temos métodos utilitários que fazem exatamente isso. Ele é codificado aproximadamente como segue (de memória):

    public enum LogLevel {
       FATAL, ERROR, WARNING, INFO, DEBUG;

       public void log(Logger logger, String format, Object... parameters) {
         if (isEnabled(logger)) {
            logImpl(logger, String.format(format, parameters));
         }
       }
       public boolean isEnabled(Logger logger) {
         switch(this) {
           case WARNING : return logger.isWarningEnabled();
           case INFO : return logger.isInfoEnabled();
           case DEBUG : return logger.isDebugEnabled();
           default: return true;
         }
       }
       private void logImpl(Logger logger, String message) {
         switch(this) {
           case WARNING : logger.warn(message);
           // other cases
         }
       }
    }

É usado como:

     public void myMethod(Object param) {
       LogLevel.WARNING.log(LOGGER, "What is my message ....", "myMethod", param);
     }

Atualizar : Se você precisar chamar um método no log ...

  • Uma possibilidade é usar o método toString. Isto é apropriado se o seu registro for 'técnico' , e será usado também durante a depuração.

  • Se o seu logging é mais funcional (não voltado para o developper), eu sugiro para definir uma interface (que é funcionalmente soar nesse caso, por isso é útil para fornecer significado) :

    public interface Detailable { // the name could also suggest logging?
      String getFullDetails();
    }
    

    Implementar essa interface em qualquer objeto que precisam ser passados ??como objeto de registro, com um cálculo complexo para construir o log.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top