系统操作日志:集成 mzt-biz-log 3

This commit is contained in:
puhui999
2023-12-13 15:18:19 +08:00
parent 13d6c42a48
commit c74881c8f0
11 changed files with 145 additions and 94 deletions

View File

@ -1,22 +1,15 @@
package cn.iocoder.yudao.module.system.dal.dataobject.logger;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 操作日志表
* 操作日志表 V2
*
* @author 芋道源码
*/
@ -26,16 +19,6 @@ import java.util.Map;
@EqualsAndHashCode(callSuper = true)
public class OperateLogV2DO extends BaseDO {
/**
* {@link #javaMethodArgs} 的最大长度
*/
public static final Integer JAVA_METHOD_ARGS_MAX_LENGTH = 8000;
/**
* {@link #resultData} 的最大长度
*/
public static final Integer RESULT_MAX_LENGTH = 4000;
/**
* 日志主键
*/
@ -68,22 +51,14 @@ public class OperateLogV2DO extends BaseDO {
*/
private String name;
/**
* 操作分类
*
* 枚举 {@link OperateTypeEnum}
* 操作模块业务编号
*/
private Integer type;
private Long bizId;
/**
* 操作内容,记录整个操作的明细
* 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
*/
private String content;
/**
* 拓展字段,有些复杂的业务,需要记录一些字段
* 例如说,记录订单编号,则可以添加 key 为 "orderId"value 为订单编号
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> exts;
/**
* 请求方法名
@ -102,43 +77,4 @@ public class OperateLogV2DO extends BaseDO {
*/
private String userAgent;
/**
* Java 方法名
*/
private String javaMethod;
/**
* Java 方法的参数
*
* 实际格式为 Map<String, Object>
* 不使用 @TableField(typeHandler = FastjsonTypeHandler.class) 注解的原因是,数据库存储有长度限制,会进行裁剪,会导致 JSON 反序列化失败
* 其中key 为参数名value 为参数值
*/
private String javaMethodArgs;
/**
* 开始时间
*/
private LocalDateTime startTime;
/**
* 执行时长,单位:毫秒
*/
private Integer duration;
/**
* 结果码
*
* 目前使用的 {@link CommonResult#getCode()} 属性
*/
private Integer resultCode;
/**
* 结果提示
*
* 目前使用的 {@link CommonResult#getMsg()} 属性
*/
private String resultMsg;
/**
* 结果数据
*
* 如果是对象,则使用 JSON 格式化
*/
private String resultData;
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.system.dal.mysql.logger;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
@ -16,14 +15,7 @@ public interface OperateLogV2Mapper extends BaseMapperX<OperateLogV2DO> {
default PageResult<OperateLogV2DO> selectPage(OperateLogPageReqVO reqVO, Collection<Long> userIds) {
LambdaQueryWrapperX<OperateLogV2DO> query = new LambdaQueryWrapperX<OperateLogV2DO>()
.likeIfPresent(OperateLogV2DO::getModule, reqVO.getModule())
.inIfPresent(OperateLogV2DO::getUserId, userIds)
.eqIfPresent(OperateLogV2DO::getType, reqVO.getType())
.betweenIfPresent(OperateLogV2DO::getStartTime, reqVO.getStartTime());
if (Boolean.TRUE.equals(reqVO.getSuccess())) {
query.eq(OperateLogV2DO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode());
} else if (Boolean.FALSE.equals(reqVO.getSuccess())) {
query.gt(OperateLogV2DO::getResultCode, GlobalErrorCodeConstants.SUCCESS.getCode());
}
.inIfPresent(OperateLogV2DO::getUserId, userIds);
query.orderByDesc(OperateLogV2DO::getId); // 降序
return selectPage(reqVO, query);
}

View File

@ -3,14 +3,13 @@ package cn.iocoder.yudao.module.system.framework.bizlog.config;
import com.mzt.logapi.starter.annotation.EnableLogRecord;
import org.springframework.context.annotation.Configuration;
/**
*
* mzt-biz-log 配置类
*
* @author HUIHUI
*/
@Configuration(proxyBeanMethods = false)
@EnableLogRecord(tenant = "${yudao.info.base-package}")
@EnableLogRecord(tenant = "") // 貌似用不上 tenant 这玩意给个空好啦
public class YudaoOperateLogV2Configuration {
}

View File

@ -34,11 +34,11 @@ public class AdminUserParseFunction implements IParseFunction {
@Override
public String apply(Object value) {
if (value == null) {
log.warn("(getAdminUserById) 解析异常参数为 null");
//log.warn("(getAdminUserById) 解析异常参数为 null");
return "";
}
if (StrUtil.isEmpty(value.toString())) {
log.warn("(getAdminUserById) 解析异常参数为空");
//log.warn("(getAdminUserById) 解析异常参数为空");
return "";
}

View File

@ -1,9 +1,14 @@
package cn.iocoder.yudao.module.system.framework.bizlog.service;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.system.api.logger.OperateLogApi;
import cn.iocoder.yudao.module.system.service.logger.bo.OperateLogV2CreateReqBO;
import com.mzt.logapi.beans.LogRecord;
import com.mzt.logapi.service.ILogRecordService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@ -26,7 +31,42 @@ public class ILogRecordServiceImpl implements ILogRecordService {
@Override
public void record(LogRecord logRecord) {
log.info("【logRecord】log={}", logRecord);
OperateLogV2CreateReqBO reqBO = new OperateLogV2CreateReqBO();
// 补全通用字段
reqBO.setTraceId(TracerUtils.getTraceId());
// 补充用户信息
fillUserFields(reqBO);
// 补全模块信息
fillModuleFields(reqBO, logRecord);
// 补全请求信息
fillRequestFields(reqBO);
// 异步记录日志
log.info("操作日志 ===> {}", reqBO);
}
private static void fillUserFields(OperateLogV2CreateReqBO reqBO) {
reqBO.setUserId(WebFrameworkUtils.getLoginUserId());
reqBO.setUserType(WebFrameworkUtils.getLoginUserType());
}
public static void fillModuleFields(OperateLogV2CreateReqBO reqBO, LogRecord logRecord) {
reqBO.setModule(logRecord.getType()); // 大模块类型如 crm-客户
reqBO.setName(logRecord.getSubType());// 操作名称如 转移客户
reqBO.setBizId(Long.parseLong(logRecord.getBizNo())); // 操作模块业务编号
reqBO.setContent(logRecord.getAction());// 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
}
private static void fillRequestFields(OperateLogV2CreateReqBO reqBO) {
// 获得 Request 对象
HttpServletRequest request = ServletUtils.getRequest();
if (request == null) {
return;
}
// 补全请求信息
reqBO.setRequestMethod(request.getMethod());
reqBO.setRequestUrl(request.getRequestURI());
reqBO.setUserIp(ServletUtils.getClientIP(request));
reqBO.setUserAgent(ServletUtils.getUserAgent(request));
}
@Override
@ -38,4 +78,5 @@ public class ILogRecordServiceImpl implements ILogRecordService {
public List<LogRecord> queryLogByBizNo(String bizNo, String type, String subType) {
return Collections.emptyList();
}
}

View File

@ -53,8 +53,6 @@ public class OperateLogServiceImpl implements OperateLogService {
@Override
public void createOperateLogV2(OperateLogCreateReqDTO createReqDTO) {
OperateLogV2DO log = BeanUtils.toBean(createReqDTO, OperateLogV2DO.class);
log.setJavaMethodArgs(StrUtils.maxLength(log.getJavaMethodArgs(), JAVA_METHOD_ARGS_MAX_LENGTH));
log.setResultData(StrUtils.maxLength(log.getResultData(), RESULT_MAX_LENGTH));
operateLogV2Mapper.insert(log);
}

View File

@ -0,0 +1,78 @@
package cn.iocoder.yudao.module.system.service.logger.bo;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
/**
* 系统操作日志 Create Req BO
*
* @author HUIHUI
*/
@Data
public class OperateLogV2CreateReqBO {
/**
* 链路追踪编号
*
* 一般来说通过链路追踪编号可以将访问日志错误日志链路追踪日志logger 打印日志等,结合在一起,从而进行排错。
*/
private String traceId;
/**
* 用户编号
*
* 关联 MemberUserDO 的 id 属性,或者 AdminUserDO 的 id 属性
*/
@NotEmpty(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*
* 关联 {@link UserTypeEnum}
*/
@NotEmpty(message = "用户类型不能为空")
private Integer userType;
/**
* 操作模块
*/
@NotEmpty(message = "操作模块不能为空")
private String module;
/**
* 操作名
*/
@NotEmpty(message = "操作名不能为空")
private String name;
/**
* 操作模块业务编号
*/
@NotEmpty(message = "操作模块业务编号不能为空")
private Long bizId;
/**
* 操作内容,记录整个操作的明细
* 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
*/
@NotEmpty(message = "操作内容不能为空")
private String content;
/**
* 请求方法名
*/
@NotEmpty(message = "请求方法名不能为空")
private String requestMethod;
/**
* 请求地址
*/
@NotEmpty(message = "请求地址不能为空")
private String requestUrl;
/**
* 用户 IP
*/
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
/**
* 浏览器 UA
*/
@NotEmpty(message = "浏览器 UA 不能为空")
private String userAgent;
}