logback进阶
参考:
https://www.cnblogs.com/yw0219/p/9310701.html
https://www.cnblogs.com/yw0219/p/9310845.html
https://www.cnblogs.com/yw0219/p/9320846.html
https://www.cnblogs.com/yw0219/p/9361040.html
以上是logback的官方文档的翻译,值得一看。
在一般的服务中,我们调试的时候将日志打印到控制台console,生产环境中将日志输出到日志文件
1.对日志分级别level进行打印,一般至少分三个文件error.log,warn.log和info.log
2.每天的日志写入以当天命名的文件夹中,比如20220525,
3.日志文件指定一个阈值大小,比如10M,或者100M,超过阈值对日志文件进行切分,新日志写入新文件。
分级别、分日期、滚动写入。以上的配置对于一般的服务就足够了。
但有一种特殊的服务,比如调度系统,它会执行非常多的异构任务,这些任务的日志为了方便查看,是不应该写入一个文件中的。
需要将每个任务写入特定的文件中。那么logback能实现吗?
答案是肯定的!
首先我们贴出logback.xml配置文件。
<?xml version="1.0" encoding="UTF-8"?> <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 --> <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true --> <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 --> <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 --> <configuration> <property name="logDir" value="logs" /> <property name="maxHistory" value="30" /> <property name="log.base" value="logs"/> <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> <!-- ERROR级别日志 --> <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${logDir}/error.log</file> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${logDir}/%d{yyyyMMdd}/error.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern> <charset class="java.nio.charset.Charset">UTF-8</charset> </encoder> <append>false</append> <prudent>false</prudent> </appender> <!-- WARN级别日志 --> <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${logDir}/warn.log</file> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>WARN</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${logDir}/%d{yyyyMMdd}/warn.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger-%msg%n</pattern> <charset class="java.nio.charset.Charset">UTF-8</charset> </encoder> <append>false</append> <prudent>false</prudent> </appender> <!-- INFO级别日志 --> <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${logDir}/info.log</file> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${logDir}/%d{yyyyMMdd}/info.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger-%msg%n</pattern> <charset class="java.nio.charset.Charset">UTF-8</charset> </encoder> <append>false</append> <prudent>false</prudent> </appender> <appender name="TASKLOGFILE" class="ch.qos.logback.classic.sift.SiftingAppender"> <filter class="cc.eslink.metadata.scheduler.log.TaskLogFilter"/> <Discriminator class="cc.eslink.metadata.scheduler.log.TaskLogDiscriminator"> <key>taskAppId</key> <logBase>${log.base}</logBase> </Discriminator> <sift> <appender name="FILE-${taskAppId}" class="ch.qos.logback.core.FileAppender"> <file>${log.base}/${taskAppId}.log</file> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger-%msg%n</pattern> <charset class="java.nio.charset.Charset">UTF-8</charset> </encoder> <append>true</append> </appender> </sift> </appender> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="ERROR" /> <appender-ref ref="WARN" /> <appender-ref ref="INFO" /> <appender-ref ref="TASKLOGFILE" /> </root> </configuration>
name等于ERROR、WARN、INFO的appender都是一般的配置,我们指定任务写入指定文件的配置主要在TASKLOGFILE的appender中。
为了实现行级日志的指定文件写入,我们自定义了两个配置类。分别是TaskLogFilter和TaskLogDiscriminator
//TaskLogFilter 决定哪些日志会被筛选到名为TASKLOGFILE的appender中 public class TaskLogFilter extends Filter<ILoggingEvent> { private Level level; public void setLevel(String level) { this.level = Level.toLevel(level); } @Override public FilterReply decide(ILoggingEvent event) { FilterReply filterReply = FilterReply.DENY; if ((event.getThreadName().startsWith("taskAppId") && event.getLoggerName().startsWith("TaskLogLogger")) || event.getLevel().isGreaterOrEqual(level)) { filterReply = FilterReply.ACCEPT; } return filterReply; } }
日志的筛选我们已经完成了,下一步就是把对应任务的日志写入对应的文件中,这个实现在TaskLogDiscriminator中
//通过一系列操作,我们将groupName=group,jobName=job的调度任务的日志写入到group/job.log文件中 public class TaskLogDiscriminator extends AbstractDiscriminator<ILoggingEvent> { /** * key */ private String key; /** * log base */ private String logBase; @Override public String getDiscriminatingValue(ILoggingEvent event) { String key = "unknown_task"; if (event.getLoggerName().startsWith("TaskLogLogger")) { String threadName = event.getThreadName(); String part1 = threadName.split("=")[1]; String prefix = "TASK-"; if (part1.startsWith(prefix)) { key = part1.substring(prefix.length()).replaceFirst("-", "/"); } } return key; } @Override public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getLogBase() { return logBase; } public void setLogBase(String logBase) { this.logBase = logBase; } }
大功告成,感谢logback!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
2021-05-26 java8新时间API-LocalDateTime(转)