Spring boot审计日志2:使用AppenderBase实现日记采集log.info

1.使用方式

和正常的log.info一样使用,根据规定好的格式判定日志采集

2.日志拦截

实现AuditLogAppender类,获取日志信息进行处理。原理是继承AppenderBase类,可以拦截info打印的日志,然后判断是否审计日志,处理日志信息。

package com.dehua.aop;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import com.alibaba.fastjson.JSON;
import com.dehua.entity.AuditLogDO;
import com.dehua.util.CommonConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * 自定义日志采集
 *
 * @param <E>
 */
@Slf4j
@Component
public class AuditLogAppender<E> extends AppenderBase<E> implements ApplicationContextAware {

    private static AuditLogService auditLogService;

    @Override
    protected void append(E eventObject) {
        try {
            // 获取日志
            if (eventObject instanceof ILoggingEvent) {
                ILoggingEvent event = (ILoggingEvent) eventObject;
                String message = event.getMessage();
                if (!Objects.equals(message, CommonConstants.AUDIT_LOG_INFO)) {
                    return;
                }

                Object[] argumentArray = event.getArgumentArray();

                String methodName = "unknown";
                String className = "unknown";

                StackTraceElement[] callerDataArray = event.getCallerData();
                if (null != callerDataArray && callerDataArray.length > 0) {
                    StackTraceElement callerData = callerDataArray[0];
                    methodName = callerData.getMethodName();
                    className = callerData.getClassName();
                }

                String auditName = argumentArray[0]+"";
                String auditNo = argumentArray[1]+"";
                String auditType = argumentArray[2]+"";
                Object paramJson = argumentArray[3];
                Object resultJson = argumentArray[4];

                AuditLogDO auditLogDO = AuditLogFactory.buildAuditLogDO(auditName, auditNo, auditType,
                        className, methodName, JSON.toJSONString(paramJson), JSON.toJSONString(resultJson));

                //log.info(JSON.toJSONString(auditLogDO));
                //简单处理,插入数据库
                auditLogService.save(auditLogDO);
            }
        } catch (Exception e) {
            log.error("审计日志采集异常 e:", e);
        }
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        auditLogService = applicationContext.getAutowireCapableBeanFactory().getBean(AuditLogService.class);
    }
}

日志工厂类AuditLogFactory

package com.dehua.aop;

import com.alibaba.fastjson.JSON;
import com.dehua.entity.AuditLogDO;
import com.dehua.util.CommonJoinPointUtil;
import com.dehua.util.HttpServletUtil;
import lombok.extern.slf4j.Slf4j;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.aspectj.lang.JoinPoint;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Map;

@Slf4j
public class AuditLogFactory {

    private AuditLogFactory() {
    }

    public static AuditLogDO buildAuditLogDO(JoinPoint joinPoint, Object result, AuditLog commonLog) {
        String auditName = commonLog.name();
        String idOgnl = commonLog.idOgnl();
        String auditType = commonLog.type();


        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Map<String, Object> paramMap = CommonJoinPointUtil.getMethodArgsAsMap(joinPoint);

        String auditNo = getAuditNo(idOgnl, paramMap);

        return buildAuditLogDO(auditName, auditNo, auditType, className, methodName,
                JSON.toJSONString(paramMap), JSON.toJSONString(result));
    }

    public static AuditLogDO buildAuditLogDO(String auditName, String auditNo, String auditType, String className,
                                             String methodName, String paramJson, String resultJson) {
        //HttpServletRequest request = HttpServletUtil.getRequest();
        String requestURI = "url";//request.getRequestURI();
        String traceId = "traceId";//TraceIdUtils.getTraceId();

        AuditLogDO auditLoDO = new AuditLogDO();
        auditLoDO.setAuditName(auditName);
        auditLoDO.setAuditNo(auditNo);
        auditLoDO.setAuditType(auditType);
        auditLoDO.setReqUrl(requestURI);
        auditLoDO.setClassName(className);
        auditLoDO.setMethodName(methodName);
        auditLoDO.setParamJson(paramJson);
        auditLoDO.setResultJson(resultJson);
        auditLoDO.setTraceId(traceId);
        auditLoDO.setCreateDate(LocalDateTime.now());
        auditLoDO.setCreateUser("");
        return auditLoDO;
    }

    public static String getAuditNo(String idOgnl, Map<String, Object> paramMap) {
        OgnlContext context = new OgnlContext();
        context.setRoot(paramMap);
        Object root = context.getRoot();
        try {
            return String.valueOf(Ognl.getValue(idOgnl, context, root));
        } catch (OgnlException e) {
            log.error("Ognl key:{} error:", idOgnl, e);
        }
        return idOgnl;
    }
}

常量类,约定审计日志的格式

public class CommonConstants {
    /**
     * 审计日志前缀
     */
    public static final String AUDIT_LOG_PREFIX = "audit_log:";
    /**
     * 审计日志:auditName auditNo auditType paramJson resultJson
     */
    public static final String AUDIT_LOG_INFO = AUDIT_LOG_PREFIX + "{} {} {} {} {}";
}

3.logback-spring.xml日志文件配置

resources目录下添加logback-spring.xml文件,配置审计日志<AUDIT_LOG_APPENDER>

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
    <!-- 彩色日志格式 -->
    <property name="log.pattern" value="%magenta(%d{yyyy-MM-dd HH:mm:ss.SSS}) %cyan([TRACE_ID:%X{X-TraceId}]) %yellow([Call_Ip:%X{X-Call-Ip}]) %blue([%thread]) %highlight(%-5level) %green(%logger) - %msg%n" />
    <property name="log.file" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID} %logger{39}: %msg%n" />
    <!-- Console 输出设置 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${log.pattern}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- 输出到控制台 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>info</level>
        </filter>
        <encoder>
            <pattern>%d{yy-MM-dd.HH:mm:ss.SSS} [%-16t] %-5p %-22c{0}%X{ServiceId} -%X{trace-id} %m%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- info日志 appender  -->
    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${log.file}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印info日志 -->
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="AUDIT_LOG_APPENDER" class="com.dehua.aop.AuditLogAppender">
        <!-- 审计日志 -->
    </appender>
    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="INFO"/>
        <appender-ref ref="AUDIT_LOG_APPENDER"/>
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

增加的配置如下,就可以实现审计日志拦截

4控制层

package com.dehua.controller;

import com.dehua.aop.AuditLog;
import com.dehua.entity.UserDO;
import com.dehua.util.CommonConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("test/user/")
public class UserController {

    @AuditLog(name = "操作用户", idOgnl = "userDO.name", type = "add")
    @PostMapping("add")
    public String add(@RequestBody UserDO userDO) {

        log.info("添加用户");
        log.info(CommonConstants.AUDIT_LOG_INFO,"操作用户-info",userDO.getName(),"add",userDO,"ok");
        return "ok";
    }

    @AuditLog(name = "操作用户", idOgnl = "userDO.id", type = "update")
    @PostMapping("update")
    public String update(UserDO userDO) {

        log.info("修改用户");

        return "ok";
    }
}

5测试

审计日志1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值