Définition du niveau de journalisation du message lors de l'exécution dans slf4j


100

Lors de l'utilisation de log4j, la Logger.log(Priority p, Object message)méthode est disponible et peut être utilisée pour consigner un message à un niveau de journal déterminé lors de l'exécution. Nous utilisons ce fait et cette astuce pour rediriger stderr vers un enregistreur à un niveau de journal spécifique.

slf4j n'a pas de log()méthode générique que je puisse trouver. Cela signifie-t-il qu'il n'y a aucun moyen de mettre en œuvre ce qui précède?


4
Il semble qu'il y ait une discussion sur l'ajout de ceci à slf4j 2.0 sur la liste de diffusion des développeurs: qos.ch/pipermail/slf4j-dev/2010-March/002865.html
Edward Dale

1
jetez un œil à Marker, ce sont des données personnalisées que vous pouvez transmettre à la chaîne de journaux.
tuxSlayer

1
@tuxSlayer pouvez-vous expliquer comment utiliser Marker dans ce cas?
Misérable variable du

Ce n'est probablement pas la meilleure idée pour la "journalisation", mais vous pouvez utiliser plusieurs marqueurs pour l'entrée de journal "priorité" (haute | basse | normale, info | avertir | fatal) et utiliser le filtrage dans la connexion ou un appender personnalisé pour consommer des marqueurs et générer des entrées de journal dans des canaux séparés (informations de journal, e-mail fatal, etc.). Cependant, la manière la plus directe est d'avoir une façade pour cela, comme cela a été souligné dans les réponses ci-dessous.
tuxSlayer

2
Cette fonctionnalité est censée faire partie de slf4j 2.0. jira.qos.ch/browse/SLF4J-124 Voir ma réponse pour plus de détails et pour une slf4j 1.xsolution de contournement possible .
slartidan

Réponses:


47

Il n'y a aucun moyen de faire cela avec slf4j.

J'imagine que la raison pour laquelle cette fonctionnalité est manquante est qu'il est pratiquement impossible de construire un Leveltype pour slf4jqui peut être mappé efficacement au type Level(ou équivalent) utilisé dans toutes les implémentations de journalisation possibles derrière la façade. Alternativement, les concepteurs ont décidé que votre cas d'utilisation était trop inhabituel pour justifier les frais généraux liés à sa prise en charge.

Concernant le cas d' utilisation de @ ripper234 (tests unitaires), je pense que la solution pragmatique est de modifier le (s) test (s) unitaire pour connaître en dur le système de journalisation derrière la façade slf4j ... lors de l'exécution des tests unitaires.


9
Il n'y a pas vraiment de cartographie nécessaire. Il existe cinq niveaux déjà définis implicitement par les méthodes dans org.slf4j.Logger: debug, error, info, trace, warn.
Edward Dale

1
Et les problèmes ont été fermés comme non valides. Pour autant que je sache, c'est un choix de conception délibéré.
ripper234

9
@ ripper234 - Je ne pense pas que votre bug aborde le même problème que la question initiale de scompt.com. Vous avez demandé comment configurer le niveau du système de journalisation sous - jacent via l'API SLF4J. Ce que recherchait scompt.com était une méthode générique de «journalisation» dans l'API SLF4J, qui prend le niveau de journalisation du message comme paramètre.
Richard Fearn

1
+1 @RichardFearn Et on ne peut pas annuler le vote pour le commentaire après 60 secondes, meh . Demande de fonctionnalité est en vigueur quant à lui: bugzilla.slf4j.org/show_bug.cgi?id=133
janvier

3
Les liens RFE ne se résolvent plus. Les liens pertinents sont maintenant: jira.qos.ch/browse/SLF4J-124 et jira.qos.ch/browse/SLF4J-197 ... et les deux ont été fermés. Lisez les commentaires pour la justification.
Stephen C

27

Richard Fearn a la bonne idée, alors j'ai rédigé le cours complet en me basant sur son squelette de code. J'espère que c'est assez court pour être publié ici. Copiez et collez pour le plaisir. Je devrais probablement ajouter une incantation magique aussi: "Ce code est publié dans le domaine public"

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

Ce serait plus facile à utiliser avec un paramètre args variadique (Object ...).
Anonymoose

"org.slf4j.Logger" a pas mal de signatures de méthode de journalisation qui ne sont pas gérées dans la classe ci-dessus, donc une extension est probablement justifiée: slf4j.org/api/org/slf4j/Logger.html
David Tonhofer

1
Je pense que cette implémentation ajoutera un changement non souhaité. Lorsque vous utilisez le call logger.info (...), le logger a accès à la classe et à la méthode de l'appelant et il peut être ajouté automatiquement à l'entrée du journal. Désormais, avec cette implémentation, le journal des appels (logger, level, txt) produira une entrée de journal qui aura toujours le même appelant: Loglevel.log. Ai-je raison?
Domin

@Domin Salut, vous voulez dire, l'enregistreur pourrait examiner la pile d'appels actuelle, puis extraire la dernière entrée pour la journalisation automatique, ce qui n'est pas le cas ici? En principe oui, mais en fait, la pile va baisser un peu plus même après cela jusqu'à ce que le message réel soit écrit (en particulier, logback doit être appelé à un moment donné, puis l'appender réel). Je pense que le rôle de l'appender devrait être de supprimer les lignes de pile non intéressantes, afin que vous puissiez l'adapter pour tout jeter jusqu'à et y compris l'appel à cette classe Loglevel.
David Tonhofer

@David, oui, vous avez raison :-). Je ne suis pas sûr que ce soit une tâche pour l'appender car dans ce cas vous définissez une dépendance dure entre l'appender et le logger ... mais ... c'est une solution. Merci David
Domin

14

Essayez de passer à Logback et utilisez

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

Je crois que ce sera le seul appel à Logback et le reste de votre code restera inchangé. Logback utilise SLF4J et la migration sera sans problème, seuls les fichiers de configuration xml devront être modifiés.

N'oubliez pas de redéfinir le niveau de journalisation une fois que vous avez terminé.


J'utilisais déjà slf4j basé sur Logback, et cela m'a instantanément permis de nettoyer mes tests unitaires. Merci!
Lambart

2
C'était mon premier -1, merci. Je crois que tu as tort. Logback utilise SLF4J, donc la réponse est pertinente.
Αλέκος

3
@AlexandrosGelbessis Vous devriez relire la question. Il a été demandé une méthode qui pourrait consigner par programme un message de journal à n'importe quel niveau. Vous modifiez le niveau de l'enregistreur racine pour tous les messages, pas seulement pour un.
jan

12

Vous pouvez l'implémenter à l'aide de lambdas 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);
    }
}

Eh bien oui ... mais maintenant vous devez modifier votre base de code pour utiliser cette API ainsi que ou à la place de slf4j. Si vous l'utilisez à la place de slf4j 1) il doit probablement être plus riche, 2) beaucoup (au moins) d'importations doivent être changées, et 3) cette nouvelle couche devant slf4j ajoute une surcharge de journalisation supplémentaire.
Stephen C

4
Sachez également que lorsque vous optez pour cette solution, la classe qui effectue la journalisation réelle ne sera pas enregistrée (car l'enregistreur est initialisé avec LevelLogger), ce qui n'est pas une bonne chose car ce sont généralement des informations très utiles.
Loir du

6

Cela peut être fait avec une enumméthode et une aide:

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

Vous pouvez ajouter d'autres variantes de log, par exemple si vous vouliez des équivalents génériques du paramètre 1 ou 2 paramètres de SLF4J warn/ error/ etc. méthodes.


3
C'est vrai, mais le but de slf4j n'est pas d'avoir à écrire des wrappers de journal.
djjeck

5
Le but de SLF4J est de fournir une abstraction pour différents frameworks de journalisation. Si cette abstraction ne fournit pas exactement ce dont vous avez besoin, vous n'avez pas d'autre choix que d'écrire une méthode d'assistance. La seule autre alternative est d'apporter une méthode comme celle de ma réponse au projet SLF4J.
Richard Fearn

Je suis d'accord, mais dans ce cas, il y a des mises en garde, comme le fait que vous ne seriez plus en mesure de fournir le numéro de fichier et de ligne, à moins que vous n'ayez mis en œuvre une autre solution de contournement pour cela. Dans ce cas, je serais resté avec log4j, jusqu'à ce que le framework prenne en charge la fonctionnalité - ce qui s'est finalement produit via une extension, voir la réponse plus récente de Robert Elliot.
djjeck


3

J'ai juste besoin de quelque chose comme ça et j'ai trouvé:

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

usage:

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

Logger est passé lors de l'invocation, donc les informations de classe devraient être correctes, et cela fonctionne bien avec l'annotation @ Slf4j lombok.


Merci beaucoup pour cette approche géniale - j'ai publié une réponse similaire, basée sur votre idée.
slartidan

DEBUGest manquant comme constante.
slartidan

Cette solution sera toujours journalisée en LogLeveltant que classe et en logtant que méthode, ce qui rend les journaux moins significatifs.
slartidan

2

Il n'est pas possible de spécifier un niveau de journalisation dans sjf4j 1.xhors de la boîte. Mais il y a de l'espoir pour slf4j 2.0de résoudre le problème . En 2.0, cela pourrait ressembler à ceci:

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

En attendant, pour slf4j 1.x, vous pouvez utiliser cette solution de contournement:

Copiez cette classe dans votre chemin de classe:

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

Ensuite, vous pouvez l'utiliser comme ceci:

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

Cela produira un journal comme celui-ci:

[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

Est-ce que ça vaut le coup?

  • ProIl conserve l' emplacement du code source (les noms de classe, les noms de méthode, les numéros de ligne pointeront vers votre code)
  • ProVous pouvez facilement définir des variables , des paramètres et des types de retour commeLogLevel
  • ProVotre code d'entreprise reste court et facile à lire, et aucune dépendance supplémentaire n'est requise.

Le code source comme exemple minimal est hébergé sur GitHub .


Remarque: l' LogMethodinterface doit être publique pour qu'elle fonctionne avec des classes en dehors de son package. Autre que cela, cela fonctionne comme prévu. Merci!
andrebrait

1

Il n'est pas possible avec l'API slf4j de modifier dynamiquement le niveau de journalisation, mais vous pouvez configurer la connexion (si vous l'utilisez) par vous-même. Dans ce cas, créez une classe d'usine pour votre enregistreur et implémentez l'enregistreur racine avec la configuration dont vous avez besoin.

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

Après avoir configuré l'enregistreur racine (une seule fois suffit), vous pouvez déléguer l'obtention d'un nouvel enregistreur en

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

N'oubliez pas d'utiliser la même chose loggerContext.

Changer le niveau de journalisation est facile à faire avec l'enregistreur racine fourni par loggerContext.

root.setLevel(Level.DEBUG);

1

Confirmer la réponse 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);

Vous obtiendrez le résultat:

2020-05-14 14: 01: 16,644 TRACE [] [oakcmMetrics] Test worker Métrique enregistrée nommée MetricName [name = bufferpool-wait-time-total, group = Producer-metrics, description = Le temps total pendant lequel un ajouteur attend l'allocation d'espace ., tags = {client-id = producteur-2}]


0

Je viens de rencontrer un besoin similaire. Dans mon cas, slf4j est configuré avec l'adaptateur de journalisation java (le jdk14). À l'aide de l'extrait de code suivant, j'ai réussi à modifier le niveau de débogage au moment de l'exécution:

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

1
Comme d'autres réponses, cela ne répond pas à la question initiale, c'est un problème différent.
E-Riz

0

Sur la base de la réponse de massimo virgilio, j'ai également réussi à le faire avec slf4j-log4j en utilisant l'introspection. 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());
}

0

Voici une solution lambda pas aussi conviviale que celle de @Paul Croarkin dans un sens (le niveau est effectivement passé deux fois). Mais je pense que (a) l'utilisateur devrait passer le Logger; et (b) AFAIU la question initiale ne demandait pas un moyen pratique pour partout dans l'application, seulement une situation avec peu d'utilisations à l'intérieur d'une bibliothèque.

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

Étant donné que slf4j autorise un Throwable (dont la trace de la pile doit être enregistrée) dans le paramètre varargs , je pense qu'il n'est pas nécessaire de surcharger la logméthode d'assistance pour d'autres consommateurs que (String, Object[]).


0

J'ai pu le faire pour la liaison JDK14 en demandant d'abord l'instance SLF4J Logger, puis en définissant le niveau de la liaison - vous pouvez essayer ceci pour la liaison 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);
}

0

La méthode que j'utilise consiste à importer les modules ch.qos.logback, puis à transtyper l'instance de slf4j Logger en ch.qos.logback.classic.Logger. Cette instance inclut une méthode 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 );

Pour connaître les niveaux de journalisation possibles, vous pouvez exploser la classe ch.qos.logback pour voir toutes les valeurs possibles pour Level :

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

Les résultats sont les suivants:

{
   // ...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;
}

-2

en utilisant l'introspection java, vous pouvez le faire, par exemple:

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

}

5
Cela fait explicitement référence à log4j et non à slf4j de manière générique
Thorbjørn Ravn Andersen

-6

non, il a un certain nombre de méthodes, info (), debug (), warn (), etc. (cela remplace le champ de priorité)

jetez un œil à http://www.slf4j.org/api/org/slf4j/Logger.html pour consulter l'API Logger complète.


désolé, je vois ce que vous demandez maintenant. non, il n'y a pas de moyen générique de changer le niveau de journal au moment de l'exécution, mais vous pouvez facilement implémenter une méthode d'assistance avec une instruction de commutateur.
chris

Oui, mais vous devez le faire une fois pour chaque version surchargée de la méthode "log".
Andrew Swan
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.