1 日志
1.1 什么是日志
通过日志查看程序的运行过程,运行信息,异常信息等
1.2 配置日志级别
日志记录器(Logger)的行为是分等级的。如下表所示:
分为:FATAL、ERROR、WARN、INFO、DEBUG
默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别
# 设置日志级别 logging: level: root: ERROR
这种方式能将ERROR级别以及以上级别的日志打印在控制台上
2 log4j 简介
a) log4j 是 Apache 提供的一款记录日志的工具
b) log4j既可以将日志信息打印在控制台, 也可以打印输出
到一个日志文件中.
c) log4j 可以定制日志的输出格式
d) log4j 可以定制日志级别
2.1 日志级别
2.1.1 FATAL
致命的, 表示非常严重的错误, 一般是系统错误
2.1.2 ERROR
错误, 表示代码错误, 比较严重
2.1.3 WARN
警告, 不影响程序的运行, 但是可能存在风险.
2.1.4 INFO
信息, 表示一个普通的输出信息
2.1.5 DEBUG
调试, 表示程序员人为的一些调试信息
3 log4j 的使用
3.1 导包
log4j-1.2.17.jar
log4j-api-2.0-rc1.jar
log4j-core-2.0-rc1.jar
3.2 配置文件放到src目录下(方便加载,其他目录也可)
使用一个叫 log4j.properties 的配置文件, 会设定 log4j的设置信息, 例如日志级别, 日志输出方式, 日志格式等等.
# Set root category priority to INFO and its only appender to CONSOLE. #设置根目录优先级为INFO和它的唯一附加到控制台。 log4j.rootCategory=INFO, CONSOLE #log4j.rootCategory=INFO, CONSOLE, LOGFILE # Set the enterprise logger category to FATAL and its only appender to CONSOLE. #将enterprise logger类别设置为FATAL及其惟一追加到控制台。 log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE # CONSOLE is set to be a ConsoleAppender using a PatternLayout. # CONSOLE被设置为使用PatternLayout的ConsoleAppender log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Threshold=INFO log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=- %m%n # LOGFILE is set to be a File appender using a PatternLayout. # LOGFILE被设置为使用PatternLayout的文件追加器。 log4j.appender.LOGFILE=org.apache.log4j.FileAppender log4j.appender.LOGFILE.File=axis.log log4j.appender.LOGFILE.Append=true log4j.appender.LOGFILE.Threshold=INFO log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
3.3 日志的输出格式
%c 输出日志信息所属的类的全名
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy-MM-dd HH:mm:ss },输出类似:2020-5-4- 12:10:28
%f 输出日志信息所属的类的类名
%l 输出日志事件的发生位置,即输出日志信息的语句处于它所在的类的第几行
%m 输出代码中指定的信息,如log(message)中的message
%n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL。如果是调用debug()输出的,则为DEBUG,依此类推
%r 输出自应用启动到输出该日志信息所耗费的毫秒数
%t 输出产生该日志事件的线程名
所以:
%5p [%t] (%F:%L) - %m%n 就表示宽度是5的优先等级 线程名称 (文件名:行号) - 信息 回车换行
3.4 测试代码
日志配置文件:
# Set root category priority to INFO and its only appender to CONSOLE. # log4j.rootCategory=DEBUG, CONSOLE log4j.rootCategory=DEBUG, CONSOLE, LOGFILE # CONSOLE is set to be a ConsoleAppender using a PatternLayout. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=- %m %d{yyyy-MM-dd HH:mm:ss}%n # LOGFILE is set to be a File appender using a PatternLayout. log4j.appender.LOGFILE=org.apache.log4j.FileAppender log4j.appender.LOGFILE.File=d:/test.log log4j.appender.LOGFILE.Append=true log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern=- %m %n
调用日志:
import org.apache.log4j.Logger; public class TestLog4j { public static void main(String[] args) { // 获取日志对象 Logger logger = Logger.getLogger(TestLog4j.class); // 五个日志级别分别对应五个输出方法, 方法名和级别名一致 logger.fatal("系统崩溃了..."); logger.error("发生了错误!"); logger.warn("警告!"); logger.info("消息~"); logger.debug("调试..."); } }
运行效果:
4 MyBatis 对 log4j 的支持
4.1 通过<settings>开启 log4j 的支持
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- properties加载外部文件 --> <properties resource="db.properties" /> <!-- settings标签 --> <settings> <!-- 设置MyBatis使用log4j日志支持 --> <setting name="logImpl" value="LOG4J"/> </settings> <!-- typeAliases给类型起别名 --> <typeAliases> <!-- 给User类起别名为u --> <typeAlias type="com.csdn.pojo.User" alias="u" /> <package name="com.csdn.pojo"/> </typeAliases> <environments default="dev"> <environment id="dev"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/csdn/mapper/UserMapper.xml" /> </mappers> </configuration>
4.2 日志配置文件区域选择:
<settings>用于设置 MyBatis 在运行时的行为方式, 例如:缓存, 延迟加载, 日志等.
# Set root category priority to INFO and its only appender to CONSOLE. log4j.rootCategory=ERROR, CONSOLE # log4j.rootCategory=DEBUG, CONSOLE, LOGFILE # 单独设置SQL语句的输出级别为DEBUG级别 # 方法级别 # log4j.logger.com.csdn.mapper.UserMapper.selAll=DEBUG # 类级别 # log4j.logger.com.csdn.mapper.UserMapper=DEBUG # 包级别 log4j.logger.com.csdn.mapper=DEBUG # CONSOLE is set to be a ConsoleAppender using a PatternLayout. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=- %m%n # LOGFILE is set to be a File appender using a PatternLayout. log4j.appender.LOGFILE=org.apache.log4j.FileAppender log4j.appender.LOGFILE.File=d:/test.log log4j.appender.LOGFILE.Append=true log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern=- %m %l%n
5 Logback日志
spring boot内部使用Logback作为日志实现的框架。
Logback和log4j非常相似,如果你对log4j很熟悉,那对logback很快就会得心应手。
logback相对于log4j的一些优点:https://blog.csdn.net/caisini_vc/article/details/48551287
5.1 配置logback日志
删除application.yml中的日志配置
安装idea彩色日志插件:grep console
resources 中创建 logback-spring.xml (默认日志的名字,必须是这个名字)
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="10 seconds"> <contextName>logback</contextName> <property name="log.path" value="D:/project/helen/guli_log/edu" /> <!--控制台日志格式:彩色日志--> <!-- magenta:洋红 --> <!-- boldMagenta:粗红--> <!-- cyan:青色 --> <!-- white:白色 --> <!-- magenta:洋红 --> <property name="CONSOLE_LOG_PATTERN" value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/> <!--文件日志格式--> <property name="FILE_LOG_PATTERN" value="%date{yyyy-MM-dd HH:mm:ss} |%-5level |%thread |%file:%line |%logger |%msg%n" /> <!--编码--> <property name="ENCODING" value="UTF-8" /> <!--输出到控制台--> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <!--日志级别--> <level>DEBUG</level> </filter> <encoder> <!--日志格式--> <Pattern>${CONSOLE_LOG_PATTERN}</Pattern> <!--日志字符集--> <charset>${ENCODING}</charset> </encoder> </appender> <!--输出到文件--> <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!--日志过滤器:此日志文件只记录INFO级别的--> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <!-- 正在记录的日志文件的路径及文件名 --> <file>${log.path}/log_info.log</file> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> <charset>${ENCODING}</charset> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天日志归档路径以及格式 --> <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文件保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> </appender> <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 日志过滤器:此日志文件只记录WARN级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>WARN</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <!-- 正在记录的日志文件的路径及文件名 --> <file>${log.path}/log_warn.log</file> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> <charset>${ENCODING}</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文件保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> </appender> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 日志过滤器:此日志文件只记录ERROR级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <!-- 正在记录的日志文件的路径及文件名 --> <file>${log.path}/log_error.log</file> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> <charset>${ENCODING}</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文件保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> </appender> <!--开发环境--> <springProfile name="dev"> <!--可以灵活设置此处,从而控制日志的输出--> <root level="DEBUG"> <appender-ref ref="CONSOLE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> </root> </springProfile> <!--生产环境--> <springProfile name="pro"> <root level="ERROR"> <appender-ref ref="ERROR_FILE" /> </root> </springProfile> </configuration>
5.2 节点说明
- <property>:定义变量
- <appender>:定义日志记录器
- <filter>:定义日志过滤器
- <rollingPolicy>:定义滚动策略
- <springProfile>:定义日志适配的环境
- <root>:根日志记录器
5.3 控制日志级别
通过在开发环境设置以下<root>节点的 level 属性的值,调节日志的级别
<!--开发环境--> <springProfile name="dev"> <!--可以灵活设置此处,从而控制日志的输出--> <root level="DEBUG"> <appender-ref ref="CONSOLE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> </root> </springProfile>
在controller的listAll方法中输出如下日志,调节日志级别查看日志开启和关闭的效果
log.info("所有讲师列表....................");
6 错误日志处理
6.1 用日志记录器记录错误日志
GlobalExceptionHandler.java 中
类上添加注解 @Slf4j
修改异常输出语句
//e.printStackTrace(); log.error(e.getMessage());
6.2 输出日志堆栈信息
为了保证日志的堆栈信息能够被输出,我们需要定义工具类
import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; public class ExceptionUtils { public static String getMessage(Exception e) { StringWriter sw = null; PrintWriter pw = null; try { sw = new StringWriter(); pw = new PrintWriter(sw); // 将出错的栈信息输出到printWriter中 e.printStackTrace(pw); pw.flush(); sw.flush(); } finally { if (sw != null) { try { sw.close(); } catch (IOException e1) { e1.printStackTrace(); } } if (pw != null) { pw.close(); } } return sw.toString(); } }
common_util中创建ExceptionUtil.java工具类
修改异常输出语句
//e.printStackTrace(); //log.error(e.getMessage()); log.error(ExceptionUtils.getMessage(e));
7 日志实例模板
public void info(String format, Object... arguments);
支持多个参数的参数化log方法,对比上面的俩个方法来说,会多增加构造一个Object[]的开销。例子:
logger.info("在配置文件[{}]中读取到配置项[{}]的值为[{}]","/somePath/config.properties","maxSize", 5);
输出
2021-08-11 23:36:17,789 [ main ] INFO c.j.training.logging.service.UserService - 在配置文件 [ /somePath/config.properties ]中读取到配置项 [ maxSize ]的值为 [ 5 ]