从青铜到王者,如何从0到1搭建一个完善的日志系统
【摘要】 不管是游戏还是其他的web开发,日志都是非常重要的组件,是解决问题的关键,今天聊聊日志组件Logback。 在业务系统开发中,一般使用的日志框架有 Commons logging 、 Log4j 、 Slf4j 、 Logback 、 Log4j 2 等。 业务日志一般分为trace 、 debug 、 warn、 info 和 error 级别等,线上系统根据其特点进行的相应设置也不同,...
1、slf4j 和logback的绑定
1、SLF4J和logback 原理
2、源码解析
2.3、自己实现:(技术点)
public class App {
public static void main(String[] args) throws IOException {
Enumeration<URL> resources = App.class.getClassLoader().getResources("org/slf4j/impl/StaticLoggerBinder.class");
while(resources.hasMoreElements()) {
URL path = resources.nextElement();
System.out.println(path);
}
}
}
2、logback的概念
1、配置文件的加载顺序
-
在classpath查找logback-test.xml(一般classpath为src/test/resources) -
如果该文件不存在,logback尝试寻找logback.groovy -
如果该文件不存在,logback尝试寻找logback.xml -
如果该文件不存在,logback会在META-INF下查找 [com.qos.logback.classic.spi.Configurator](http://logback.qos.ch/xref/ch/qos/logback/classic/spi/Configurator.html)接口的实现
-
如果依然找不到,则会使用默认的BasicConfigurator,导致日志直接打印到控制台,日志等级为DEBUG,日志的格式为%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
2、配置详解
2.1、configuration
-
scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -
scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -
debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
2.2 root标签
<logger>
标签,不过其是根标签;若 <logger >
或 <appender>
标签为设置输出级别时就会默认继承该标签设置的级别!
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
2.3 appender
appender
让我们的应用知道怎么打、打印到哪里、打印成什么样;而logger
则是告诉应用哪些可以这么打。例如某个类下的日志可以使用这个appender
打印或者某个包下的日志可以这么打印。
-
ConsoleAppender:把日志添加到控制台 -
FileAppender:把日志添加到文件 -
RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。它是FileAppender的子 -
additivity
属性为false,表示此logger的打印信息不再向上级传递(注:该值默认为true,logger的日志信息会依次向上级传递,最高级logger为root,如果不加则至少打印2次,本身一次,root一次)- -
level
:用来设置打印级别(TRACE
,DEBUG
,INFO
,WARN
,ERROR
,ALL
和OFF
),还有一个值INHERITED
或者同义词NULL
,代表强制执行上级的级别。如果没有设置此属性,那么当前logger
将会继承上级的级别。 -
filter
:过滤器可以通过LevelFilter
过滤器设置日志最低的打印级别 -
encoder
:可用通过Pattern
标签设置日志格式,通过charset
设置日志的字符集<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder charset="UTF-8"> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender>
2.4 变量
-
name:变量的名称 -
value:变量的值
3、logback实例
默认使用的日志框架是
logback,其由三个组件组成
-
logback-core -
logback-classic -
logback-access
<!-- Slf4j 依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<!-- logback 依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--自定义控制台日志格式-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder charset="UTF-8">
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--系统INFO级别日志-滚动记录日志-->
<appender name="SYS_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值-->
<File>sys_info.log</File>
<!--如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。-->
<append>true</append>
<!--级别过滤器(LevelFilter),此处只打INFO级别的日志-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<!--下面2个属性表示匹配规定level的接受打印,不匹配的(即非INFO)拒绝打印-->
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--设置滚动文件规则,如果直接使用 %d,默认格式是 yyyy-MM-dd-->
<fileNamePattern>sys_info.log.%d</fileNamePattern>
<!--保留30天的日志-->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--系统ERROR级别日志-滚动记录日志-->
<appender name="SYS_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>sys_error.log</File>
<append>true</append>
<!--此处只打ERROR级别的日志-->
<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>sys_error.log.%d</fileNamePattern>
<maxHistory>12</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--不同业务逻辑的日志打印到不同文件,见下面2种业务日志-->
<!--业务逻辑日志-->
<appender name="game_Appender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>D:/log/yj-test/b1.log</File>
<append>true</append>
<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>D:/log/yj-test/b1.log.%d</fileNamePattern>
<maxHistory>12</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--战斗日志-->
<appender name="fight_Appender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>D:/log/yj-test/b2.log</File>
<append>true</append>
<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>D:/log/yj-test/b2.log.%d</fileNamePattern>
<maxHistory>12</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- additivity属性为false,表示此logger的打印信息不再向上级传递(注:该值默认为true,logger的日志信息会依次向上级传递,最高级logger为root,如果不加则至少打印2次,本身一次,root一次)-->
<logger name="game" additivity="false" level="INFO">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="fight" additivity="false" level="INFO">
<appender-ref ref="fight_Appender"/>
</logger>
<!--info和error分开打印,注:ERROR > WARN > INFO > DEBUG > TRACE-->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="SYS_INFO"/>
<appender-ref ref="SYS_ERROR"/>
</root>
</configuration>
package com.pdool.logdemo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LogDemoApplication {
public static void main(String[] args) {
SpringApplication.run(LogDemoApplication.class, args);
Logger logger = LoggerFactory.getLogger(LogDemoApplication.class);
Logger gameLogger = LoggerFactory.getLogger("game");
logger.error("ccccccccccccccc");
gameLogger.error("bbbbbbbbbbb");
}
}
4、总结
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)