最近有用到了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,发现网上那堆东西都跑不通。然后就走起了打开依赖包的狗血之路

springboot TDengine 轨迹_xml

       显然,你们是看到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>

已经用在生产环境,如果有什么疑问或问题,欢迎指出一起讨论