前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

原文链接:https://blog.csdn.net/MeituanTech/article/details/120340493

1、系统日志和操作日志的区别

1.1、系统日志:

系统日志主要是为开发排查问题提供依据,一般打印在日志文件中;系统日志的可读性要求没那么高,日志中会包含代码的信息,比如在某个类的某一行打印了一个日志。

1.2、操作日志:

主要是对某个对象进行新增操作或者修改操作后记录下这个新增或者修改,操作日志要求可读性比较强,因为它主要是给用户看的,比如订单的物流信息,用户需要知道在什么时间发生了什么事情。再比如,客服对工单的处理记录信息。

1.3.2、操作日志的记录格式

大概分为下面几种:

1、单纯的文字记录,比如:2021-09-16 10:00 订单创建。

2、简单的动态的文本记录,比如:2021-09-16 10:00 订单创建,订单号:NO.11089999,其中涉及变量订单号“NO.11089999”。

3、修改类型的文本,包含修改前和修改后的值,比如:2021-09-16 10:00 用户小明修改了订单的配送地址:从“金灿灿小区”修改到“银盏盏小区” ,其中涉及变量配送的原地址“金灿灿小区”和新地址“银盏盏小区”。

4、修改表单,一次会修改多个字段。

2、操作日志如何和系统日志区分开

2.1、log4j2.xml

<logger name="businessLog" additivity="false" level="INFO">
  <appender-ref ref="businessLog"/>
</logger>
<?xml version="1.0" encoding="UTF-8"?>

<!--status  Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,
 你会看到log4j2内部各种详细输出。可以设置成OFF(关闭)或Error(只输出错误信息)-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="error" monitorInterval="30">
    <!--    %d{yyyy-MM-dd HH:mm:ss, SSS} : 日志生产时间-->
    <!--    %p : 日志输出格式-->
    <!--    %thread表示线程名,-->
    <!--    %c : logger的名称-->
    <!--    %m : 日志内容,即 logger.info("message")-->
    <!--    %n : 换行符-->
    <!--    %C : Java类名-->
    <!--    %L : 日志输出所在行数-->
    <!--    %M : 日志输出所在方法名-->
    <!--    hostName : 本地机器名-->
    <!--    hostAddress : 本地ip地-->

    <!-- 日志文件目录和压缩文件目录配置 -->
    <Properties>
        <Property name="level">debug</Property>
        <Property name="LOG_PATTERN">
            %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level -[%-32X{REQ_UID}]- %msg%xEx %logger{36}.%M[%L]%n
        </Property>

        <Property name="logDri">/Users/healerjean/Desktop/logs</Property>
        <Property name="logFileName">hlj-client</Property>

        <Property name="infoLogDri">${logDri}/info</Property>
        <Property name="infoLogGz">${infoLogDri}/gz</Property>
        <Property name="infoLogFileName">${logFileName}.log</Property>

        <Property name="errorLogDri">${logDri}/error</Property>
        <Property name="errorLogGz">${errorLogDri}/gz</Property>
        <Property name="errorLogFileName">${logFileName}.error</Property>


        <Property name="businessLogDri">${logDri}/business</Property>
        <Property name="businessLogGz">${businessLogDri}/gz</Property>
        <Property name="businessLogFileName">${logFileName}.bus.log</Property>
    </Properties>

    <appenders>
        <console name="Console" target="SYSTEM_OUT">
            <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
            <ThresholdFilter level="${level}" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
            <!--输出日志的格式-->
            <PatternLayout pattern="${LOG_PATTERN}"/>
        </console>


        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingRandomAccessFile name="infoFile" fileName="${infoLogDri}/${infoLogFileName}"
                                 filePattern="${infoLogGz}/${date:yyyy-MM}/%d{yyyy-MM-dd}-%i.${infoLogFileName}.gz">
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!-- 基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小 -->
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <!-- 基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour -->
                <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
            </Policies>
            <Filters>
                <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)
                onMatch属性设置为DENY,过滤掉高等级的日志;onMismatch设置为NEUTRAL,把低等级的日志放行,
                -->
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <!-- 指定每天(文件夹是以天的,看上面的)的最大压缩包个数,默认7个,超过了会覆盖之前的(用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)) -->
            <DefaultRolloverStrategy max="2000"/>
        </RollingRandomAccessFile>


        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
        <RollingRandomAccessFile name="errorFile" fileName="${errorLogDri}/${errorLogFileName}"
                                 filePattern="${errorLogGz}/${date:yyyy-MM}/%d{yyyy-MM-dd}-%i.${errorLogFileName}.gz">
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!-- 基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小 -->
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <!-- 基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour -->
                <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
            </Policies>
            <Filters>
                <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)
                onMatch属性设置为DENY,过滤掉高等级的日志;onMismatch设置为NEUTRAL,把低等级的日志放行,
                -->
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <!-- 指定每天(文件夹是以天的,看上面的)的最大压缩包个数,默认7个,超过了会覆盖之前的(用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)) -->
            <DefaultRolloverStrategy max="2000"/>
        </RollingRandomAccessFile>


        <!--操作日志-->
        <RollingRandomAccessFile name="businessLog" fileName="${businessLogDri}/${businessLogFileName}"
                                 filePattern="${businessLogGz}/${date:yyyy-MM}/%d{yyyy-MM-dd}-%i.${businessLogFileName}.gz">
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="500 MB"/>
                <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
            </Policies>
            <Filters>
                <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <DefaultRolloverStrategy max="2000"/>
        </RollingRandomAccessFile>


    </appenders>


    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <loggers>
        <!-- AsyncRoot - 异步记录日志 - 需要LMAX Disruptor的支持 -->
        <!-- additivity如果设置为true将会输出两次日志,意思和log4j里面意思是否追加 -->
        <AsyncRoot level="${level}" additivity="false" includeLocation="true">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="infoFile"/>
            <AppenderRef ref="errorFile"/>
        </AsyncRoot>

        <logger name="businessLog" additivity="false" level="INFO">
            <appender-ref ref="businessLog"/>
        </logger>
    </loggers>

</configuration>

2.2、样例

@Slf4j
@Service
public class BusinessLogService {

    private static final Logger BUSINESS_LOG = LoggerFactory.getLogger("businessLog");

    @Test
    public void test(){
        BUSINESS_LOG.info("业务日志");
        log.debug("INFO 系统日志");
        log.info("INFO 系统日志");
        log.error("ERROR 系统日志");
    }

}

3、注解操作日志

3.1、动态模板

一提到动态模板,就会涉及到让变量通过占位符的方式解析模板,从而达到通过注解记录操作日志的目的。模板解析的方式有很多种,这里使用了 SpEL(Spring Expression Language,Spring表达式语言)来实现。我们可以先写下期望的记录日志的方式,然后再看下能否实现这样的功能。

ContactAuthor