背景:
系统划分了多个微服务,想记录系统操作记录(增删改数据),但是不想每个服务都写边存储日志代码,kafka和mq等需要外搭服务的,因为某些原因无法使用。
现在想的是上传到reids(es) ,然后再一个服务统一处理,但是reids 一个担心内存爆,一个担心丢数据。后续看看能不能做成jar,在各个服务中,获取到数据库连接,然后自动创表,直接存库。
各位大神有好的想法也可以指导下小弟
LogRecodeAspect.java 具体实现
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Maps;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @Author: zhichong
* @Date: 2023/7/24 18:24
* @Description: LogRecodeAspect
* @Version 1.0.0
*/
@Aspect
@Component
@Slf4j
public class LogRecodeAspect {
@Value("${configuration.isEnableAopLog:false}")
private Boolean isEnableAopLog;
@Value("${spring.application.name:notHave}")
private String springApplicationName;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Pointcut("execution(public * com.controller.*.*(..))")
public void controllerAspectse() {
}
@Around(value = "controllerAspectse()")
public Object controllerAspectse(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = proceedingJoinPoint.proceed();
if(isEnableAopLog){
result = recordLog(proceedingJoinPoint);
}
return result;
}
public Object recordLog(ProceedingJoinPoint point) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
String methodName = point.getSignature().getName();
Object result = point.proceed();
if(methodName.startsWith("update")||methodName.startsWith("save")){
// 打印请求相关参数
long startTime = System.currentTimeMillis();
String traceId = request.getAttribute("trace_id").toString();
final ControllerAspectseLog l = ControllerAspectseLog.builder()
.ip(getIp(request))
.url(request.getRequestURL().toString())
.httpMethod(request.getMethod())
.requestParams(getNameAndValue(point))
.result(result)
.timeCost(System.currentTimeMillis() - startTime)
.traceId(traceId)
.springApplicationName(springApplicationName)
.build();
uploadData(l);
}
return result;
}
/**
* 数据上传
* @param l
*/
private void uploadData(ControllerAspectseLog l) {
String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase();
String key = RedisConstant.REDIS_CONFIGURATION_AOP_LOG +uuid;
redisTemplate.opsForValue().setIfAbsent(key, l, 10, TimeUnit.MINUTES);
}
private Map<String, Object> getNameAndValue(ProceedingJoinPoint joinPoint) {
final Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
final String[] names = methodSignature.getParameterNames();
final Object[] args = joinPoint.getArgs();
if (ArrayUtil.isEmpty(names) || ArrayUtil.isEmpty(args)) {
return Collections.emptyMap();
}
if (names.length != args.length) {
log.warn("{}方法参数名和参数值数量不一致", methodSignature.getName());
return Collections.emptyMap();
}
Map<String, Object> map = Maps.newHashMap();
for (int i = 0; i < names.length; i++) {
map.put(names[i], args[i]);
}
return map;
}
private static final String UNKNOWN = "unknown";
public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
String comma = ",";
String localhost = "127.0.0.1";
if (ip.contains(comma)) {
ip = ip.split(",")[0];
}
if (localhost.equals(ip)) {
// 获取本机真正的ip地址
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
log.error(e.getMessage(), e);
}
}
return ip;
}
}
实体类
ControllerAspectseLog.java
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.io.Serializable;
/**
* @author Administrator
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class ControllerAspectseLog extends TradeBasePo2 implements Serializable {
private static final long serialVersionUID = 473556916427144328L;
// ip
private String ip;
// url
private String url;
// http方法 GET POST PUT DELETE PATCH
private String httpMethod;
// 请求参数
private Object requestParams;
// 返回参数
private Object result;
// 接口耗时
private Long timeCost;
// traceId
private String traceId;
// 服务应用名
private String springApplicationName;
}