Domanda

Come molti utenti di log4j, spesso abbiamo una registrazione a livello di debug che è costosa da valutare. Quindi proteggiamo quei casi con un codice come:

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

Tuttavia, è più brutto di una semplice chiamata a _logger.debug e talvolta il programmatore non si rende conto che la valutazione potrebbe essere costosa.

Sembra che dovrebbe essere abbastanza semplice scrivere un programma che prende un jar compilato e protegge tutte le chiamate _logger.debug con il controllo isDebugEnabled. Saremmo probabilmente disposti ad accettare l'ulteriore sovraccarico di controllare isDebugEnabled in tutti i casi.

Qualcuno ha provato questo approccio o ha eseguito una post-elaborazione simile di un vaso?

È stato utile?

Soluzione

Hai guardato AspectJ ? Ciò supporta aspetti che utilizzano la tessitura bytecode e può intercettare in un file .jar precedentemente compilato .

Altri suggerimenti

Invece di cercare di modificare il vaso, cerco una soluzione usando Strumentazione bytecode . Il problema sarà identificare quelle parti del codice che vuoi racchiudere in un .isDebugEnabled () - dovrai identificare gli oggetti che sono usati solo per le invocazioni log4j.

Credo che una buona soluzione sarebbe che il codice sarebbe efficiente come è .

Considera che log4j è obsoleto. L'autore stesso lo ha lasciato così com'è, per evitare di rompere la compatibilità, ma ne ha creato uno nuovo, SLF4J ( http: // www .slf4j.org / ). Fornisce sia una facciata che un'implementazione, secondo la distinzione commons-logging / log4j, ma senza i difetti di ogni ...

Credo che, in questa nuova funzione di registrazione, sia possibile inviare i parametri Object alla registrazione e che il livello venga valutato prima di convertire gli oggetti (in String o in altro modo). L'idea è di utilizzare una stringa di formato e parametri.


Il nostro codice non utilizza slf4j, ma abbiamo metodi di utilità che fanno esattamente questo. È codificato approssimativamente come segue (dalla memoria):

    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
         }
       }
    }

È usato come:

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

AGGIORNAMENTO : se è necessario chiamare un metodo nel registro ...

  • Una possibilità è usare il metodo toString . Questo è appropriato se la tua registrazione è "tecnica" e verrà utilizzata anche durante il debug.

  • Se la tua registrazione è più funzionale (non mirata allo sviluppatore), ti suggerisco di definire un'interfaccia (è funzionalmente sana in quel caso, quindi è utile fornire un significato) :

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

    Implementa quell'interfaccia in qualsiasi oggetto che deve essere passato come oggetto di registrazione, con un calcolo complesso per costruire il registro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top