一、为什么要使用日志框架?
-
调试: 开发过程中,输出的日志便于记录程序在之前的运行结果,可以方便地知道当前程序的运行状态。
-
错误定位: 项目在运行一段时候后,可能由于数据问题,网络问题,内存问题等出现异常,这时日志可以帮助开发或者运维人员快速定位错误位置,尽快找到解决方案。
-
数据分析: 大数据的兴起,使得大量的日志分析成为可能,日志中蕴含了大量的用户数据,包括点击行为,兴趣偏好等,用户画像对于公司下一步的战略方向有一定指引作用。
二、常用日志相关的框架有哪些?
1、日志框架及相关优先级介绍
日志框架名称 | 日志等级及优先级 |
---|---|
Logback | ALL < TRACE < DEBUG < INFO < WARN < ERROR < OFF |
Log4j2 | ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF |
log4js、debugout.js等等…
2、日志等级介绍及使用场景
( 1 )ALL
最低等级的,用于打开所有日志记录(包括自定义的级别)。
( 2 )TRACE
用于展现程序执行的轨迹,如函数间的相互调用关系,函数的参数和返回值等现场信息。很低的日志级别,通常不会使用。
( 3 )DEBUG
指出细粒度信息事件,对调试应用程序是非常有帮助的,主要用于开发过程当中打印一些运行信息。
( 4 )INFO
在粗粒度级别上突出强调应用程序的运行过程。打印一些重要的信息,这个能够用于生产环境中输出程序运行的一些重要信息。(程序入口相关参数、计算结果)
( 5 )WARN
表明会出现潜在错误的情形。(某个不常走到的分支,对于常规的操作是不应该打印WARN日志的,只有在满足某个条件才能走到的分支,且这个分支引起了“警觉”,此时就应该打印WARN日志。)
( 6 )ERROR
表明出现了系统错误和异常,无法正常完成目标操作。(调用API的方法时有异常抛出,而且异常无法处理并影响业务功能时使用)
( 7 )FATAL
指出严重的错误事件将会导致应用程序的退出。(Logback无)
( 8 )OFF
最高等级的,用于关闭所有日志记录(包括自定义的级别)。
3、日志级别的作用
开发人员可通过相关的配置改变是否记录相关级别的日志信息。
例如:日志级别配置为INFO,则表示低于INFO级别(TRACE、DEBUG)的日志信息不会被记录。
三、如何使用相关日志框架?
前提:基于Spring Boot的Maven项目实践演示。
Github:https://github.com/liumingjun2018/LogDemoForJava
1、LogBack使用步骤
( 1 )注入依赖
特别说明:根据Spring Boot官方文档中说明:当引入spring-boot-starter-web时,也就自动引入了Logback,并且在没有其它声明的情况下,它会默认启动Logback作为输出手段,默认级别设置为INFO。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
( 2 )配置文件(命名为logback-test.xml)
根节点configuration下有两个属性,三个节点。
两个属性:
- contextName( 上下文名称)- 0个或多个
- property(变量设置)- 0个或多个
三个节点:
-
appender(负责写日志的组件)- 0个或多个
- filter(级别过滤器,有LevelFilter、EvaluatorFilter和ThresholdFilter三种过滤方式)
- rollingPolicy (用来设置日志的滚动策略,当达到条件后会自动将条件前的日志生成一个备份日志文
- triggeringPolicy(日志触发器策略,常用的是日志的大小的控制,当日志达到对应的大小的时候,就会触发,生成新的日志文件。)
- encoder(负责把对记录事件进行格式化)
-
root(配置根记录器,它支持单个属性,即level属性)- 最多一个
- appender-ref(引用的每个 appender 都被添加到root中)
-
logger(用来设置某一个包或者具体的某一个类的日志打印级别)- 0个或多个
- appender-ref(引用的每个 appender 都被添加到logger中)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--配置控制台的输出-->
<appender name="consolelog" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern> [%p] [%d] - %msg%n</pattern>
</layout>
</appender>
<!--文件输出info及以上级别并过滤掉ERROR日志的配置-->
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--筛选的级别有三种 DENY ACCEPT NEUTRAL 禁止,接受和中立 具体看类 filterReply-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--设置权限-->
<level>ERROR</level>
<!--命中-->
<onMatch>DENY</onMatch>
<!--未命中-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<encoder>
<pattern>
[%p] [%d] - %msg%n
</pattern>
</encoder>
<!--滚动策略 按照时间来滚动 每日创建一个日志文件-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/%d-Logback/fileInfoLog.log</fileNamePattern>
</rollingPolicy>
</appender>
<!--文件输出error日志的配置-->
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--为了在error日志中没有info日志,所以我们设置一个过滤器 记住是ThresholdFilter,不是levelFilter-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<encoder>
<pattern>
[%p] [%d] - %msg%n
</pattern>
</encoder>
<!--滚动策略 按照时间来滚动-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/%d-Logback/fileErrorLog.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<root level="info">
<appender-ref ref="consolelog" />
<appender-ref ref="fileInfoLog" />
<appender-ref ref="fileErrorLog" />
</root>
</configuration>
2、Log4j2使用步骤
( 1 )注入依赖
特别说明:SLF4J API 旨在一次绑定一个且仅只能绑定一个底层日志记录框架,所以需要将上述的logback依赖移除后添加log4j2依赖。
什么是SLF4J?
Simple Logging Facade for Java(SLF4J)用作各种日志框架(例如java.util.logging,logback,log4j)的简单外观或抽象,允许最终用户在部署时插入所需的日志记录框架。SLF4J只是一个外观,这意味着它不提供完整的日志记录解决方案。使用SLF4J无法执行配置appender或设置日志记录级别等操作。
详情请参阅http://www.51gjie.com/javaweb/1121.html
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!-- 移除logback -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 使用log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
( 2 )配置文件(命名为log4j2.xml)
根节点configuration下有两个属性,三个节点。
两个属性:
- status(用来指定log4j本身的打印日志的级别)
- monitorinterval(用于指定自动重新配置的监测间隔时间,单位是s,最小是5s)
两个节点:
- Appenders(负责写日志的组件)
- Console(用来定义输出到控制台的Appender)
- name:指定Appender的名字;
- target:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT;
- PatternLayout:输出格式,不设置默认为:%m%n;
- File(用来定义输出到指定位置的文件的Appender)
- name:指定Appender的名字;
- fileName:指定输出日志的目的文件带全路径的文件名;
- PatternLayout:输出格式,不设置默认为:%m%n;
- RollingFile(用来定义超过指定大小自动删除旧的创建新的的Appender)
- name:指定Appender的名字;
- fileName:指定输出日志的目的文件带全路径的文件名;
- PatternLayout:输出格式,不设置默认为:%m%n;
- filePattern:指定新建日志文件的名称格式;
- Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志;
- TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am…而不是7am;
- SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小;
- DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。
- Console(用来定义输出到控制台的Appender)
- Loggers
- Root(用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出)
- level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF;
- AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender;
- Logger(用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等)
- level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF;
- name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点;
- AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.如果指定了,那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity="false"只在自定义的Appender中进行输出。
- Root(用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出)
日志文件内容的格式
%c 输出所属类的全名;
%d 输出日志时间其格式为 %d{yyyy-MM-dd HH:mm:ss,SSS},可指定格式 如 %d{HH:mm:ss};
%l 输出日志事件发生位置,包括类目名、发生线程,在代码中的行数;
%n 换行符;
%m 输出代码指定信息,如info(“message”),输出message;
%p 输出优先级,即 FATAL ,ERROR 等;
%r 输出从启动到显示该log信息所耗费的毫秒数;
%t 输出产生该日志事件的线程名;
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="off" monitorInterval="30">
<Properties>
<property name="filePattern">${date:yyyy-MM-dd}</property>
</Properties>
<!--先定义所有的appender-->
<appenders>
<!--这个输出控制台的配置-->
<console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%p] - %l - %m%n" />
</console>
<File name="FileAppender" fileName="logs/${filePattern}-Log4j2/allFileLog.log" append="false">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] - %l - %m%n" />
</File>
<!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档.filePattern指定新建日志文件的名称格式 -->
<RollingFile name="RollingFileInfo" fileName="logs/${filePattern}-Log4j2/infoFileLog.log" append="false" filePattern="/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" />
<!-- Policies指定滚动日志的策略,就是什么时候进行新建日志文件输出日志 -->
<Policies>
<!-- 基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1hour。modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am...而不是7am. -->
<TimeBasedTriggeringPolicy />
<!-- 基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小 -->
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
</RollingFile>
<RollingFile name="RollingFileWarn" fileName="logs/${filePattern}-Log4j2/warnFileLog.log" append="false" filePattern="/logs/$${date:yyyy-MM-dd}/warn-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
<!-- DefaultRolloverStrategy用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
<DefaultRolloverStrategy max="20" />
</RollingFile>
<RollingFile name="RollingFileError" fileName="logs/${filePattern}-Log4j2/errorFileLog.log" append="false" filePattern="logs/$${date:yyyy-MM-dd}/error-%d{yyyy-MM-dd}-%i.log">
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
</RollingFile>
</appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<loggers>
<!-- Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别 -->
<!--过滤掉spring一些无用的DEBUG信息-->
<logger name="org.springframework" level="off"></logger>
<root level="warn">
<!-- appender-ref用来指定该日志输出到哪个Appender. -->
<appender-ref ref="Console" />
<appender-ref ref="FileAppender" />
<appender-ref ref="RollingFileInfo" />
<appender-ref ref="RollingFileWarn" />
<appender-ref ref="RollingFileError" />
</root>
</loggers>
</configuration>
3、log4js演示
基于nodejs项目演示
4、debugout.js演示
基于angular项目演示
四、注意事项
合理选择日志级别,避免打印过多日志,不仅占用资源,而且定位问题变得越发困难。