最近有用到了springboot下需要日志的需求,然后就顺带做个笔记,正常操作,直接上代码
一、关于日志的基本知识:
目录
一、关于日志的基本知识:
格式与注意:
不同级别使用:
二、基本配置
①单一日志部分:
1、pom.xml
2、打开哥们的spring-boot-1.X.X.RELEASE.jar
4、按时间自动滚动的日志文件:
5、测试
0、application.yml配置
二、logback相关配置说明:
根节点 configuration 结构:
设置上下文名称:contextName
设置变量: property
获取时间戳字符串:
打日志的方式:之前,我们需要知道什么时候需要打日志,打的有格式,有逻辑,而不能像开始入门一样随便是不是都打日志,过分的日志会适得其反
什么时候打日志:
1、当你遇到问题的时候,只能通过debug功能来确定问题,你应该考虑打日志,良好的系统,是可以通过日志进行问题定为的。
3、经常以功能为核心进行开发,你应该在提交代码前,可以确定通过日志可以看到整个流程
格式与注意:
1、最基本的:(利用了{}作参数隔离,可读性高)
logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol);
2、对于Debug的日志,必须先判断再打:
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " +id + " symbol: " + symbol);
}
不要进行字符串拼接,那样会产生很多String对象,占用空间,影响性能。(反例)
logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
不同级别使用:
ERROR:
影响到程序正常运行、当前请求正常运行的异常情况:
1、打开配置文件失败
2、所有第三方对接的异常(包括第三方返回错误码)
3、所有影响功能使用的异常,包括:SQLException和除了业务异常之外的所有异常(RuntimeException和Exception)
如果进行了抛出异常操作,请不要记录error日志,由最终处理方进行处理:
反例(不要这么做):
try{
....
}catch(Exception ex){
String errorMessage=String.format("Error while reading information of user [%s]",userName);
logger.error(errorMessage,ex);
throw new UserServiceException(errorMessage,ex);
}
WARN
不应该出现但是不影响程序、当前请求正常运行的异常情况:
1、有容错机制的时候出现的错误情况
2、找不到配置文件,但是系统能自动创建配置文件
当接口抛出业务异常时,应该记录此异常,或者某值接近临界值的时候;
INFO
一般系统运行信息
1、Service方法中对于系统/业务状态的变更
2、主要逻辑中的分步骤
外部接口部分
1、客户端请求参数(REST/WS)
2、调用第三方时的调用参数和调用结果
说明:
1、 并不是所有的service都进行出入口打点记录,单一、简单service是没有意义的(job除外,job需要记录开始和结束,)。
反例(不要这么做):
public List listByBaseType(Integer baseTypeId) {
log.info("开始查询基地");
BaseExample ex=new BaseExample();
BaseExample.Criteria ctr = ex.createCriteria();
ctr.andIsDeleteEqualTo(IsDelete.USE.getValue());
Optionals.doIfPresent(baseTypeId, ctr::andBaseTypeIdEqualTo);
log.info("查询基地结束");
return baseRepository.selectByExample(ex);
}
2、 对于复杂的业务逻辑,需要进行日志打点,以及埋点记录,比如电商系统中的下订单逻辑,以及OrderAction操作(业务状态变更)。
3、对于整个系统的提供出的接口(REST/WS),使用info记录入参
4、如果所有的service为SOA架构,那么可以看成是一个外部接口提供方,那么必须记录入参。
5、 调用其他第三方服务时,所有的出参和入参是必须要记录的(因为你很难追溯第三方模块发生的问题)
DEBUG
1、可以填写所有的想知道的相关信息(但不代表可以随便写,debug信息要有意义,最好有相关参数)
2、生产环境需要关闭DEBUG信息
3、如果在生产情况下需要开启DEBUG,需要使用开关进行管理,不能一直开启。
如何使用Logback————————————————————
二、基本配置
①单一日志部分:
1、pom.xml
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
2、打开哥们的spring-boot-1.X.X.RELEASE.jar
开始是想用到log4j,发现网上那堆东西都跑不通。然后就走起了打开依赖包的狗血之路
显然,你们是看到log4j2的,然而我尝试过一次就搜索不行,这东西就得自己玩另一个(既然有)
然后认真的老铁会发现,其实两个的构成是相似的
4、按时间自动滚动的日志文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<!-- 按照时间滚动 -->
<appender name="TIME_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i</fileNamePattern>
<maxHistory>365</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="TIME_FILE" />
</root>
</configuration>
4.1参数意味
%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
%r: 输出自应用启动到输出该log信息耗费的毫秒数
%c: 输出日志信息所属的类目,通常就是所在类的全名
%t: 输出产生该日志事件的线程名
%l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main (TestLog4.Java:10)
%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像Java servlets这样的多客户多线程的应用中。
%%: 输出一个"%"字符
%F: 输出日志消息产生时所在的文件名称
%L: 输出代码中的行号
%m: 输出代码中指定的消息,产生的日志具体信息 %n: 输出一个回车换行符,Windows平台为"/r/n",Unix平台为"/n"输出日志信息换行
%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式
5、测试
private static final Logger logger = LoggerFactory.getLogger(AdminServiceImpl.class);
//AdminServiceImpl是一个类名
方法内填入:其中{}是为了填入后面的参数,会自动填入的,有多少个{}自定义,就应该加入多少个参数在后面。
logger.info("method : {} ",MethodList.AdminModfiy,"updateSysUser--username:"+sysUser.getUsername());
测试方法:
结果:
2017-12-04 12:27:19.709 INFO 9392 --- [nio-8088-exec-5] com.**.service.impl.AdminServiceImpl : method : 1
0、application.yml配置
logging:
path: /Users/coffeeandice/temp/ #文件存放的目录
pattern:
file: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n" //配置文件后缀,默认名字是spring.log
level:
com.coffeeandice.dao: DEBUG // 监听某个位置的日志 ,当然也可以不写类,默认全部的debug
file:User #日志文件名称
②多日志切割
在这里我暂时到目前为止没有看到好的文档说介绍 附上官网 ,故而继续使用logback配置文件的方式
其实springboot ,内部本身就存在logback继承,你只需要排除额外的影响logger包避免冲突即可
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<property name="LOG_FILE" value="Users/WorkOpt/one"/>
<property name="OPT_FILE" value="Users/WorkOpt/Opt/two" />
<!-- 按照时间滚动 -->
<appender name="TIME_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n</pattern>
</encoder>
<file>${LOG_FILE}/spring.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}/%d{yyyy-MM-dd}/spring.log.%d{yyyy-MM-dd}-%i.gz</fileNamePattern>
<maxHistory>365</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100mb</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<appender name="OPT_RECORD_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd} - %d{HH:mm:ss.SSS} %msg%n</pattern>
</encoder>
<file>${OPT_FILE}/spring.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${OPT_FILE}/%d{yyyy-MM-dd}/os_node.%d{yyyy-MM-dd}-%i.txt.gz</fileNamePattern>
<maxHistory>365</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100mb</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<logger name="com.coffeeandice.os.aop.test" level="INFO" additivity="false">
<appender-ref ref="OPT_RECORD_FILE"/>
<appender-ref ref="CONSOLE"/>
</logger>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="TIME_FILE"/>
</root>
</configuration>
其实作用的是logger,主要用于监听我指定的类,这个类我用于切面截取日志,下面的appender-ref则是调用不同的方式,这样,就产生相应2个日志输出点。
③logback相关配置说明:
一:根节点<configuration>包含的属性:
scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 其他配置省略-->
</configuration>
根节点 configuration 结构:
configuration
|
————————————--
| | |
appender logger root
设置上下文名称:contextName
每个logger都关联到logger上下文,默认上下文名称为default。但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改。
<!-- lang: xml-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>myAppName</contextName>
<!-- 其他配置省略-->
</configuration>
设置变量: property
用来定义变量值的标签,<property>
有两个属性name和value;
- name: 变量的名称
- value: 的值时变量定义的值。
通过<property>
定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。
例如使用<property>
定义上下文名称,然后在<contentName>
设置logger上下文时使用。
<!-- lang: xml-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="APP_Name" value="myAppName" />
<contextName>${APP_Name}</contextName>
<!-- 其他配置省略-->
</configuration>
获取时间戳字符串:<timestamp>
- key: 标识此
<timestamp>
的名字; - datePattern: 设置将当前时间(解析配置文件的时间)转换为字符串的模式,遵循java.txt.SimpleDateFormat的格式。
例如将解析配置文件的时间作为上下文名称
<!-- lang: xml-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
<contextName>${bySecond}</contextName>
<!-- 其他配置省略-->
</configuration>
已经用在生产环境,如果有什么疑问或问题,欢迎指出一起讨论