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)

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot提供了一个功能强大的审计框架,可以通过restful API请求来监管、审计和收集应用的运行情况。通过使用自定义注解类、AOP切面类、业务类和控制器,可以轻松实现审计功能。如果想要自定义的端点生效,需要在启动类添加一个必要的Bean,并将自定义端点交由Spring进行管理。具体的代码实现可以根据项目的具体需求进行定制。 总结起来,Spring Boot的审计功能可以通过自定义注解类、AOP切面类、业务类和控制器来实现,同时需要在启动类添加必要的Bean来使自定义端点生效。这样就可以通过restful API请求来监管、审计和收集应用的运行情况。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Spring Boot —— Actuator 监控、检测、审计、应用情况采集](https://blog.csdn.net/Cy_LightBule/article/details/94365823)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [【日常补录】springboot使用spring的AOP实现审计日志功能](https://blog.csdn.net/huang_550/article/details/122576219)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值