我是靠谱客的博主 风趣水池,最近开发中收集的这篇文章主要介绍springboot学习(五十四) springboot中记录审计/访问日志,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在web项目中记录每个接口的访问信息做审计是很重要的,下面介绍使用log4j2+拦截器将日志记录到日志文件的一种方式。

1、编写记录日志实体类AccessLog

package com.iscas.biz.model.common.access;

import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Date;

/**
 * 访问日志的实体
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/8/29 20:37
 * @since jdk1.8
 */
@Data
@Accessors(chain = true)
public class AccessLog {

    /**访问用户*/
    private String username = "unknown";

    /**uri*/
    private String uri;

    /**访问时长*/
    private Long duration;

    /**请求方式*/
    private String method;

    /**客户端IP*/
    private String ip;

    /**状态码*/
    private int status;

    /**时间*/
    private Date createTime;

}

2、编写拦截器

这里在preHandle中构建基础AccessLog的属性和请求时间并将它们绑定到request中,在postHandle中从request中取出AccessLog并设置访问耗时、访问用户等属性,注意:这里的访问用户的获取方式是我项目中的方式,根据实际情况要做修改。
设置完所有AccessLog的属性后,使用log.debug输出日志。

package com.iscas.biz.config.log;

import com.iscas.base.biz.model.auth.AuthContext;
import com.iscas.base.biz.util.AuthContextHolder;
import com.iscas.base.biz.util.SpringUtils;
import com.iscas.biz.model.common.access.AccessLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * 访问/审计日志
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/8/29 20:42
 * @since jdk1.8
 */
@Slf4j
public class AccessLogInterceptor implements HandlerInterceptor {

    /**访问开始时间*/
    private static final String KEY_REQUEST_START_TIME = "KEY_REQUEST_START_TIME";

    /**访问开始时间*/
    private static final String KEY_ACCESS_LOG = "KEY_ACCESS_LOG";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        AccessLog accessLog = new AccessLog();
        accessLog.setIp(SpringUtils.getIpAddr())
                .setMethod(request.getMethod())
                .setUri(request.getRequestURI());

        //将信息绑定在request中
        request.setAttribute(KEY_REQUEST_START_TIME, System.currentTimeMillis());
        request.setAttribute(KEY_ACCESS_LOG, accessLog);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                            @Nullable ModelAndView modelAndView) throws Exception {
        AccessLog accessLog = (AccessLog) request.getAttribute(KEY_ACCESS_LOG);
        Long startTime = (Long) request.getAttribute(KEY_REQUEST_START_TIME);
        if (accessLog != null) {
            Date createTime = new Date();
            AuthContext context = AuthContextHolder.getContext();
            accessLog.setCreateTime(createTime)
                    .setDuration(createTime.getTime() - startTime)
                    .setStatus(response.getStatus())
                    .setUsername(context == null ? null : context.getUsername());
            log.debug(accessLog.toString());
        }
    }
}

3、注册拦截器

package com.iscas.biz.config;

import com.iscas.biz.config.log.AccessLogInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/8/29 21:02
 * @since jdk1.8
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加拦截器,配置拦截地址
        registry.addInterceptor(new AccessLogInterceptor())
                .addPathPatterns("/**");
//                .excludePathPatterns("/login","/userLogin")
//                .excludePathPatterns("/image/**");
    }
}

4、配置log4j2对审计日志的支持
log4j2的配置方式见上一篇文章介绍:https://blog.csdn.net/u011943534/article/details/119876319

在上一篇的配置基础上,添加审计日志的RollingFile,日志级别为debug

<!--访问日志-->
        <RollingFile name="accessAppender"
                     fileName="${FILE_PATH}/${FILE_NAME}/log_access.log"
                     filePattern="${FILE_PATH}/${FILE_NAME}/access/log-access-%d{yyyy-MM-dd}_%i.log.gz"
                     append="true">
            <!--设置日志格式-->
            <PatternLayout pattern="${ACCESS_LOG_PATTERN}" charset="UTF-8"/>
            <Filters>
                <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>
            <Policies>
                <!-- 基于时间的触发策略。该策略主要是完成周期性的log文件封存工作。有两个参数:
               interval,integer型,指定两次封存动作之间的时间间隔。单位:以日志的命名精度来确定单位,
                   比如yyyy-MM-dd-HH 单位为小时,yyyy-MM-dd-HH-mm 单位为分钟
               modulate,boolean型,说明是否对封存时间进行调制。若modulate=true,
                   则封存时间将以0点为边界进行偏移计算。比如,modulate=true,interval=4hours,
                   那么假设上次封存日志的时间为00:00,则下次封存日志的时间为04:00,
                   之后的封存时间依次为08:00,12:00,16:00-->
                <TimeBasedTriggeringPolicy interval="1"/>
                <SizeBasedTriggeringPolicy size="10MB"/>
            </Policies>

            <!-- DefaultRolloverStrategy 属性如不设置,则默认为最多同一文件夹下当天 7 个文件后开始覆盖-->
            <DefaultRolloverStrategy max="30">
                <!-- 删除处理策略,在配置的路径中搜索,maxDepth 表示往下搜索的最大深度 -->
                <Delete basePath="${FILE_PATH}/${FILE_NAME}/" maxDepth="2">
                    <!-- 文件名搜索匹配,支持正则 -->
                    <IfFileName glob="*.log.gz"/>
                    <!--!Note: 这里的 age 必须和 filePattern 协调, 后者是精确到 dd, 这里就要写成 xd, xD 就不起作用
                    另外, 数字最好 >2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!-->
                    <!--7天-->
                    <IfLastModified age="7d"/>
                </Delete>
            </DefaultRolloverStrategy>

        </RollingFile>

ACCESS_LOG_PATTERN的格式如下:

<!--变量配置-->
    <properties>
        <!-- 格式化输出:%date 表示日期,%thread 表示线程名,%-5level:级别从左显示 5 个字符宽度 %msg:日志消息,%n 是换行符-->
        <!-- %logger{36} 表示 Logger 名字最长 36 个字符 -->
        <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [%logger{50}:%L] - %msg%n"/>
        <property name="LOG_CONSOLE_PATTERN" value="%style{%d{ISO8601}}{bright,green} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C{}}{bright,yellow}: %msg%n%style{%throwable}{red}"/>
        <property name="ACCESS_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} - %msg%n"/>

        <!-- 定义日志存储的路径 -->
        <property name="FILE_PATH" value="logs"/>
        <property name="FILE_NAME" value="newframe"/>
    </properties>

将拦截器类单独配置一个Logger:

		<AsyncLogger name="com.iscas.biz.config.log.AccessLogInterceptor" level="debug" includeLocation="true" additivity="false">
            <AppenderRef ref="accessAppender"/>
            <AppenderRef ref="consoleAppender"/>
        </AsyncLogger>

大功告成,看下我生成的access_log.log文件:

2021-08-29 21:11:36.822 - AccessLog(username=null, uri=/demo/ttt, duration=7, method=GET, ip=0:0:0:0:0:0:0:1, status=404, createTime=Sun Aug 29 21:11:36 CST 2021)
2021-08-29 21:11:39.639 - AccessLog(username=null, uri=/demo/404, duration=23, method=GET, ip=0:0:0:0:0:0:0:1, status=404, createTime=Sun Aug 29 21:11:39 CST 2021)

最后

以上就是风趣水池为你收集整理的springboot学习(五十四) springboot中记录审计/访问日志的全部内容,希望文章能够帮你解决springboot学习(五十四) springboot中记录审计/访问日志所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部