如何配置Logback实现特定Logger9-17点Info级、其余时段Warning级?
Logback实现按时间段切换特定Logger日志级别
Logback原生没有提供基于时间的日志级别动态切换功能,不过可以通过两种自定义方案实现需求:
方案一:自定义TurboFilter(实时判断时间过滤)
TurboFilter是Logback中优先级最高的过滤器,能在日志事件生成前进行判断,适合这种需要实时根据时间动态过滤的场景。
1. 编写自定义TurboFilter类
import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.turbo.TurboFilter; import ch.qos.logback.core.spi.FilterReply; import java.time.LocalTime; public class TimeBasedLevelFilter extends TurboFilter { // 目标Logger的名称(支持子Logger匹配) private String targetLoggerName; // 工作时段开始时间,默认9:00 private LocalTime startTime = LocalTime.of(9, 0); // 工作时段结束时间,默认17:00 private LocalTime endTime = LocalTime.of(17, 0); // 工作时段允许的最低日志级别 private Level workingLevel = Level.INFO; // 非工作时段允许的最低日志级别 private Level nonWorkingLevel = Level.WARN; @Override public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) { // 只处理目标Logger及其子Logger,其他日志直接放行 if (!logger.getName().startsWith(targetLoggerName)) { return FilterReply.NEUTRAL; } LocalTime now = LocalTime.now(); // 判断当前是否处于工作时段 boolean isWorkingHours = now.isAfter(startTime) && now.isBefore(endTime); Level allowedLevel = isWorkingHours ? workingLevel : nonWorkingLevel; // 日志级别高于等于允许级别则放行,否则拒绝 return level.isGreaterOrEqual(allowedLevel) ? FilterReply.ACCEPT : FilterReply.DENY; } // 提供setter方法,供Logback配置文件注入参数 public void setTargetLoggerName(String targetLoggerName) { this.targetLoggerName = targetLoggerName; } public void setStartTime(String startTime) { this.startTime = LocalTime.parse(startTime); } public void setEndTime(String endTime) { this.endTime = LocalTime.parse(endTime); } public void setWorkingLevel(String workingLevel) { this.workingLevel = Level.valueOf(workingLevel); } public void setNonWorkingLevel(String nonWorkingLevel) { this.nonWorkingLevel = Level.valueOf(nonWorkingLevel); } }
2. 在Logback配置文件中注册过滤器
修改logback.xml(或logback-spring.xml),添加自定义过滤器配置:
<configuration> <!-- 注册自定义时间级别过滤器 --> <turboFilter class="com.yourpackage.TimeBasedLevelFilter"> <!-- 指定要控制的目标Logger,例如com.example.myapp --> <targetLoggerName>com.example.myapp</targetLoggerName> <!-- 工作时段开始时间,格式HH:mm --> <startTime>09:00</startTime> <!-- 工作时段结束时间 --> <endTime>17:00</endTime> <!-- 工作时段允许的最低日志级别 --> <workingLevel>INFO</workingLevel> <!-- 非工作时段允许的最低日志级别 --> <nonWorkingLevel>WARN</nonWorkingLevel> </turboFilter> <!-- 常规Appender配置示例 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- Root Logger配置 --> <root level="DEBUG"> <appender-ref ref="CONSOLE" /> </root> </configuration>
方案二:定时切换Logger级别(修改Logger配置)
通过定时任务每天在指定时间修改目标Logger的级别,逻辑更直观。
1. 编写定时任务类
import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import org.slf4j.LoggerFactory; import java.time.LocalTime; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class LogLevelScheduler { public static void setupScheduledLogLevelChange(String targetLoggerName) { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); Logger targetLogger = loggerContext.getLogger(targetLoggerName); ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); // 计算距离下一个9点的延迟时间 LocalTime now = LocalTime.now(); LocalTime nineOClock = LocalTime.of(9, 0); long initialDelayToNine = now.isBefore(nineOClock) ? calculateDelay(now, nineOClock) : TimeUnit.DAYS.toMillis(1) - calculateDelay(nineOClock, now); // 每天9点将目标Logger级别设为INFO scheduler.scheduleAtFixedRate( () -> targetLogger.setLevel(Level.INFO), initialDelayToNine, TimeUnit.DAYS.toMillis(1), TimeUnit.MILLISECONDS ); // 计算距离下一个17点的延迟时间 LocalTime seventeenOClock = LocalTime.of(17, 0); long initialDelayToSeventeen = now.isBefore(seventeenOClock) ? calculateDelay(now, seventeenOClock) : TimeUnit.DAYS.toMillis(1) - calculateDelay(seventeenOClock, now); // 每天17点将目标Logger级别设为WARN scheduler.scheduleAtFixedRate( () -> targetLogger.setLevel(Level.WARN), initialDelayToSeventeen, TimeUnit.DAYS.toMillis(1), TimeUnit.MILLISECONDS ); // 可选:在应用关闭时关闭线程池,避免内存泄漏 Runtime.getRuntime().addShutdownHook(new Thread(scheduler::shutdown)); } private static long calculateDelay(LocalTime start, LocalTime end) { return TimeUnit.HOURS.toMillis(end.getHour() - start.getHour()) + TimeUnit.MINUTES.toMillis(end.getMinute() - start.getMinute()) - TimeUnit.SECONDS.toMillis(start.getSecond()) - start.getNano() / 1000000; } }
2. 在应用启动时初始化定时任务
以Spring Boot应用为例,在启动类中调用初始化方法:
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); // 给目标Logger设置定时级别切换 LogLevelScheduler.setupScheduledLogLevelChange("com.example.myapp"); } }
两种方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| TurboFilter | 实时判断时间,精准度高;应用重启不影响 | 需编写过滤器逻辑,需注意Filter执行顺序 |
| 定时切换 | 逻辑直观,直接修改Logger配置 | 应用重启后需重新初始化,重启后到触发点前级别可能不符合预期 |
注意事项
- 自定义类的包路径要正确,确保Logback能加载到。
- 使用TurboFilter时,它会优先于所有Appender执行,需避免影响其他Logger的日志输出。
- 定时任务方案要处理好线程池的关闭,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Kash
相关产品推荐
相关产品推荐

