在 Logback 中,除了通过 JMX 动态修改日志级别外,还可以通过编程方式动态调整日志级别,而不依赖 JMX。这种方式在某些场景下更加灵活,例如从 REST 接口、配置文件或命令行参数中动态修改日志级别。

LoggerContext修改日志级别

LoggerContext 是 Logback 的核心组件,提供了对日志记录器和配置的直接控制。可以通过 LoggerContext 修改某个日志记录器的级别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;

public class DynamicLogLevelExample {
public static void main(String[] args) {
// 获取 LoggerContext
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

// 获取目标 Logger
Logger logger = context.getLogger("com.example.MyClass");

// 打印当前日志级别
System.out.println("Current Log Level: " + logger.getLevel());

// 动态修改日志级别为 DEBUG
logger.setLevel(Level.DEBUG);

// 打印修改后的日志级别
System.out.println("Updated Log Level: " + logger.getLevel());

// 测试日志输出
logger.info("This is an INFO message");
logger.debug("This is a DEBUG message");
}
}

配置文件动态加载日志级别

可以监控外部配置文件的变化,并动态更新日志级别。例如,使用 Logback 的 ConfigurationAction 类来重新加载配置。

在 Logback 配置中启用自动重载,通过编辑配置文件中的日志级别,Logback 会在下次扫描时自动加载更新。

  • scan="true":启用配置文件监控。
  • scanPeriod="30 seconds":每 30 秒检查一次配置文件的变化。
1
2
3
4
5
6
<configuration scan="true" scanPeriod="30 seconds">
<property name="logLevel" value="INFO"/>
<root level="${logLevel}">
<appender-ref ref="console"/>
</root>
</configuration>

REST API 动态调整日志级别

如果需要通过外部接口控制日志级别,可以结合 LoggerContext 和 REST 框架(如 Spring Boot)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/log")
public class LogController {

@PostMapping("/level")
public String changeLogLevel(@RequestParam String loggerName, @RequestParam String level) {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger logger = context.getLogger(loggerName);

if (logger == null) {
return "Logger not found: " + loggerName;
}

try {
Level newLevel = Level.valueOf(level.toUpperCase());
logger.setLevel(newLevel);
return "Logger level updated to " + newLevel + " for logger " + loggerName;
} catch (IllegalArgumentException e) {
return "Invalid log level: " + level;
}
}
}

测试接口:

1
curl -X POST "http://localhost:8080/log/level" -d "loggerName=com.example.MyClass" -d "level=DEBUG"

从数据库或外部配置源加载日志级别

在某些场景中,日志级别可能存储在数据库或其他外部配置中,可以定期检查这些配置并更新日志级别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.LoggerFactory;

import java.util.Timer;
import java.util.TimerTask;

public class DynamicLogLevelFromDb {

public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
updateLogLevel();
}
}, 0, 60000); // 每 60 秒检查一次
}

private static void updateLogLevel() {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger logger = context.getLogger("com.example.MyClass");

// 模拟从数据库获取日志级别
String dbLogLevel = getLogLevelFromDb(); // 假设这个方法从数据库中获取日志级别

if (dbLogLevel != null) {
logger.setLevel(Level.valueOf(dbLogLevel.toUpperCase()));
System.out.println("Updated logger level to " + dbLogLevel);
}
}

private static String getLogLevelFromDb() {
// 模拟从数据库中获取日志级别
return "DEBUG"; // 实际情况应通过数据库查询获取
}
}

总结

  1. 编程动态修改:通过 LoggerContext 直接修改日志级别,简单高效。
  2. 配置文件自动加载:监控配置文件的变化,自动更新日志级别。
  3. REST API:通过接口灵活控制日志级别,适合微服务架构。
  4. 外部配置(如数据库):定期检查外部配置,并动态更新日志级别。