Initial commit
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.oneone.cloud</groupId>
|
||||
<artifactId>oneone-common</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-log</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.oneone.cloud</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oneone.cloud</groupId>
|
||||
<artifactId>common-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.oneone.common.log;
|
||||
|
||||
import com.oneone.common.log.aspect.SysLogAspect;
|
||||
import com.oneone.common.log.handler.DefaultLogHandler;
|
||||
import com.oneone.common.log.handler.LogHandler;
|
||||
import com.oneone.upms.api.logger.OperateLogApi;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.boot.autoconfigure.condition.*;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
|
||||
@EnableAsync
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnProperty(prefix = "oneone.log" , name = "enabled" , havingValue = "true" , matchIfMissing = true)
|
||||
public class LogAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(LogHandler.class)
|
||||
public DefaultLogHandler logHandler(OperateLogApi operateLogApi) {
|
||||
return new DefaultLogHandler(operateLogApi);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SysLogAspect sysLogAspect(LogHandler logHandler) {
|
||||
return new SysLogAspect(logHandler);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.oneone.common.log.annotation;
|
||||
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface ISysLog {
|
||||
|
||||
/**
|
||||
* 描述
|
||||
* @return {String}
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
package com.oneone.common.log.aspect;
|
||||
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.oneone.common.base.LocalUser;
|
||||
import com.oneone.common.log.annotation.ISysLog;
|
||||
import com.oneone.common.log.event.SysLog;
|
||||
import com.oneone.common.log.handler.LogHandler;
|
||||
import com.oneone.common.result.Result;
|
||||
import com.oneone.common.result.ResultCode;
|
||||
import com.oneone.common.util.JsonUtils;
|
||||
import com.oneone.common.util.TracerUtils;
|
||||
import com.oneone.common.web.util.UserContext;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.lang.reflect.Array;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class SysLogAspect {
|
||||
@Value("${spring.application.name}")
|
||||
private String applicationName;
|
||||
|
||||
private final LogHandler logHandler;
|
||||
private final ThreadLocal<SysLog> logThreadLocal = new ThreadLocal<>();
|
||||
|
||||
@Before("@annotation(iSysLog)")
|
||||
public void doBefore(JoinPoint joinPoint, ISysLog iSysLog) {
|
||||
ServletRequestAttributes attributes =
|
||||
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
//get方法不记录日志
|
||||
if ("GET".equals(request.getMethod())) {
|
||||
return;
|
||||
}
|
||||
SysLog sysLog = new SysLog();
|
||||
sysLog.setTraceId(TracerUtils.getTraceId());
|
||||
|
||||
sysLog.setModule(applicationName);
|
||||
sysLog.setName(iSysLog.value());
|
||||
sysLog.setType(0);
|
||||
sysLog.setRequestMethod(request.getMethod());
|
||||
sysLog.setRequestUrl(URLUtil.getPath(request.getRequestURI()));
|
||||
sysLog.setUserIp(ServletUtil.getClientIP(request));
|
||||
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
||||
sysLog.setJavaMethod(methodSignature.toString());
|
||||
sysLog.setJavaMethodArgs(obtainMethodArgs(joinPoint));
|
||||
sysLog.setUserAgent(request.getHeader("user-agent"));
|
||||
sysLog.setStartTime(LocalDateTime.now());
|
||||
logThreadLocal.set(sysLog);
|
||||
}
|
||||
|
||||
@AfterReturning(value = "@annotation(iSysLog)" , returning = "result")
|
||||
public void doAfterReturning(Object result, ISysLog iSysLog) {
|
||||
try {
|
||||
// 处理完请求,从线程变量中获取日志数据,并记录到db
|
||||
SysLog sysLog = logThreadLocal.get();
|
||||
if (null != sysLog) {
|
||||
sysLog.setUserId(UserContext.getUserIdIfPresentDefault());
|
||||
LocalUser localUser = UserContext.getUser();
|
||||
Integer useType = localUser == null ? 0 : localUser.getUserType();
|
||||
sysLog.setUserType(useType);
|
||||
|
||||
Result result1 = (Result) result;
|
||||
sysLog.setResultCode(result1.getCode());
|
||||
sysLog.setResultMsg(result1.getMsg());
|
||||
sysLog.setResultData(JsonUtils.toJSONString(result1.getData()));
|
||||
|
||||
sysLog.setDuration((int) (LocalDateTimeUtil.between(sysLog.getStartTime(), LocalDateTime.now()).toMillis()));
|
||||
logHandler.save(sysLog);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("操作请求日志记录失败" , e);
|
||||
} finally {
|
||||
// 清除threadlocal
|
||||
logThreadLocal.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@AfterThrowing(value = "@annotation(iSysLog)" , throwing = "throwable")
|
||||
public void doAfterThrowing(ISysLog iSysLog, Throwable throwable) {
|
||||
try {
|
||||
// 处理完请求,从线程变量中获取日志数据,并记录到db
|
||||
SysLog sysLog = logThreadLocal.get();
|
||||
if (null != sysLog) {
|
||||
sysLog.setUserId(UserContext.getUserIdIfPresentDefault());
|
||||
LocalUser localUser = UserContext.getUser();
|
||||
Integer useType = localUser == null ? 0 : localUser.getUserType();
|
||||
sysLog.setUserType(useType);
|
||||
|
||||
sysLog.setResultCode(ResultCode.SYSTEM_EXECUTION_ERROR.getCode());
|
||||
sysLog.setResultMsg(JSON.toJSONString(throwable.getMessage()));
|
||||
sysLog.setDuration((int) (LocalDateTimeUtil.between(sysLog.getStartTime(), LocalDateTime.now()).toMillis()));
|
||||
logHandler.save(sysLog);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("操作请求日志记录失败" , e);
|
||||
} finally {
|
||||
// 清除threadlocal
|
||||
logThreadLocal.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private static String obtainMethodArgs(JoinPoint joinPoint) {
|
||||
// TODO 提升:参数脱敏和忽略
|
||||
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
||||
String[] argNames = methodSignature.getParameterNames();
|
||||
Object[] argValues = joinPoint.getArgs();
|
||||
// 拼接参数
|
||||
Map<String, Object> args = Maps.newHashMapWithExpectedSize(argValues.length);
|
||||
for (int i = 0; i < argNames.length; i++) {
|
||||
String argName = argNames[i];
|
||||
Object argValue = argValues[i];
|
||||
// 被忽略时,标记为 ignore 字符串,避免和 null 混在一起
|
||||
args.put(argName, !isIgnoreArgs(argValue) ? argValue : "[ignore]");
|
||||
}
|
||||
return JsonUtils.toJSONString(args);
|
||||
}
|
||||
|
||||
private static boolean isIgnoreArgs(Object object) {
|
||||
Class<?> clazz = object.getClass();
|
||||
// 处理数组的情况
|
||||
if (clazz.isArray()) {
|
||||
return IntStream.range(0, Array.getLength(object))
|
||||
.anyMatch(index -> isIgnoreArgs(Array.get(object, index)));
|
||||
}
|
||||
// 递归,处理数组、Collection、Map 的情况
|
||||
if (Collection.class.isAssignableFrom(clazz)) {
|
||||
return ((Collection<?>) object).stream()
|
||||
.anyMatch((Predicate<Object>) SysLogAspect::isIgnoreArgs);
|
||||
}
|
||||
if (Map.class.isAssignableFrom(clazz)) {
|
||||
return isIgnoreArgs(((Map<?, ?>) object).values());
|
||||
}
|
||||
// obj
|
||||
return object instanceof MultipartFile
|
||||
|| object instanceof HttpServletRequest
|
||||
|| object instanceof HttpServletResponse
|
||||
|| object instanceof BindingResult;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.oneone.common.log.event;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Data
|
||||
public class SysLog implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 链路追踪编号
|
||||
*/
|
||||
private String traceId;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private Integer userType;
|
||||
|
||||
/**
|
||||
* 操作模块
|
||||
*/
|
||||
private String module;
|
||||
|
||||
/**
|
||||
* 操作名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 操作分类
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 操作明细
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 拓展字段
|
||||
*/
|
||||
private Map<String, Object> exts;
|
||||
|
||||
/**
|
||||
* 请求方法名
|
||||
*/
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 请求地址
|
||||
*/
|
||||
private String requestUrl;
|
||||
|
||||
/**
|
||||
* 用户 IP
|
||||
*/
|
||||
private String userIp;
|
||||
|
||||
/**
|
||||
* 浏览器 UserAgent
|
||||
*/
|
||||
private String userAgent;
|
||||
|
||||
/**
|
||||
* Java 方法名
|
||||
*/
|
||||
private String javaMethod;
|
||||
|
||||
/**
|
||||
* Java 方法的参数
|
||||
*/
|
||||
private String javaMethodArgs;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 执行时长,单位:毫秒
|
||||
*/
|
||||
private Integer duration;
|
||||
|
||||
/**
|
||||
* 结果码
|
||||
*/
|
||||
private String resultCode;
|
||||
|
||||
/**
|
||||
* 结果提示
|
||||
*/
|
||||
private String resultMsg;
|
||||
|
||||
/**
|
||||
* 结果数据
|
||||
*/
|
||||
private String resultData;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.oneone.common.log.handler;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.oneone.common.log.event.SysLog;
|
||||
import com.oneone.upms.api.logger.OperateLogApi;
|
||||
import com.oneone.upms.api.logger.dto.OperateLogCreateReqDTO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class DefaultLogHandler implements LogHandler{
|
||||
|
||||
private final OperateLogApi operateLogApi;
|
||||
|
||||
@Override
|
||||
public void save(SysLog sysLog) {
|
||||
OperateLogCreateReqDTO reqDTO = BeanUtil.copyProperties(sysLog, OperateLogCreateReqDTO.class);
|
||||
operateLogApi.createOperateLog(reqDTO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.oneone.common.log.handler;
|
||||
|
||||
import com.oneone.common.log.event.SysLog;
|
||||
|
||||
/**
|
||||
* @author mice
|
||||
* @version 1.0
|
||||
* @date 2022-12-21 13:58
|
||||
*/
|
||||
public interface LogHandler {
|
||||
|
||||
void save(SysLog sysLog);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.oneone.common.log.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
/**
|
||||
* @author mice
|
||||
* @version 1.0
|
||||
* @desc 事件
|
||||
* @date 2022-04-20 12:10:02
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "事件" )
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EventParam {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题" )
|
||||
@Length(max = 8)
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 告警等级
|
||||
*/
|
||||
@Schema(description = "告警等级" )
|
||||
private Integer level;
|
||||
|
||||
/**
|
||||
* 应用
|
||||
*/
|
||||
@Schema(description = "应用" )
|
||||
private String app;
|
||||
|
||||
/**
|
||||
* 通知人id [userId:userName,1:陈浩]
|
||||
*/
|
||||
@Schema(description = "通知人id" )
|
||||
@Length(max = 200)
|
||||
private String notifyUser;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
@Schema(description = "内容" )
|
||||
private String content;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.oneone.common.log.LogAutoConfiguration
|
||||
Reference in New Issue
Block a user