Logger.getLogger (MyClass.class) è il modo migliore per inizializzare i logger log4j?


13

Questo tutorial di Mkyong suggerisce di inizializzare i logger in questo modo:

@Controller
public class WelcomeController {

    private static final Logger logger = Logger.getLogger(WelcomeController.class);

   // etc

}

Ora presumibilmente ogni altra classe che usi, che ha un logger inizializzerà i loro logger allo stesso modo.

La mia domanda è: è questo il modo migliore per farlo? Sembra ... ripetitivo.


2
Cosa trovi dettagliato su questo (mettendo da parte la sintassi di Java)? Devi creare una variabile per contenere il logger e devi dire getLogger()il nome del logger da ottenere.
kdgregory,

2
@kdgregory il fatto che sto facendo la stessa cosa in ogni classe.
dwjohnston,

1
Dai un'occhiata a questa domanda su Stack Overflow
toniedzwiedz,

3
Troppo vecchio per migrare, ma questa domanda è fuori tema qui e più adatta per StackOverflow.
Andres F.

1
@AndresF. Penso di averlo messo qui perché è più una questione di stile di codice / modelli di progettazione, che un problema tecnico.
dwjohnston,

Risposte:


16

Il tuo commento afferma che "dettagliato" si riferisce alla necessità di ripetere questa riga di codice in ogni classe. La mia prima risposta è che, in generale, l'aggiunta di due righe di codice (definizione variabile più istruzione di importazione) a ogni classe non è un grosso problema. Soprattutto perché devi solo aggiungerli alle classi che hanno un comportamento e quindi devi fare il log. Detto questo, la specifica riga di codice che stai utilizzando è soggetta a errori di copia-incolla (ne parleremo più avanti).

Ma, dal momento che vuoi alternative, eccone alcune, con motivi per cui potresti o non vorrai usarle.

Utilizzare un logger singolo per l'intera app

Se non ti interessa quale classe sta segnalando, o sei disposto a inserire tutto il contesto necessario nel messaggio, allora un semplice logger singleton farà il lavoro:

LoggerSingleton.getInstance().debug("MyController is running")

A mio avviso, uno dei maggiori vantaggi di un framework di registrazione è avere il contesto fornito da istanze di logger separate - se non altro per indirizzare i messaggi di log verso destinazioni diverse. Non mi arrenderei solo per salvare una riga di codice (hai ancora bisogno dell'importazione).

Inoltre, questo aumenta la verbosità nel punto di utilizzo, che finirà con un numero molto maggiore di tasti.

Crea i tuoi logger nel punto di utilizzo

Lo sto buttando fuori solo perché elimina la variabile. Non credo di dover commentare. Anche se mostra la mia tecnica preferita per ottenere un'istanza del logger.

Logger.getLogger(getClass()).debug("blah blah blah");

Utilizzare un post-processore bean per iniettare il logger

Il tuo esempio usa Spring e Spring ti consente di agganciarti al codice di inizializzazione del bean. È possibile creare un post-processore che ispeziona il bean per una loggervariabile membro e crea Loggerun'istanza quando ne trova una.

Mentre un post-processore di questo tipo è solo poche decine di righe di codice, è un'altra parte mobile dell'applicazione e quindi un'altra potenziale fonte di bug. Preferisco averne il minor numero possibile.

Usa un mixin

Scala e Groovy forniscono tratti che consentono di incapsulare il comportamento. Un tipico modello Scala è quello di creare un Loggingtratto, quindi aggiungerlo alla classe che necessita di registrazione:

class MyController with Logging

Sfortunatamente, questo significa che devi cambiare lingua. A meno che non si stia utilizzando Java 8, nel qual caso è possibile creare Loggingun'interfaccia con un "metodo predefinito":

public interface Logging {
    default Logger getLogger() {
        return Logger.getLogger(getClass());
    } 
}

Ora, all'interno del tuo codice di classe, puoi semplicemente usare

getLogger().debug("blah blah blah");

Sebbene facile, questo ha un paio di svantaggi. Per prima cosa, inquina l'interfaccia di ogni classe che la utilizza, poiché tutti i metodi di interfaccia sono pubblici. Forse non è poi così male se lo usi solo per le classi che sono istanziate e iniettate da Spring, specialmente se segui la separazione interfaccia / implementazione.

Il problema più grande è che deve cercare l'istanza effettiva del logger ad ogni chiamata. Che è veloce, ma non necessario.

E hai ancora bisogno di una dichiarazione di importazione.

Sposta il logger in una superclasse

Lo ripeterò: non trovo le definizioni di logger ripetute dettagliate, ma se lo fai penso che sia l'approccio migliore per eliminarle.

public abstract class AbstractController {
    protected Logger logger = Logger.getLogger(getClass());
}

Ora le tue classi di controller ereditano AbstractControllere hanno accesso alla loggervariabile. Ricorda che devi mettere l' @Controllerannotazione sulla classe concreta.

Alcune persone troveranno questa perversione dell'eredità. Ho cercato di molestarli nominando la classe AbstractControllerpiuttosto che AbstractProjectClass. Puoi decidere tu stesso se esiste o meno una relazione is-a .

Altre persone si opporranno all'uso di una variabile di istanza piuttosto che di una variabile statica. I logger statici IMO sono inclini a errori di copia e incolla, poiché è necessario fare esplicito riferimento al nome della classe; getClass()assicura che il logger sia sempre corretto.


Penso che dovresti stare attento a getClass () nella classe di ereditarietà, MethodHandles.lookup (). LookupClass () è meglio dopo jdk 7
yuxh

@luxh - hai una spiegazione per questo?
kdgregory,


@yuxh - l'unica menzione di MethodHandles in quella domanda (che non era nella risposta che hai collegato), è un'affermazione simile non supportata con un commento che chiede chiarimenti. Hai un supporto autorevole per l'affermazione che MethodHandles.lookup().lookupClass()è meglio di Object.getClass()?
kdgregory,

MethodHandles.lookup().lookupClass()può essere utilizzato per variabili statiche, non è soggetto a errori di copia e incolla ed è veloce: stackoverflow.com/a/47112323/898747 Significa un ulteriore inport, ma mi piace che i miei logger siano statici, quindi vale almeno la pena menzione :)
FableBlaze,

0

Per estendere la risposta fornita da @kdgregory, Groovy fornisce @Slf4j( groovy.util.logging.Slf4j) out of the box come un'annotazione che esegue una trasformazione AST sulla classe per affrontarla con un logger che assume il nome della variabile logper impostazione predefinita se non specificato.

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.