Klassenname für Logger unter Java automatisch ermitteln

Vor einiger Zeit schrieb ich einen Artikel darüber, wie der Klassenname für einen Logger ermittelt werden kann. Im Endergebnis sah die damalige Lösung, unter Nutzung der Simple Logging Facade for Java kurz SLF4J, wie folgt aus:

Logger log = LoggerFactory.getLogger(new Exception().fillInStackTrace().getStackTrace()[0].getClassName());

Damit wird der gesamte Stacktrace zusammengesammelt und entsprechend der Klassenname extrahiert. Das Problem an dieser Variante ist das der gesamte Stack dafür ausgewertet wird und für jede Nutzung eines Logs eine relativ unintuitive und lange Zeile von A nach B kopiert werden muss. Anders sieht es mit folgender Lösung aus:

package net.seeseekey.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Utility class to get logger
 */
public final class Logging {

    private Logging() {
    }

    public static Logger getLogger() {

        StackWalker.StackFrame frame = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
                .walk(stream -> stream.skip(1)
                        .findFirst()
                        .orElse(null));

        if (frame == null) {
            return LoggerFactory.getLogger("Common");
        }

        return LoggerFactory.getLogger(frame.getClassName());
    }
}

Bei dieser Utility-Klasse wird der entsprechende Klassenname dynamisch über einen StackWalker ermittelt. Zurückgegeben wird hierbei der Klassenname des Aufrufers. Konnte kein Klassenname ermittelt werden, so wird stattdessen ein Logger mit dem Namen Common zurückgegeben. Damit kann der eigentliche Logger nun wie folgt angelegt werden:

Logger log = Logging.getLogger();

Der StackWalker ist ab Java 9 verfügbar und kann somit in neueren Projekten problemlos genutzt werden. Im Gegensatz zu den bisherigen Methoden Teile des Stacktrace zu erhalten, ist der StackWalker aus Performancesicht zu bevorzugen. Definiert wurde diese API in der JEP 259.

Klassenname für Logger unter Java ermitteln

Wenn ein Logger unter Java erstellt wird, so wird diesem in den meisten Fällen ein Name übergeben, über den er später identifiziert und konfiguriert werden kann. Mit der Simple Logging Facade for Java kurz SLF4J würde das Ganze so aussehen:

Logger logger = LoggerFactory.getLogger("Testclass");

Die erste Möglichkeit wäre es nun den Namen der Klasse, über die Klasseninformationen mittels:

Logger logger = LoggerFactory.getLogger(Testclass.class.getName());

zu ermitteln. Alternativ kann diese Klasseninformation direkt in die Methode gegeben werden:

Logger logger = LoggerFactory.getLogger(Testclass.class);

Alle diese Methoden haben den Nachteil das die jeweilige Klasse in irgendeiner Form übergeben werden muss. Wenn nun dieser Logger in eine andere Klasse kopiert wird, um ihn dort ebenfalls zu nutzen, muss der Name der Klasse angepasst werden. Anders funktioniert das Ganze mit der folgenden Methode:

Logger logger = LoggerFactory.getLogger(new Exception().fillInStackTrace().getStackTrace()[0].getClassName());

Bei diesem Beispiel wird eine neue Exception instanziiert und aus dem Stacktrace dieser Exception der Name der Klasse ermittelt. Somit kann diese Zeile von Klasse zu Klasse kopiert werden, ohne das eine Anpassung notwendig wird.