Logback:动态更改特定程序包中每个类的日志级别

时间:2018-07-17 15:46:56

标签: java logging logback slf4j

我正在一个使用SLF4J + Logback的项目中,我希望找到一种使用REST API调用来配置不同范围的日志级别的方法。该调用接收具有范围(类,包或根路径)和所需日志记录级别的对象。我项目中有记录器的每个类都使用一个静态的Logback记录器。

我使用了其他Stack Overflow答案和Logback手册来找到更改单个类的日志记录级别的解决方案:

LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger target = loggerContext.getLogger(DESIRED_CLASS_PATH);
target.setLevel(DESIRED_LOGGING_LEVEL);

这适用于该班。但是,我尝试使用root记录器来更改项目中所有类的所有记录器,方法是:

Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(DESIRED_LOGGING_LEVEL);

这仅更改了根记录器,并且当我尝试打印项目中任何类的日志级别时,它都不是所需的日志级别。我尝试在logback.xml文件中声明一个记录器,该记录器声明了一个包记录器(包含所有我的类和子包的包),并尝试修改该记录器以更改子类记录器,但这没有用。这是我的logback.xml文件:

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
        </layout>
    </appender>

    <root level="info">
        <appender-ref ref="STDOUT"/>
    </root>

    <logger name="my.uppermost.package" level="info" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>
</configuration>

我是否误解了Logback的代码或功能?如果没有,是否可以输入我的REST API调用的程序包路径,并更新该程序包中包含的类的所有记录器?

谢谢。

2 个答案:

答案 0 :(得分:2)

您可以获取现有记录器的列表并按名称过滤它们:

LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();

for(logger : loggerContext.getLoggerList()) {
 if(logger.getName().startWith("my.target.package.")) {
  logger.setLevel(DESIRED_LOGGING_LEVEL);
 }
}

请注意,它只会更改已存在的记录器的日志级别。如果 my.target.package 中的某个对象稍后注册了一个记录器,则其日志级别将是 logback.xml 中配置的任何内容

答案 1 :(得分:0)

<块引用>

这只会改变根记录器,当我尝试打印项目内任何类的日志级别时,它不是所需的日志级别

请注意 Logger#getEffectiveLevel 而不是 Logger#getLevel 是用于过滤日志的实际级别。


参考Effective Level aka Level Inheritance

<块引用>

如果给定的 logger 没有被分配一个级别,那么它会从其最近的祖先那里继承一个并分配一个级别。更正式的:

<块引用>

给定记录器 L 的有效级别等于其层次结构中的第一个非空级别,从 L 本身开始,在层次结构中向上向根记录器前进。

并且参考Logger setLevelhandleParentLevelChange 的源代码,如果日志级别为那些记录器没有设置。 如果日志级别已经在这些记录器中设置,Thibault Urien's answer 将完成这项工作。

以上行为可以通过以下示例进行说明。 LoggerLevelNotSet 未设置记录器级别的类

setLevel

LoggerLevelNotSet 设置了记录器级别的类

package com.logback.logger;

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

public class LoggerLevelNotSet {
    private static final Logger logger = LoggerFactory.getLogger(LoggerLevelNotSet.class);

    public static void log() {
        logger.trace("TRACE");
        logger.debug("DEBUG");
        logger.info("TRACE");
        logger.warn("WARN");
        logger.error("ERROR");
    }
}

logback.xml

package com.logback.logger;

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

public class LoggerLevelSet {
    private static final Logger logger = LoggerFactory.getLogger(LoggerLevelSet.class);

    public static void log() {
        logger.trace("TRACE");
        logger.debug("DEBUG");
        logger.info("TRACE");
        logger.warn("WARN");
        logger.error("ERROR");
    }
}

TestSetLoggerLevel 主类

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">

    <appender name="stdout"
              class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%-5level %logger{36} - %msg%n</Pattern>
        </layout>
    </appender>

    <logger name="com.logback.logger"
            additivity="false" level="TRACE">
        <appender-ref ref="stdout"/>
    </logger>
    <logger name="com.logback.logger.LoggerLevelSet"
            additivity="false" level="WARN">
        <appender-ref ref="stdout"/>
    </logger>

    <root>
        <appender-ref ref="stdout"/>
    </root>
</configuration>

结果

package com.logback.logger;

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

public class TestSetLoggerLevel {
    private static final Logger logger = LoggerFactory.getLogger(TestSetLoggerLevel.class);

    public static void main(String[] args) {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
        logger.error("Before set level");
        logLevel(loggerContext.getLogger("com.logback.logger.LoggerLevelNotSet"));
        logLevel(loggerContext.getLogger("com.logback.logger.LoggerLevelSet"));
        LoggerLevelNotSet.log();
        LoggerLevelSet.log();
        loggerContext.getLogger("com.logback.logger").setLevel(Level.ERROR);
        logger.error("After set level");
        logLevel(loggerContext.getLogger("com.logback.logger.LoggerLevelNotSet"));
        logLevel(loggerContext.getLogger("com.logback.logger.LoggerLevelSet"));
        LoggerLevelNotSet.log();
        LoggerLevelSet.log();
    }

    private static void logLevel(ch.qos.logback.classic.Logger log) {
        logger.error("{} level: {} effective level:{}", log.getName(), log.getLevel(), log.getEffectiveLevel());
    }
}