2011-12-09 11 views
24

Aiutami in una discussione qui .. :)Anche con slf4j, dovresti proteggere il tuo logging?

Il sito slf4j qui http://www.slf4j.org/faq.html#logging_performance indica che a causa della registrazione parametrizzata, le protezioni di registrazione non sono necessarie. Cioè invece di scrivere:

if(logger.isDebugEnabled()) { 
    logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); 
} 

si può ottenere via con:

Object entry = new SomeObject(); 
logger.debug("The entry is {}.", entry); 

è davvero questo va bene, o lo fa incorrere nella (seppur inferiore) costi di creazione della stringa statica che è passato al metodo trace ..?

risposta

33

cercherò di mettere le mie due centesimi da un'altra prospettiva

Che cosa è esattamente il vantaggio di registrazione parametrizzata?

Basta rinviare toString() invocazione e concatenazione di stringhe fino realmente necessario, che è quando si ha realmente bisogno di registrare il messaggio. Questo ottimizza le prestazioni quando quella particolare operazione di registrazione è disabilitata. Controllare source code for SLF4J se non si è sicuri.

La registrazione parametrizzata rende le protezioni inutili in tutti i casi?

No.

In quali casi sarebbero guardie di registrazione essere utile?

Quando ci sono altre potenziali operazioni costose.

Per esempio (nel caso questa particolare operazione di registrazione è disabilitata), se abbiamo nessuna guardia registrazione

logger.debug("User: {}", getUserService().getCurrentUser()); 
  1. Ci sarebbe pagare il costo da obj = getUserService().getCurrentUser()
  2. risparmieremmo il costo da "User name: " + obj.toString()

Se uso guardia registrazione:

if (logger.isDebugEnabled()) { 
    logger.debug("User: {}", getUserService().getCurrentUser()); 
} 
  1. Vorremmo pagare il costo di logger.isDebugEnabled()
  2. Ci sarebbe salvare il costo da obj = getUserService().getCurrentUser()
  3. ci permetterebbe di risparmiare il costo da "User name: " + obj.toString()

Nella successiva c ase, salveremmo entrambi i costi al prezzo di controllare lo isDebugEnabled() due volte quando questa particolare operazione di registrazione è abilitata.

NOTA: questo è solo un esempio, non tentare di discutere le buone/cattive pratiche qui.

+0

Grazie fgelz, questa è la spiegazione più chiara, quindi ho cambiato idea e la risposta. Ti fa pensare che nonostante tutti i diversi quadri, ci sia ancora spazio per l'innovazione nel mondo del disboscamento, in termini di rinvio di operazioni costose .. forse con i delegati –

+0

@MarkD JDK 8 Progetto Lambda aiuterà l'innovazione (http: // openjdk .java.net/projects/lambda /) – fglez

+0

Dovresti anche essere consapevole del fatto che chiamare un metodo varargs (come logger.debug (String, Object ..) sta effettivamente facendo sotto le copertine logger.debug (String, new Object [. ..]). Quindi se non si effettua il wrap delle chiamate, si sta creando (quindi eliminando) un nuovo array Oggetto ogni volta che si attraversa questo metodo, anche se non si scrive mai il contenuto. Se si dispone di un sistema altamente performante o sperimentare la pressione della memoria, quindi questo può accumularsi nel tempo e la chiamata a logger.isDebugEnabled() sarà in-line da una JIT decente se usata molto. SLF4J lo specializza per uno e due argomenti, ma per di più si otterrà zangola – AlBlue

2

Si prega di non utilizzare l'istruzione if, perché ogni volta che guardo il codice come questo

if (logger.isDebug()) { 
    logger.debug("Of course it's debug {}", sadFace); 
} 

piango.

Spero che il costo di creazione della stringa statica sia così basso da risultare insignificante per il 99% degli utenti.

+1

slf4j non usa il costrutto '{0}'. –

+0

Se si utilizza molta registrazione di debug, tuttavia, come fanno le applicazioni più grandi, può essere un sovraccarico. Stai creando più immondizia per il garbage collector da raccogliere, e alcuni sistemi hanno già abbastanza pressione in quell'area così com'è. Se non fai nessuna chiamata per ottenere il tuo param, e usi sempre una stringa costante per la stringa param, va bene, fino a quando qualcuno arriva e lo cambia per fare qualcosa di leggermente meno banale. È più semplice da una prospettiva di "standard di codifica" richiedere semplicemente la dichiarazione if. – Dogs

15

Scrivere e leggere tutti quelli if(logger.isDebugEnabled()) {} probabilmente costerà il tempo che ti risparmiano.

Ovviamente, chiamare il metodo di registrazione non è gratuito, ma lo stesso vale per la chiamata isDebugEnabled(). Quindi stai pagando di più per ogni istruzione di registro che è attiva se usi questo modello (perché il framework di registrazione controllerà il livello due volte).

Inoltre ingombra il codice.

In pratica, non ho trovato la penalità di prestazioni abbastanza grande da disturbare.

Se la registrazione è troppo lenta per te, scrivi un appender non bloccante che spinge gli eventi del registro in una coda senza pochi controlli e usa un thread in background per elaborarli.

Sfondo: gli appendici standard sono tutti sincronizzati in modo che l'accesso a un'applicazione multi-thread possa causare molte piccole pause in cui tutti i thread attendono che un messaggio di log venga scritto su un file.

+0

grazie anche a quello che penso anch'io. Aspetterò di vedere quale sia il conscensus generale prima di darti un vantaggio :) Mi piace la mancia degli appendici che potrebbe essere un problema per noi. –

+0

Sia "chiamare il metodo di registrazione" sia "chiamare isDebugEnabled()" possono ** essere effettivamente gratuiti ** con alcune ottimizzazioni JIT che penso. Non ne sono sicuro, ma se fosse la persona che fornisce un'implementazione effettiva ad alte prestazioni per sl4jf, posizionerei un'implementazione con il metodo no-op in rutime per i livelli disabilitati, in modo che JIT possa rimuovere la chiamata. –

4

Il problema con una dichiarazione di registrazione come questa:

logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); 

è che si farà un sacco di lavoro per concatenare i valori in un String, che viene poi mai utilizzata se la registrazione di debug è spento. In tal caso, è utile verificare se la registrazione di debug è attiva prima di eseguire questa linea. Quando sei solo di passaggio parametri:

logger.debug("The entry is {}.", entry); 

allora non inutilmente bisogno di costruire un String che non viene mai utilizzato, e il controllo non è necessario; solo passare argomenti a un metodo non ha un sovraccarico molto alto.

Si noti che se si dispone di espressioni relativamente costose per gli argomenti in un'istruzione di registrazione, potrebbe comunque essere utile controllare prima il livello di registrazione.

+0

È possibile gestire espressioni costose inserendole nel metodo toString() in una classe anonima in modo che non vengano valutate fino a quando non sono effettivamente necessarie. –

+0

@ ThorbjørnRavnAndersen Sì, ma questo renderebbe il codice abbastanza dettagliato. – Jesper

5

La protezione non viene utilizzata a causa della creazione della stringa.

Al contrario, viene in genere utilizzato per evitare un'espressione di argomento potenzialmente costosa, ad esempio entry[i].retrieveExtendedDebugInformation().formatNicely(). Per questo, il logback si assicura che l'argomento venga valutato solo quando il messaggio di log viene effettivamente stampato, mentre log4j valuta sempre l'argomento prima di chiamare debug().

Qui l'unico candidato è String.valueOf(entry[i]), che non è molto costoso, quindi è possibile fare una discussione che questa guardia è inutile del tutto.

+1

okay - questo ha senso ed è un'altra visione delle cose. Quindi secondo te è un giudizio su se fare la guardia, e la guardia dovrebbe essere usata solo su operazioni (costose) relativamente rare? .. l'introduzione di parametri che riducono la quantità di quelle operazioni .. –

+0

Sì, e in base a quanto è costoso il l'operazione di protezione spesso ha senso solo per tracciare le istruzioni all'interno dei loop. Si potrebbe anche obiettare che se le tue istruzioni di debug sono così costose da rallentare la classe anche quando si è su un livello log più alto, allora non si sta usando log.debug, in particolare, si sta probabilmente facendo 'while (condizione) {log.debug (complicatedExpression); doSomething();} 'mentre si dovrebbe fare' log.debug (complexExpression); while (condizione) {log.trace (simpleExpression); doSomething();} '. Ma io non sono zelota, ammetto che invece sto scrivendo una guardia. – wallenborn

+0

"Non molto costoso" è ancora abbastanza costoso da fare la differenza per un programma con molte dichiarazioni di registro. –

Problemi correlati