在slf4j中设置运行时消息的日志级别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在slf4j中设置运行时消息的日志级别相关的知识,希望对你有一定的参考价值。

使用log4j时,Logger.log(Priority p, Object message)方法可用,可用于在运行时确定的日志级别记录消息。我们正在使用这个事实和this tip将stderr重定向到特定日志级别的记录器。

slf4j没有我能找到的通用log()方法。这是否意味着无法实现上述目标?

答案

使用slf4j无法做到这一点。

我想,缺少这个功能的原因是几乎不可能为Level构造一个slf4j类型,它可以有效地映射到在Facade后面的所有可能的日志记录实现中使用的Level(或等效)类型。或者,设计师决定your use-case is too unusual证明支持它的开销是合理的。

关于@ripper234use-case(单元测试),我认为实用的解决方案是修改单元测试,以便在运行单元测试时强硬了解slf4j外观背后的日志系统的知识。

另一答案

基于massimo virgilio的答案,我还设法使用内省来使用slf4j-log4j。 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());
}
另一答案

这是一个lambda解决方案,不像@Paul Croarkin那样用户友好(水平有效地传递了两次)。但我认为(a)用户应该通过Logger; (b)AFAIU原始问题并不是要求应用程序中的任何地方使用方便的方法,只是在图书馆内几乎没有使用的情况。

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

自从slf4j allows a Throwable (whose stack trace should be logged) inside the varargs param以来,我认为除了log之外,没有必要为其他消费者重载(String, Object[])辅助方法。

另一答案

我能够通过首先请求SLF4J Logger实例然后在绑定上设置级别来为JDK14绑定执行此操作 - 您可以尝试使用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);
}
另一答案

我使用的方法是导入ch.qos.logback模块,然后将slf4j Logger实例类型转换为ch.qos.logback.classic.Logger。此实例包含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 );

要找出可能的日志级别,您可以展开ch.qos.logback类以查看Level的所有可能值:

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

结果如下:

{
   // ...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;
}
另一答案

使用java自省可以做到,例如:

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

}
另一答案

不,它有很多方法,info(),debug(),warn()等(这取代了优先级字段)

看看http://www.slf4j.org/api/org/slf4j/Logger.html的完整Logger api。

另一答案

Richard Fearn有正确的想法,所以我根据他的骨架代码编写了完整的类。希望足够短,可以在这里发布。复制和粘贴享受。我应该添加一些神奇的咒语:“此代码发布到公共领域”

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;
  

以上是关于在slf4j中设置运行时消息的日志级别的主要内容,如果未能解决你的问题,请参考以下文章

在 MISRA C 中设置日志级别的标准方法

如何在 Winston/Node.js 中设置日志级别

如何在运行时在 org.jboss.logging 中设置日志记录

通过环境变量在 Spring Boot 中设置日志记录级别

如何在运行时在由 android studio 创建的导航抽屉中设置默认片段

python 如何在tensorflow中设置日志记录级别