Ustawianie poziomu dziennika wiadomości w czasie wykonywania w slf4j

100

W przypadku korzystania z log4j Logger.log(Priority p, Object message)metoda jest dostępna i może służyć do rejestrowania komunikatu na poziomie dziennika określonym w czasie wykonywania. Używamy tego faktu i tej wskazówki, aby przekierować stderr do rejestratora na określonym poziomie dziennika.

slf4j nie ma ogólnej log()metody, którą mogę znaleźć. Czy to oznacza, że ​​nie ma sposobu na wdrożenie powyższego?

Edward Dale
źródło
4
Wygląda na to, że jest dyskusja o dodaniu tego do slf4j 2.0 na liście dyskusyjnej deweloperów
Edward Dale
1
spójrz na Marker, są to niestandardowe dane, które możesz przekazać do łańcucha dziennika.
tuxSlayer
1
@tuxSlayer Czy możesz wyjaśnić, jak używać Markera w tym przypadku?
Nędzna zmienna,
Prawdopodobnie nie jest to najlepszy pomysł na "rejestrowanie", ale możesz użyć kilku znaczników dla wpisu do dziennika "priorytet" (wysoki | niski | normalny, info | ostrzeżenie | krytyczny) i użyć filtrowania w logbacku lub niestandardowym programie dołączającym, aby zużywać znaczniki i wpisy dziennika dysku na oddzielne kanały (informacje logowania, krytyczny e-mail itp.) Jednak prostszym sposobem jest posiadanie fasady, jak wskazano w odpowiedziach poniżej.
tuxSlayer
2
Ta funkcja ma być częścią slf4j 2.0. jira.qos.ch/browse/SLF4J-124 Zobacz moją odpowiedź, aby uzyskać szczegółowe informacje i możliwe slf4j 1.xobejście.
slartidan

Odpowiedzi:

47

Nie da się tego zrobić slf4j.

Wyobrażam sobie, że powodem braku tej funkcji jest to, że prawie niemożliwe jest skonstruowanie Leveltypu, slf4jktóry można skutecznie odwzorować na Level(lub równoważny) typ używany we wszystkich możliwych implementacjach logowania za fasadą. Alternatywnie, projektanci zdecydowali, że Twój przypadek użycia jest zbyt nietypowy, aby uzasadnić koszty jego obsługi.

Odnośnie @ ripper234 „s przypadków użycia (Unit Testing), myślę, że pragmatyczne rozwiązanie jest zmodyfikowanie testu (ów) Urządzenie do wiedzy trudno drutu jaki system rejestracji jest za fasadą slf4j ... podczas uruchamiania testów jednostkowych.

Stephen C.
źródło
9
Naprawdę nie ma potrzeby mapowania. Istnieje pięć poziomów już domyślnie zdefiniowanych przez metody w org.slf4j.Logger: debug, error, info, trace, warn.
Edward Dale,
1
Problemy zostały zamknięte jako nieprawidłowe. O ile to rozumiem, jest to przemyślany wybór projektowy.
ripper234
9
@ ripper234 - Nie sądzę, aby Twój błąd dotyczył tego samego problemu, co pytanie zadane przez scompt.com. Pytałeś o konfigurację poziomu podstawowego systemu logowania za pośrednictwem SLF4J API. Scompt.com szukał ogólnej metody „log” w interfejsie API SLF4J, która przyjmuje jako parametr poziom rejestrowania wiadomości .
Richard Fearn,
1
+1 @RichardFearn i nie można cofnąć komentarza upvote po 60 sekundach, meh . W międzyczasie istnieje prośba o dodanie funkcji: bugzilla.slf4j.org/show_bug.cgi?id=133
sty
3
Linki RFE już nie rozwiązują. Odpowiednie linki to teraz: jira.qos.ch/browse/SLF4J-124 i jira.qos.ch/browse/SLF4J-197 ... i oba zostały zamknięte. Przeczytaj komentarze dotyczące uzasadnienia.
Stephen C
27

Richard Fearn ma dobry pomysł, więc napisałem całą klasę w oparciu o jego szkieletowy kod. Mam nadzieję, że jest wystarczająco krótki, aby opublikować tutaj. Kopiuj i wklejaj dla przyjemności. Powinienem też chyba dodać jakieś magiczne zaklęcie: „Ten kod jest udostępniany publicznie”

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
źródło
Byłoby łatwiejsze w użyciu z parametrem argumentów variadic (Object ...).
Anonymoose
"org.slf4j.Logger" ma sporo sygnatur metod logowania, które nie są obsługiwane w powyższej klasie, więc rozszerzenie jest prawdopodobnie uzasadnione: slf4j.org/api/org/slf4j/Logger.html
David Tonhofer
1
Myślę, że ta implementacja doda niechcianą zmianę. Gdy używasz wywołania logger.info (...), rejestrator ma dostęp do klasy i metody wywołującego i może zostać automatycznie dodany do wpisu dziennika. Teraz, dzięki tej implementacji, dziennik połączeń (rejestrator, poziom, txt) utworzy wpis dziennika, który będzie miał zawsze tego samego dzwoniącego: Loglevel.log. Czy mam rację?
Domin
@Domin Cześć, masz na myśli, że program rejestrujący mógłby sprawdzić bieżący stos wywołań, a następnie wyodrębnić ostatni wpis do automatycznego logowania, co nie ma miejsca w tym przypadku? W zasadzie tak, ale w rzeczywistości stos będzie się trochę powiększał, nawet po tym, aż właściwa wiadomość zostanie wypisana (w szczególności w pewnym momencie należy wywołać logback, a następnie faktyczny appender). Myślę, że rolą appendera powinno być wyrzucenie nieciekawych wierszy stosu, więc można go dostosować tak, aby wyrzucić wszystko do tej klasy Loglevel, włącznie z wywołaniem.
David Tonhofer
@David, tak, masz rację :-). Nie jestem pewien, czy jest to zadanie dla appendera, ponieważ w tym przypadku definiujesz twardą zależność między aplikatorem a loggerem ... ale ... to jest rozwiązanie. Dzięki David
Domin
14

Spróbuj przełączyć się na Logback i użyj

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"));

Wierzę, że będzie to jedyne wezwanie do Logback, a reszta twojego kodu pozostanie niezmieniona. Logback używa SLF4J, a migracja będzie bezbolesna, wystarczy zmienić pliki konfiguracyjne xml.

Pamiętaj, aby po zakończeniu ustawić ponownie poziom dziennika.

Αλέκος
źródło
Używałem już slf4j wspieranego przez Logback, co pozwoliło mi natychmiast wyczyścić testy jednostkowe. Dzięki!
Lambart
2
To był mój pierwszy -1, dzięki. Myślę, że się mylisz. Logback używa SLF4J, więc odpowiedź jest istotna.
Αλέκος
3
@AlexandrosGelbessis Powinieneś ponownie przeczytać pytanie. Poproszono o metodę, która mogłaby programowo rejestrować jeden komunikat dziennika na dowolnym poziomie. Zmieniasz poziom głównego programu rejestrującego dla wszystkich wiadomości, nie tylko dla jednego.
styczeń
12

Możesz to zaimplementować za pomocą lambd Java 8.

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
źródło
Cóż, tak ... ale teraz musisz zmodyfikować swój kod, aby używać tego interfejsu API, a także lub zamiast slf4j. Jeśli używasz go zamiast slf4j 1) prawdopodobnie musi być bogatszy, 2) wiele (przynajmniej) importów wymaga zmiany i 3) ta nowa warstwa przed slf4j dodaje dodatkowe obciążenie logowania.
Stephen C
4
Należy również pamiętać, że jeśli zdecydujesz się na to rozwiązanie, klasa, która wykonuje faktyczne rejestrowanie, nie zostanie zarejestrowana (ponieważ rejestrator jest zainicjowany LevelLogger), co nie jest dobrą rzeczą, ponieważ jest to ogólnie bardzo przydatna informacja.
Dormouse
6

Można to zrobić za enumpomocą metody i pomocnika:

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", ...);

Możesz dodać inne warianty log, powiedzmy, jeśli chcesz generycznych odpowiedników 1-parametrowego lub 2-parametrowego SLF4J warn/ error/ etc. metody.

Richard Fearn
źródło
3
To prawda, ale celem slf4j nie jest pisanie opakowań dziennika.
djjeck
5
Celem SLF4J jest zapewnienie abstrakcji dla różnych ram rejestrowania. Jeśli ta abstrakcja nie zapewnia dokładnie tego, czego potrzebujesz, nie masz innego wyjścia, jak napisać metodę pomocniczą. Jedyną alternatywą jest wniesienie metody takiej jak ta w mojej odpowiedzi do projektu SLF4J.
Richard Fearn,
Zgadzam się, ale w tym przypadku są pewne zastrzeżenia, na przykład nie będziesz w stanie podać numeru pliku i wiersza, chyba że zaimplementujesz jeszcze jedno obejście tego problemu. W tym przypadku utknąłbym z log4j, dopóki framework nie obsługiwałby tej funkcji - co ostatecznie stało się poprzez rozszerzenie, zobacz nowszą odpowiedź Roberta Elliota.
djjeck
5

Każdy, kto chce w pełni kompatybilnego z SLF4J rozwiązania tego problemu, może chcieć wypróbować Lidalia SLF4J Extensions - jest na Maven Central.

Robert Elliot
źródło
3

Po prostu potrzebowałem czegoś takiego i wymyśliłem:

@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);
    }
}

stosowanie:

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

Rejestrator jest przekazywany podczas wywołania, więc informacje o klasie powinny być w porządku i dobrze współpracuje z adnotacją @ Slf4j lombok.

Kamil Nowak
źródło
Bardzo dziękuję za to niesamowite podejście - zamieściłem podobną odpowiedź, opartą na Twoim pomyśle.
slartidan
DEBUGbrakuje jako stałe.
slartidan
To rozwiązanie będzie zawsze rejestrowane LogLeveljako klasa i logmetoda, co sprawia, że ​​dzienniki są mniej sensowne.
slartidan
2

To nie możliwe, aby określić poziom dziennika w sjf4j 1.xpo wyjęciu z pudełka. Ale jest nadzieja, że ​​slf4j 2.0naprawi problem . W wersji 2.0 może to wyglądać tak:

// 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!");

W międzyczasie w przypadku slf4j 1.x możesz zastosować to obejście:

Skopiuj tę klasę do swojej ścieżki klas:

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);
    }
}

Następnie możesz go użyć w ten sposób:

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");
}

Spowoduje to wyświetlenie następującego dziennika:

[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

Czy warto?

  • ProZachowuje lokalizację kodu źródłowego (nazwy klas, nazwy metod, numery wierszy będą wskazywać na twój kod)
  • ProMożesz łatwo definiować zmienne , parametry i typy zwracane jakoLogLevel
  • ProTwój kod biznesowy pozostaje krótki i łatwy do odczytania i nie są wymagane żadne dodatkowe zależności .

Kod źródłowy jako minimalny przykład jest hostowany na GitHub .

slartidan
źródło
Uwaga: LogMethodinterfejs musi być publiczny, aby działał z klasami spoza pakietu. Poza tym działa zgodnie z przeznaczeniem. Dzięki!
andrebrait
1

Nie jest możliwe za pomocą slf4j API, aby dynamicznie zmieniać poziom logowania, ale możesz skonfigurować logback (jeśli używasz tego) samodzielnie. W takim przypadku utwórz klasę fabryczną dla swojego rejestratora i zaimplementuj główny program rejestrujący z potrzebną konfiguracją.

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);

Po skonfigurowaniu głównego programu rejestrującego (wystarczy tylko jeden raz) możesz delegować pobieranie nowego rejestratora przez

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

Pamiętaj, aby użyć tego samego loggerContext.

Zmiana poziomu dziennika jest łatwa do zrobienia za pomocą głównego programu rejestrującego podanego z loggerContext.

root.setLevel(Level.DEBUG);
pablo127
źródło
1

Potwierdź odpowiedź 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);

Otrzymasz wynik:

2020-05-14 14: 01: 16,644 TRACE [] [oakcmMetrics] Pracownik testowy Zarejestrowana metryka o nazwie MetricName [nazwa = bufor-pula-czasu-oczekiwania-łączny, grupa = producent-metryki, description = Całkowity czas, przez który dołączający oczekuje na przydział miejsca ., tagi = {identyfikator-klienta = producent-2}]

Torino
źródło
0

Właśnie spotkałem się z podobną potrzebą. W moim przypadku slf4j jest skonfigurowany z adapterem logującym java (jdk14). Korzystając z następującego fragmentu kodu, udało mi się zmienić poziom debugowania w czasie wykonywania:

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
źródło
1
Podobnie jak inne odpowiedzi, to nie odpowiada pierwotnemu pytaniu, to inny problem.
E-Riz
0

Opierając się na odpowiedzi Massimo virgilio, udało mi się to również zrobić za pomocą slf4j-log4j przy użyciu introspekcji. 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
źródło
0

Oto rozwiązanie lambda, które nie jest tak przyjazne dla użytkownika, jak @Paul Croarkin w jednym kierunku (poziom jest skutecznie przekazywany dwukrotnie). Ale myślę, że (a) użytkownik powinien przekazać Logger; oraz (b) AFAIU, pierwotne pytanie nie dotyczyło wygodnego sposobu dla wszystkich elementów aplikacji, a jedynie sytuacji, w której w bibliotece jest niewiele zastosowań.

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);
    }
}

Ponieważ slf4j zezwala na Throwable (którego ślad stosu powinien być rejestrowany) wewnątrz parametru varargs , myślę, że nie ma potrzeby przeciążania logmetody pomocniczej dla innych konsumentów niż (String, Object[]).

EndlosSchleife
źródło
0

Udało mi się to zrobić dla powiązania JDK14, najpierw żądając instancji SLF4J Logger, a następnie ustawiając poziom wiązania - możesz spróbować tego dla powiązania Log4J.

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
źródło
0

Metoda, której używam, polega na zaimportowaniu modułów ch.qos.logback, a następnie przesłaniu instancji programu slf4j Logger do ch.qos.logback.classic.Logger. Ta instancja zawiera metodę setLevel ().

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 );

Aby poznać możliwe poziomy rejestrowania, możesz rozbić klasę ch.qos.logback, aby zobaczyć wszystkie możliwe wartości poziomu :

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

Wyniki są następujące:

{
   // ...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
źródło
-2

używając introspekcji java możesz to zrobić, na przykład:

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
źródło
5
To wyraźnie odnosi się do log4j, a nie ogólnie do slf4j
Thorbjørn Ravn Andersen
-6

nie, ma wiele metod, info (), debug (), warn () itp. (to zastępuje pole priorytetu)

zajrzyj na http://www.slf4j.org/api/org/slf4j/Logger.html, aby uzyskać pełny interfejs API Loggera.

chris
źródło
przepraszam, rozumiem teraz o co pytasz. nie, nie ma ogólnego sposobu zmiany poziomu dziennika w czasie wykonywania, ale można łatwo zaimplementować metodę pomocniczą z instrukcją przełącznika.
chris
Tak, ale musisz to zrobić raz dla każdej przeciążonej wersji metody „log”.
Andrew Swan