Il logger deve essere statico privato o meno


103

Il logger dovrebbe essere dichiarato statico o no? Di solito ho visto due tipi di dichiarazione per un logger:

    Log log protetto = nuovo Log4JLogger (aClass.class);

o

    log log statico privato = nuovo Log4JLogger (aClass.class);

Quale dovrebbe essere usato? quali sono i pro e i contro di entrambi?


1
La registrazione è una preoccupazione trasversale. Usa Aspetti e la domanda è discutibile.
Dave Jarvis

4
staticè un riferimento per classe. non statico è un riferimento per istanza (+ inizializzazione). Quindi, in alcuni casi, quest'ultimo ha un impatto significativo sulla memoria se si hanno tonnellate di istanze. Non usare mai il non statico in un oggetto frequente . Uso sempre la versione statica. (che dovrebbe essere maiuscolo LOG )
Ha QUIT - Anony-Mousse

2
come già suggerito, usa AOP e annotazioni, ad esempio: jcabi.com/jcabi-aspects/annotation-loggable.html
yegor256

1
RobertHume la versione statica sta utilizzando una costante. Questo è esattamente il motivo per cui dovrebbe essere maiuscolo.
HA USCIATO - Anony-Mousse

2
No, dovrebbe essere private static final Log logminuscolo. Il logger non è una costante, il logger è un oggetto finale statico (che può essere mutato). Personalmente lo uso sempre logger.
osundblad

Risposte:


99

Il vantaggio della forma non statica è che puoi dichiararlo in una classe base (astratta) come segue senza preoccuparti che verrà utilizzato il nome della classe corretto:

protected Log log = new Log4JLogger(getClass());

Tuttavia il suo svantaggio è ovviamente che verrà creata un'istanza di logger completamente nuova per ogni istanza della classe. Questo potrebbe non essere di per sé costoso, ma aggiunge un overhead significativo. Se desideri evitarlo, preferisci utilizzare il staticmodulo. Ma il suo svantaggio è a sua volta che devi dichiararlo in ogni singola classe e fare attenzione in ogni classe che durante la costruzione del logger sia stato utilizzato il nome di classe corretto perché getClass()non può essere utilizzato in un contesto statico. Tuttavia, nell'IDE medio è possibile creare un modello di completamento automatico per questo. Ad esempio logger+ ctrl+space.

D'altra parte, se si ottiene il logger da una factory che a sua volta può memorizzare nella cache i logger già istanziati, l'uso del modulo non statico non aggiungerà molto overhead. Log4j, ad esempio, ha LogManagera questo scopo.

protected Log log = LogManager.getLogger(getClass());

6
Dichiarare abstract Log getLogger();nella classe astratta. Implementa questo metodo, restituendo il logger statico per l'istanza particolare. Aggiungi private final static Log LOG = LogManager.getLogger(Clazz.class);al tuo modello di classe IDE.
Ha QUIT - Anony-Mousse

2
Per slf4j:protected Logger log = LoggerFactory.getLogger(getClass());
Markus Pscheidt

3
@BalusC il problema con il passaggio di getClass () al metodo getLogger è che restituisce la classe dell'istanza corrente. Normalmente è più desiderabile che il logging sia associato alla classe in cui si trova il codice. Ad esempio, se il codice di registrazione è nella classe Parent, allora vogliamo che la registrazione sia associata a Parent anche se l'istanza in esecuzione è un'istanza della classe Child che è una sottoclasse di Parent. Con getClass () verrà associato al bambino, in modo errato
o il

@inor: "erroneamente"? Se non vuoi astrarre la classe, allora non dovresti usare il getClass () ereditato in primo luogo. Ci sono sviluppatori che lo trovano corretto e utile in quanto rivela informazioni in quale sottoclasse è stata eseguita esattamente la logica.
BalusC

2
@ BalusC getLogger (getClass ()) fa registrare sempre il nome della sottoclasse in modo non corretto. Le classi di registrazione dovrebbero sempre fare getLogger (Clazz.class) per associare le registrazioni fatte dal codice nella classe Clazz. Gli sviluppatori che vogliono sapere quale delle sottoclassi è in esecuzione (es. SubClazz estende Clazz) dovrebbero fare in SubClazz: getLogger (SubClazz.class) e qualcosa come: log.info ("calling <something in my base class>");
inor

44

Pensavo che tutti i logger dovessero essere statici; tuttavia, questo articolo su wiki.apache.org solleva alcuni importanti problemi di memoria, per quanto riguarda le perdite di classloader. Dichiarare un logger come statico impedisce che la classe dichiarante (e i classloader associati) vengano raccolti in modo indesiderato nei contenitori J2EE che utilizzano un classloader condiviso. Ciò comporterà errori di PermGen se ridistribuisci l'applicazione abbastanza volte.

Non vedo davvero alcun modo per aggirare questo problema di perdita di classloader, oltre a dichiarare i logger come non statici.


4
Sospettavo che anche il campo statico avrebbe avuto problemi di perdita di memoria. Non statico potrebbe avere problemi di prestazioni come altri hanno detto. Qual è il modo ideale allora?
Liang

@piepera il problema principale descritto nell'articolo a cui hai fatto riferimento è la capacità di controllare il livello di registrazione in ciascuna applicazione quando "considera il caso in cui una classe che utilizza" log statico privato = "viene distribuita tramite un ClassLoader che è in ascendenza di più presumibilmente "applicazioni" "indipendenti. Non lo vedo come un problema perché in questa particolare situazione le applicazioni hanno un "terreno comune" e in quel "terreno comune" viene deciso il livello di registrazione per la classe e sì, vale per tutte le applicazioni ... ma mantieni in mente che questa classe è [caricata] al di fuori di queste applicazioni
entro il

17

La differenza più importante è il modo in cui influisce sui file di registro: in quale categoria vanno i registri?

  • Nella tua prima scelta, i log di una sottoclasse finiscono nella categoria della superclasse. Mi sembra molto controintuitivo.
  • C'è una variante del tuo primo caso:

    registro registro protetto = nuovo Log4JLogger (getClass ());

    In tal caso, la categoria del registro indica su quale oggetto stava lavorando il codice che ha effettuato il login.

  • Nella seconda scelta (statico privato), la categoria di registro è la classe che contiene il codice di registrazione. Quindi normalmente la classe che sta facendo la cosa che viene registrata.

Consiglio vivamente questa ultima opzione. Presenta questi vantaggi, rispetto alle altre soluzioni:

  • Esiste una relazione diretta tra il registro e il codice. È facile ritrovare l'origine di un messaggio di registro.
  • Se qualcuno deve regolare i livelli di registrazione (che viene fatto per categoria), di solito è perché è interessato (o meno) ad alcuni messaggi particolari, scritti da una particolare classe. Se la categoria non è la classe che scrive i messaggi, è più difficile regolare i livelli.
  • Puoi accedere ai metodi statici
  • I logger devono essere inizializzati (o cercati) solo una volta per classe, quindi all'avvio, invece che per ogni istanza creata.

Ha anche degli svantaggi:

  • Deve essere dichiarato in ogni classe in cui si registrano i messaggi (nessun riutilizzo dei logger delle superclassi).
  • È necessario fare attenzione a inserire il nome classe corretto durante l'inizializzazione del logger. (Ma i buoni IDE se ne occupano per te).

4

Usa l'inversione del controllo e passa il logger al costruttore. Se crei il logger all'interno della classe avrai un diavolo di tempo con i tuoi unit test. Stai scrivendo unit test, vero?


5
I test unitari che esaminano la registrazione che stai producendo suonano sia inutili che incredibilmente fragili.
Michael

1
Utilità a seconda del sistema in prova. A volte la registrazione è tutto ciò a cui hai accesso.
Wayne Allen

@ Wayne Allen quando esegui gli unit test, per definizione, hai anche i risultati dei test. Stai suggerendo una situazione in cui si fa un test unitario ma non si ottengono risultati dei test? hanno solo i registri?
inor

la creazione del logger all'interno della classe non crea problemi. Puoi mostrare un semplice esempio difficile da utilizzare perché la classe crea il proprio logger?
inor

1
Sicuro. Che ne dici di un logger che invia e-mail. Non voglio farlo ogni volta che esegui i tuoi test. Inoltre come si afferma l'effetto collaterale?
Wayne Allen
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.