feat: 提交日志

This commit is contained in:
wangyu 2021-01-14 12:07:00 +08:00
parent 66ed5cbc83
commit fb918e67fb
7 changed files with 211 additions and 8 deletions

View File

@ -1,11 +1,14 @@
package com.flyfish.framework.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.data.util.CastUtils;
import org.springframework.util.Assert;
import java.lang.reflect.*;
import java.util.Optional;
/**
* 反射工具类.
@ -333,6 +336,18 @@ public class ReflectionUtils {
public static boolean hasField(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
return field != null;
}
/**
* 获取范型默认取得第一个
* @param clazz
* @return 结果
*/
public static Optional<Class<?>> getGenericType(Class<?> clazz) {
ParameterizedType type = CastUtils.cast(clazz.getGenericSuperclass());
return Optional.ofNullable(type.getActualTypeArguments()).filter(ArrayUtils::isNotEmpty)
.map(array -> array[0])
.filter(beanType -> beanType instanceof Class)
.map(beanType -> (Class<?>) beanType);
}
}

View File

@ -1,11 +1,12 @@
package com.flyfish.framework.logging.advice;
import lombok.extern.slf4j.Slf4j;
import com.flyfish.framework.logging.service.LogManager;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 日志切面
@ -13,17 +14,20 @@ import org.springframework.stereotype.Component;
* @author wangyu
*/
@Aspect
@Slf4j
public class LogAdvice {
@Resource
private LogManager logManager;
/**
* 切入注解
*/
@Pointcut("@annotation( com.flyfish.framework.annotations.Operation)")
@Pointcut("execution(public * com.flyfish..*.*Controller.*(..))")
public void pointCut() {
}
/**
* 环绕切面获取参数
*
@ -33,13 +37,16 @@ public class LogAdvice {
@Around("pointCut()")
public Object process(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
boolean success = false;
Throwable e = null;
Object result = null;
try {
Object result = joinPoint.proceed(args);
success = true;
result = joinPoint.proceed(args);
return result;
} catch (Throwable throwable) {
e = throwable;
throw throwable;
} finally {
log.info("success: {}, {}", success,joinPoint.getSignature().getName());
logManager.tryLog(joinPoint, result, e);
}
}
}

View File

@ -2,12 +2,16 @@ package com.flyfish.framework.logging.config;
import com.flyfish.framework.logging.advice.LogAdvice;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.util.List;
/**
* 日志配置
*
* @author wangyu
*/
@EnableAspectJAutoProxy
public class LoggingConfig {
/**
@ -19,4 +23,14 @@ public class LoggingConfig {
public LogAdvice logAdvice() {
return new LogAdvice();
}
/**
* 日志文本注册提供类型的动态渲染
*
* @return 结果
*/
@Bean
public LoggingTextRegistry loggingTextRegistry(List<LoggingTextModifier> modifiers) {
return new LoggingTextRegistry(modifiers);
}
}

View File

@ -0,0 +1,15 @@
package com.flyfish.framework.logging.config;
import java.util.Map;
/**
* 日志记录文本自定义
* @author wangyu
*/
public interface LoggingTextModifier {
/**
* 自定义映射
*/
void modify(Map<String, String> mapping);
}

View File

@ -0,0 +1,26 @@
package com.flyfish.framework.logging.config;
import lombok.RequiredArgsConstructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 日志文本注册器
*
* @author wangyu
*/
@RequiredArgsConstructor
public class LoggingTextRegistry {
// 映射
private final Map<String, String> mapping = new HashMap<>();
// 自定义处理
private final List<LoggingTextModifier> modifiers;
public String text(String code) {
return mapping.getOrDefault(code, code);
}
}

View File

@ -0,0 +1,36 @@
package com.flyfish.framework.logging.domain;
import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.domain.po.Department;
import com.flyfish.framework.domain.po.Permission;
import com.flyfish.framework.domain.po.Role;
import com.flyfish.framework.domain.po.User;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 缺省的实体描述
* @author wangyu
*/
@AllArgsConstructor
@Getter
public enum DomainDescriptions {
DEFAULT(null, "未知数据"),
ADMIN_USER(User.class, "系统用户"),
ROLE(Role.class, "用户角色"),
PERMISSION(Permission.class, "用户权限"),
LOG(Log.class, "系统日志"),
DEPARTMENT(Department.class, "部门");
private final Class<? extends Domain> domainClass;
private final String name;
public static DomainDescriptions getByClass(Class<? extends Domain> clazz) {
return Arrays.stream(values()).filter(descriptions -> descriptions.domainClass == clazz)
.findFirst().orElse(DEFAULT);
}
}

View File

@ -0,0 +1,90 @@
package com.flyfish.framework.logging.service;
import com.alibaba.fastjson.JSON;
import com.flyfish.framework.annotations.Operation;
import com.flyfish.framework.beans.meta.RestBean;
import com.flyfish.framework.context.UserContext;
import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.logging.domain.DomainDescriptions;
import com.flyfish.framework.logging.domain.Log;
import com.flyfish.framework.utils.ReflectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.util.CastUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Optional;
/**
* 日志管理器
*
* @author wangyu
*/
@Service
@Slf4j
public class LogManager {
/**
* 尝试记录日志
*
* @param joinPoint 接入点
* @param e 异常
*/
public void tryLog(ProceedingJoinPoint joinPoint, Object result, Throwable e) {
Signature signature = joinPoint.getSignature();
if (signature instanceof MethodSignature) {
MethodSignature methodSignature = (MethodSignature) signature;
Operation operation = AnnotationUtils.findAnnotation(methodSignature.getMethod(), Operation.class);
if (null != operation) {
String module = operation.module();
Class<?> targetClass = joinPoint.getTarget().getClass();
if (StringUtils.isBlank(module)) {
module = ReflectionUtils.getGenericType(targetClass)
.flatMap(clazz -> {
DomainDescriptions description = DomainDescriptions.getByClass(CastUtils.cast(clazz));
if (null != description) {
return Optional.of(description.getName());
}
return Optional.ofNullable(AnnotationUtils.findAnnotation(clazz, RestBean.class))
.map(RestBean::name);
})
.orElse("未知模块");
}
log.info("监测到支持的切点:{}, {}", module, operation.value());
// 构建日志
Log log = new Log();
log.setSuccess(null == e);
log.setBody(bodyString(joinPoint.getArgs()));
log.setModule(module);
log.setBusiness(operation.value());
log.setError(Optional.ofNullable(e).map(JSON::toJSONString).orElse(null));
log.setResponse(Optional.ofNullable(result).map(JSON::toJSONString).orElse(null));
log.setOperator(UserContext.sharedContext().map(UserContext::currentUser).map(Domain::getName).orElse("未知"));
log.setSignature(joinPoint.getSignature().getName());
log.setUri(Optional.ofNullable(AnnotationUtils.findAnnotation(targetClass, RequestMapping.class))
.map(mapping -> mapping.value())
.filter(ArrayUtils::isNotEmpty)
.map(array -> array[0])
);
// 写入日志
logService.create()
}
}
}
private String bodyString(Object[] args) {
if (ArrayUtils.isEmpty(args)) {
return null;
}
if (args.length == 1) {
return JSON.toJSONString(args[0]);
}
return JSON.toJSONString(args);
}
}