Festlegen der Protokollstufe der Nachricht zur Laufzeit in slf4j

100

Bei Verwendung von log4j ist die Logger.log(Priority p, Object message)Methode verfügbar und kann zum Protokollieren einer Nachricht auf einer zur Laufzeit festgelegten Protokollebene verwendet werden. Wir nutzen diese Tatsache und diesen Tipp , um stderr zu einem Logger auf einer bestimmten Log-Ebene umzuleiten.

slf4j hat keine generische log()Methode, die ich finden kann. Bedeutet das, dass es keine Möglichkeit gibt, das oben Genannte umzusetzen?

Edward Dale
quelle
4
Es sieht so aus, als gäbe es einige Diskussionen darüber, dies zu slf4j 2.0 auf der Entwickler-
Edward Dale
1
Schauen Sie sich Marker an. Dies sind benutzerdefinierte Daten, die Sie an die Protokollkette übergeben können.
TuxSlayer
1
@tuxSlayer Kannst du bitte erläutern, wie Marker in diesem Fall verwendet wird?
Elende Variable
Wahrscheinlich ist es nicht die beste Idee für "Protokollierung", aber Sie können mehrere Markierungen für die "Priorität" des Protokolleintrags verwenden (hoch | niedrig | normal, info | warn | fatal) und die Filterung in Logback oder benutzerdefiniertem Appender verwenden, um Markierungen zu verwenden und Protokolleinträge zu steuern in separate Kanäle (Protokollinformationen, E-Mail tödlich usw.). Der geradlinigere Weg ist jedoch, eine Fassade dafür zu haben, wie in den folgenden Antworten gezeigt wurde.
TuxSlayer
2
Diese Funktion soll Teil von sein slf4j 2.0. jira.qos.ch/browse/SLF4J-124 Siehe meine Antwort für Details und eine mögliche slf4j 1.xProblemumgehung.
Slartidan

Antworten:

47

Es gibt keine Möglichkeit, dies zu tun slf4j.

Ich stelle mir vor, dass der Grund dafür, dass diese Funktionalität fehlt, darin besteht, dass es nahezu unmöglich ist, einen LevelTyp zu slf4jerstellen, der effizient dem Level(oder einem gleichwertigen) Typ zugeordnet werden kann, der in allen möglichen Protokollierungsimplementierungen hinter der Fassade verwendet wird. Alternativ haben die Designer entschieden, dass Ihr Anwendungsfall zu ungewöhnlich ist , um den Aufwand für die Unterstützung zu rechtfertigen.

Über Bezug auf den Anwendungsfall von @ ripper234 ( Komponententests ) denke ich, dass die pragmatische Lösung darin besteht, die Komponententests so zu ändern , dass sie genau wissen, welches Protokollierungssystem sich hinter der slf4j-Fassade befindet ... wenn die Komponententests ausgeführt werden.

Stephen C.
quelle
9
Es ist wirklich keine Zuordnung erforderlich. Es gibt fünf Ebenen, die von den Methoden in bereits implizit definiert wurden org.slf4j.Logger: Debug, Fehler, Info, Trace, Warnung.
Edward Dale
1
Und die Probleme wurden als ungültig geschlossen. Soweit ich das verstehe, ist es eine bewusste Designentscheidung.
Ripper234
9
@ ripper234 - Ich glaube nicht, dass Ihr Fehler das gleiche Problem wie die ursprüngliche Frage von scompt.com behoben hat. Sie haben nach der Konfiguration der Ebene des zugrunde liegenden Protokollierungssystems über die SLF4J-API gefragt. Was scompt.com suchte, war eine generische 'log'-Methode in der SLF4J-API, die die Protokollierungsstufe der Nachricht als Parameter verwendet.
Richard Fearn
1
+1 @RichardFearn Und man kann den Kommentar nach 60 Sekunden nicht rückgängig machen, meh . Feature - Request existiert mittlerweile: bugzilla.slf4j.org/show_bug.cgi?id=133
Januar
3
Die RFE-Links werden nicht mehr aufgelöst. Die relevanten Links sind jetzt: jira.qos.ch/browse/SLF4J-124 und jira.qos.ch/browse/SLF4J-197 ... und beide wurden geschlossen. Lesen Sie die Kommentare zur Begründung.
Stephen C
27

Richard Fearn hat die richtige Idee, also habe ich die ganze Klasse basierend auf seinem Skelettcode geschrieben. Es ist hoffentlich kurz genug, um hier zu posten. Kopieren und einfügen zum Genießen. Ich sollte wahrscheinlich auch eine magische Beschwörung hinzufügen: "Dieser Code ist gemeinfrei"

import org.slf4j.Logger;

public class LogLevel {

    /**
     * Allowed levels, as an enum. Import using "import [package].LogLevel.Level"
     * Every logging implementation has something like this except SLF4J.
     */

    public static enum Level {
        TRACE, DEBUG, INFO, WARN, ERROR
    }

    /**
     * This class cannot be instantiated, why would you want to?
     */

    private LogLevel() {
        // Unreachable
    }

    /**
     * Log at the specified level. If the "logger" is null, nothing is logged.
     * If the "level" is null, nothing is logged. If the "txt" is null,
     * behaviour depends on the SLF4J implementation.
     */

    public static void log(Logger logger, Level level, String txt) {
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                logger.trace(txt);
                break;
            case DEBUG:
                logger.debug(txt);
                break;
            case INFO:
                logger.info(txt);
                break;
            case WARN:
                logger.warn(txt);
                break;
            case ERROR:
                logger.error(txt);
                break;
            }
        }
    }

    /**
     * Log at the specified level. If the "logger" is null, nothing is logged.
     * If the "level" is null, nothing is logged. If the "format" or the "argArray"
     * are null, behaviour depends on the SLF4J-backing implementation.
     */

    public static void log(Logger logger, Level level, String format, Object[] argArray) {
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                logger.trace(format, argArray);
                break;
            case DEBUG:
                logger.debug(format, argArray);
                break;
            case INFO:
                logger.info(format, argArray);
                break;
            case WARN:
                logger.warn(format, argArray);
                break;
            case ERROR:
                logger.error(format, argArray);
                break;
            }
        }
    }

    /**
     * Log at the specified level, with a Throwable on top. If the "logger" is null,
     * nothing is logged. If the "level" is null, nothing is logged. If the "format" or
     * the "argArray" or the "throwable" are null, behaviour depends on the SLF4J-backing
     * implementation.
     */

    public static void log(Logger logger, Level level, String txt, Throwable throwable) {
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                logger.trace(txt, throwable);
                break;
            case DEBUG:
                logger.debug(txt, throwable);
                break;
            case INFO:
                logger.info(txt, throwable);
                break;
            case WARN:
                logger.warn(txt, throwable);
                break;
            case ERROR:
                logger.error(txt, throwable);
                break;
            }
        }
    }

    /**
     * Check whether a SLF4J logger is enabled for a certain loglevel. 
     * If the "logger" or the "level" is null, false is returned.
     */

    public static boolean isEnabledFor(Logger logger, Level level) {
        boolean res = false;
        if (logger != null && level != null) {
            switch (level) {
            case TRACE:
                res = logger.isTraceEnabled();
                break;
            case DEBUG:
                res = logger.isDebugEnabled();
                break;
            case INFO:
                res = logger.isInfoEnabled();
                break;
            case WARN:
                res = logger.isWarnEnabled();
                break;
            case ERROR:
                res = logger.isErrorEnabled();
                break;
            }
        }
        return res;
    }
}
David Tonhofer
quelle
Dies wäre mit einem variadic (Object ...) args-Parameter einfacher zu verwenden.
Anonymoose
"org.slf4j.Logger" verfügt über einige Signaturen für Protokollierungsmethoden, die in der oben genannten Klasse nicht behandelt werden. Daher
David Tonhofer
1
Ich denke, dass diese Implementierung eine unerwünschte Änderung hinzufügen wird. Wenn Sie den Aufruf logger.info (...) verwenden, hat der Logger Zugriff auf die Aufruferklasse und -methode und kann automatisch zum Protokolleintrag hinzugefügt werden. Bei dieser Implementierung erstellt das Anrufprotokoll (Logger, Level, TXT) einen Protokolleintrag, der immer denselben Aufrufer hat: Loglevel.log. Habe ich recht?
Domin
@Domin Hallo, du meinst, der Logger könnte den aktuellen Aufrufstapel untersuchen und dann den letzten Eintrag für die automatische Protokollierung extrahieren, was hier nicht der Fall ist? Im Prinzip ja, aber tatsächlich wird der Stapel auch danach noch ein bisschen größer, bis die eigentliche Nachricht ausgeschrieben ist (insbesondere muss irgendwann ein Logback aufgerufen werden, dann der eigentliche Appender). Ich denke, es sollte die Rolle des Appenders sein, nicht interessante Stapelzeilen wegzuwerfen, damit Sie sie anpassen können, um alles bis einschließlich des Aufrufs dieser Loglevel-Klasse wegzuwerfen.
David Tonhofer
@ David, ja, du hast recht :-). Ich bin nicht sicher, ob es eine Aufgabe für den Appender ist, da Sie in diesem Fall eine harte Abhängigkeit zwischen dem Appender und dem Logger definieren ... aber ... es ist eine Lösung. Vielen Dank David
Domin
14

Versuchen Sie, zu Logback zu wechseln, und verwenden Sie

ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(Level.toLevel("info"));

Ich glaube, dies ist der einzige Aufruf von Logback und der Rest Ihres Codes bleibt unverändert. Logback verwendet SLF4J und die Migration ist problemlos, nur die XML-Konfigurationsdateien müssen geändert werden.

Denken Sie daran, die Protokollstufe zurückzusetzen, nachdem Sie fertig sind.

Αλέκος
quelle
Ich habe bereits slf4j mit Logback-Unterstützung verwendet, sodass ich meine Komponententests sofort bereinigen konnte. Vielen Dank!
Lambart
2
Dies war meine erste -1, danke. Ich glaube du liegst falsch. Logback verwendet SLF4J, daher ist die Antwort relevant.
Αλέκος
3
@AlexandrosGelbessis Sie sollten die Frage erneut lesen. Es wurde nach einer Methode gefragt, mit der eine Protokollnachricht auf jeder Ebene programmgesteuert protokolliert werden kann. Sie ändern die Ebene des Root-Loggers für alle Nachrichten, nicht nur für eine.
Januar
12

Sie können dies mit Java 8 Lambdas implementieren.

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;

public class LevelLogger {
    private static final Logger LOGGER = LoggerFactory.getLogger(LevelLogger.class);
    private static final Map<Level, LoggingFunction> map;

    static {
        map = new HashMap<>();
        map.put(Level.TRACE, (o) -> LOGGER.trace(o));
        map.put(Level.DEBUG, (o) -> LOGGER.debug(o));
        map.put(Level.INFO, (o) -> LOGGER.info(o));
        map.put(Level.WARN, (o) -> LOGGER.warn(o));
        map.put(Level.ERROR, (o) -> LOGGER.error(o));
    }

    public static void log(Level level, String s) {
        map.get(level).log(s);
    }

    @FunctionalInterface
    private interface LoggingFunction {
        public void log(String arg);
    }
}
Paul Croarkin
quelle
Nun ja ... aber jetzt müssen Sie Ihre Codebasis ändern, um diese API sowie oder anstelle von slf4j zu verwenden. Wenn Sie es anstelle von slf4j verwenden, 1) muss es wahrscheinlich umfangreicher sein, 2) viele (mindestens) Importe müssen geändert werden, und 3) diese neue Ebene vor slf4j fügt einen zusätzlichen Protokollierungsaufwand hinzu.
Stephen C
4
Beachten Sie auch, dass bei dieser Lösung die Klasse, die die eigentliche Protokollierung durchführt, nicht protokolliert wird (da der Logger mit initialisiert ist LevelLogger). Dies ist keine gute Sache, da es sich im Allgemeinen um sehr nützliche Informationen handelt.
Siebenschläfer
6

Dies kann mit einer enumund einer Hilfsmethode erfolgen:

enum LogLevel {
    TRACE,
    DEBUG,
    INFO,
    WARN,
    ERROR,
}

public static void log(Logger logger, LogLevel level, String format, Object[] argArray) {
    switch (level) {
        case TRACE:
            logger.trace(format, argArray);
            break;
        case DEBUG:
            logger.debug(format, argArray);
            break;
        case INFO:
            logger.info(format, argArray);
            break;
        case WARN:
            logger.warn(format, argArray);
            break;
        case ERROR:
            logger.error(format, argArray);
            break;
    }
}

// example usage:
private static final Logger logger = ...
final LogLevel level = ...
log(logger, level, "Something bad happened", ...);

Sie können andere Varianten hinzufügen log, beispielsweise wenn Sie generische Äquivalente von SLF4Js 1-Parameter oder 2-Parameter warn/ error/ etc. Methoden.

Richard Fearn
quelle
3
Richtig, aber der Zweck von slf4j besteht nicht darin, Protokoll-Wrapper schreiben zu müssen.
Djjeck
5
Der Zweck von SLF4J besteht darin, eine Abstraktion für verschiedene Protokollierungsframeworks bereitzustellen. Wenn diese Abstraktion nicht genau das bietet, was Sie benötigen, haben Sie keine andere Wahl, als eine Hilfsmethode zu schreiben. Die einzige andere Alternative besteht darin, eine Methode wie die in meiner Antwort zum SLF4J-Projekt beizutragen.
Richard Fearn
Ich stimme zu, aber in diesem Fall gibt es Einschränkungen, so dass Sie keine Datei- und Zeilennummer mehr angeben können, es sei denn, Sie haben eine weitere Problemumgehung dafür implementiert. In diesem Fall wäre ich bei log4j geblieben, bis das Framework die Funktion unterstützt - was schließlich durch eine Erweiterung geschehen ist, siehe Robert Elliots neuere Antwort.
Djjeck
3

Ich habe gerade so etwas gebraucht und mir Folgendes ausgedacht:

@RequiredArgsConstructor //lombok annotation
public enum LogLevel{

    TRACE(l -> l::trace),
    INFO (l -> l::info),
    WARN (l -> l::warn),
    ERROR(l -> l::error);

    private final Function<Logger, Consumer<String>> function;

    public void log(Logger logger, String message) {
        function.apply(logger).accept(message);
    }
}

Verwendung:

    LogLevel level = LogLevel.TRACE;
    level.log(logger, "message");

Der Logger wird während des Aufrufs übergeben, daher sollten die Klasseninformationen in Ordnung sein und funktionieren gut mit der @ Slf4j-Lombok-Annotation.

Kamil Nowak
quelle
Vielen Dank für diesen großartigen Ansatz. Ich habe eine ähnliche Antwort veröffentlicht, die auf Ihrer Idee basiert.
Slartidan
DEBUGfehlt als Konstante.
Slartidan
Diese Lösung wird immer LogLevelals Klasse und logals Methode protokolliert, wodurch die Protokolle weniger aussagekräftig werden.
Slartidan
2

Es ist nicht möglich, eine Protokollstufe in sjf4j sofort anzugeben 1.x. Es besteht jedoch die Hoffnung, dass slf4j das Problem2.0 beheben kann . In 2.0 könnte es so aussehen:

// POTENTIAL 2.0 SOLUTION
import org.slf4j.helpers.Util;
import static org.slf4j.spi.LocationAwareLogger.*;

// does not work with slf4j 1.x
Util.log(logger, DEBUG_INT, "hello world!");

In der Zwischenzeit können Sie für slf4j 1.x diese Problemumgehung verwenden:

Kopieren Sie diese Klasse in Ihren Klassenpfad:

import org.slf4j.Logger;
import java.util.function.Function;

public enum LogLevel {

    TRACE(l -> l::trace, Logger::isTraceEnabled),
    DEBUG(l -> l::debug, Logger::isDebugEnabled),
    INFO(l -> l::info, Logger::isInfoEnabled),
    WARN(l -> l::warn, Logger::isWarnEnabled),
    ERROR(l -> l::error, Logger::isErrorEnabled);

    interface LogMethod {
        void log(String format, Object... arguments);
    }

    private final Function<Logger, LogMethod> logMethod;
    private final Function<Logger, Boolean> isEnabledMethod;

    LogLevel(Function<Logger, LogMethod> logMethod, Function<Logger, Boolean> isEnabledMethod) {
        this.logMethod = logMethod;
        this.isEnabledMethod = isEnabledMethod;
    }

    public LogMethod prepare(Logger logger) {
        return logMethod.apply(logger);
    }

    public boolean isEnabled(Logger logger) {
        return isEnabledMethod.apply(logger);
    }
}

Dann können Sie es so verwenden:

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

LogLevel level = LogLevel.ERROR;
level.prepare(logger).log("It works!"); // just message, without parameter
level.prepare(logger).log("Hello {}!", "world"); // with slf4j's parameter replacing

try {
    throw new RuntimeException("Oops");
} catch (Throwable t) {
    level.prepare(logger).log("Exception", t);
}

if (level.isEnabled(logger)) {
    level.prepare(logger).log("logging is enabled");
}

Dies gibt ein Protokoll wie folgt aus:

[main] ERROR Application - It works!
[main] ERROR Application - Hello world!
[main] ERROR Application - Exception
java.lang.RuntimeException: Oops
    at Application.main(Application.java:14)
[main] ERROR Application - logging is enabled

Lohnt es sich?

  • ProDer Quellcode-Speicherort bleibt erhalten (Klassennamen, Methodennamen und Zeilennummern verweisen auf Ihren Code).
  • ProSie können Variablen , Parameter und Rückgabetypen einfach als definierenLogLevel
  • ProIhr Geschäftscode bleibt kurz und leicht zu lesen, und es sind keine zusätzlichen Abhängigkeiten erforderlich.

Der Quellcode als minimales Beispiel wird auf GitHub gehostet .

Slartidan
quelle
Hinweis: Die LogMethodSchnittstelle muss öffentlich sein, damit sie mit Klassen außerhalb ihres Pakets arbeiten kann. Ansonsten funktioniert es wie vorgesehen. Vielen Dank!
andrebrait
1

Mit der slf4j-API ist es nicht möglich, die Protokollstufe dynamisch zu ändern, aber Sie können die Protokollierung (falls Sie diese verwenden) selbst konfigurieren. In diesem Fall erstellen Sie eine Factory-Klasse für Ihren Logger und implementieren den Root-Logger mit der von Ihnen benötigten Konfiguration.

LoggerContext loggerContext = new LoggerContext();
ch.qos.logback.classic.Logger root = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

// Configure appender
final TTLLLayout layout = new TTLLLayout();
layout.start(); // default layout of logging messages (the form that message displays 
// e.g. 10:26:49.113 [main] INFO com.yourpackage.YourClazz - log message

final LayoutWrappingEncoder<ILoggingEvent> encoder = new LayoutWrappingEncoder<>();
encoder.setCharset(StandardCharsets.UTF_8);
encoder.setLayout(layout);

final ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
appender.setContext(loggerContext);
appender.setEncoder(encoder);
appender.setName("console");
appender.start();

root.addAppender(appender);

Nachdem Sie den Root-Logger konfiguriert haben (nur einmal reicht aus), können Sie das Abrufen eines neuen Loggers an delegieren

final ch.qos.logback.classic.Logger logger = loggerContext.getLogger(clazz);

Denken Sie daran, dasselbe zu verwenden loggerContext .

Das Ändern der Protokollstufe ist mit dem Root-Logger von einfach loggerContext.

root.setLevel(Level.DEBUG);
pablo127
quelle
1

Antwort bestätigen Ondrej Skopek

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;

var rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(Level.TRACE);

Sie erhalten Ergebnis:

2020-05-14 14: 01: 16,644 TRACE [] [oakcmMetrics] Testarbeiter Registrierte Metrik mit dem Namen MetricName [Name = Pufferpool-Wartezeit-Summe, Gruppe = Hersteller-Metriken, Beschreibung = Die Gesamtzeit, die ein Appender auf die Speicherplatzzuweisung wartet ., tags = {client-id = Producer-2}]

Turin
quelle
0

Ich bin gerade auf ein ähnliches Bedürfnis gestoßen. In meinem Fall wird slf4j mit dem Java-Protokollierungsadapter (dem jdk14-Adapter) konfiguriert. Mit dem folgenden Code-Snippet konnte ich die Debug-Ebene zur Laufzeit ändern:

Logger logger = LoggerFactory.getLogger("testing");
java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger("testing");
julLogger.setLevel(java.util.logging.Level.FINE);
logger.debug("hello world");
Yair Zaslavsky
quelle
1
Wie bei anderen Antworten wird hier nicht die ursprüngliche Frage angesprochen, sondern ein anderes Problem.
E-Riz
0

Basierend auf der Antwort von massimo virgilio habe ich es auch geschafft, es mit slf4j-log4j unter Verwendung von Selbstbeobachtung zu tun. HTH.

Logger LOG = LoggerFactory.getLogger(MyOwnClass.class);

org.apache.logging.slf4j.Log4jLogger LOGGER = (org.apache.logging.slf4j.Log4jLogger) LOG;

try {
    Class loggerIntrospected = LOGGER.getClass();
    Field fields[] = loggerIntrospected.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
        String fieldName = fields[i].getName();
        if (fieldName.equals("logger")) {
            fields[i].setAccessible(true);
            org.apache.logging.log4j.core.Logger loggerImpl = (org.apache.logging.log4j.core.Logger) fields[i].get(LOGGER);
            loggerImpl.setLevel(Level.DEBUG);
        }
    }
} catch (Exception e) {
    System.out.println("ERROR :" + e.getMessage());
}
Guido
quelle
0

Hier ist eine Lambda-Lösung, die in einer Hinsicht nicht so benutzerfreundlich ist wie die von @Paul Croarkin (das Level wird effektiv zweimal bestanden). Aber ich denke (a) der Benutzer sollte den Logger übergeben; und (b) AFAIU die ursprüngliche Frage lautete nicht nach einem bequemen Weg für überall in der Anwendung, sondern nur nach einer Situation mit wenigen Verwendungen innerhalb einer Bibliothek.

package test.lambda;
import java.util.function.*;
import org.slf4j.*;

public class LoggerLambda {
    private static final Logger LOG = LoggerFactory.getLogger(LoggerLambda.class);

    private LoggerLambda() {}

    public static void log(BiConsumer<? super String, ? super Object[]> logFunc, Supplier<Boolean> logEnabledPredicate, 
            String format, Object... args) {
        if (logEnabledPredicate.get()) {
            logFunc.accept(format, args);
        }
    }

    public static void main(String[] args) {
        int a = 1, b = 2, c = 3;
        Throwable e = new Exception("something went wrong", new IllegalArgumentException());
        log(LOG::info, LOG::isInfoEnabled, "a = {}, b = {}, c = {}", a, b, c);

        // warn(String, Object...) instead of warn(String, Throwable), but prints stacktrace nevertheless
        log(LOG::warn, LOG::isWarnEnabled, "error doing something: {}", e, e);
    }
}

Da slf4j ein Throwable (dessen Stack-Trace protokolliert werden soll) innerhalb des varargs-Parameters zulässt , besteht meines Erachtens keine Notwendigkeit, die Hilfsmethodelog für andere Benutzer als zu überladen (String, Object[]).

EndlosSchleife
quelle
0

Ich konnte dies für die JDK14-Bindung tun, indem ich zuerst die SLF4J-Logger-Instanz anforderte und dann die Ebene für die Bindung festlegte. Sie können dies für die Log4J-Bindung versuchen.

private void setLevel(Class loggerClass, java.util.logging.Level level) {
  org.slf4j.LoggerFactory.getLogger(loggerClass);
  java.util.logging.Logger.getLogger(loggerClass.getName()).setLevel(level);
}
youurayy
quelle
0

Die Methode, die ich verwende, besteht darin, die ch.qos.logback-Module zu importieren und dann die slf4j Logger-Instanz in einen ch.qos.logback.classic.Logger zu typisieren. Diese Instanz enthält eine setLevel () -Methode.

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;

Logger levelSet = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);

// Now you can set the desired logging-level
levelSet.setLevel( Level.OFF );

Um die möglichen Protokollierungsstufen herauszufinden, können Sie die Klasse ch.qos.logback auflösen, um alle möglichen Werte für Stufe anzuzeigen :

prompt$ javap -cp logback-classic-1.2.3.jar ch.qos.logback.classic.Level

Die Ergebnisse sind die folgenden:

{
   // ...skipping
   public static final ch.qos.logback.classic.Level OFF;
   public static final ch.qos.logback.classic.Level ERROR;
   public static final ch.qos.logback.classic.Level WARN;
   public static final ch.qos.logback.classic.Level INFO;
   public static final ch.qos.logback.classic.Level DEBUG;
   public static final ch.qos.logback.classic.Level TRACE;
   public static final ch.qos.logback.classic.Level ALL;
}
Glenn Inn
quelle
-2

Mit Java Introspection können Sie dies zum Beispiel tun:

private void changeRootLoggerLevel(int level) {

    if (logger instanceof org.slf4j.impl.Log4jLoggerAdapter) {
        try {
            Class loggerIntrospected = logger.getClass();
            Field fields[] = loggerIntrospected.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                String fieldName = fields[i].getName();
                if (fieldName.equals("logger")) {
                    fields[i].setAccessible(true);
                    org.apache.log4j.Logger loggerImpl = (org.apache.log4j.Logger) fields[i]
                            .get(logger);

                    if (level == DIAGNOSTIC_LEVEL) {
                        loggerImpl.setLevel(Level.DEBUG);
                    } else {
                        loggerImpl.setLevel(org.apache.log4j.Logger.getRootLogger().getLevel());
                    }

                    // fields[i].setAccessible(false);
                }
            }
        } catch (Exception e) {
            org.apache.log4j.Logger.getLogger(LoggerSLF4JImpl.class).error("An error was thrown while changing the Logger level", e);
        }
    }

}
massimo virgilio
quelle
5
Dies bezieht sich ausdrücklich auf log4j und nicht generisch auf slf4j
Thorbjørn Ravn Andersen
-6

Nein, es gibt eine Reihe von Methoden, info (), debug (), warn () usw. (dies ersetzt das Prioritätsfeld).

hat einen Blick auf http://www.slf4j.org/api/org/slf4j/Logger.html für den vollen Logger api.

chris
quelle
Entschuldigung, ich sehe, was Sie jetzt fragen. Nein, es gibt keine generische Möglichkeit, die Protokollstufe zur Laufzeit zu ändern, aber Sie können problemlos eine Hilfsmethode mit einer Switch-Anweisung implementieren.
chris
Ja, aber dann müssen Sie dies einmal für jede überladene Version der "log" -Methode tun.
Andrew Swan