1. logback-spring.xml
<appender name="monitorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
<file>${logging.file.path}/smart.monitor.log</file>
<!--滚动策略-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--按时间保存日志 修改格式可以按小时、按天、月来保存-->
<fileNamePattern>${logging.file.path}/smart.monitor.log.%d{yyyy-MM-dd}</fileNamePattern>
<!--保存时长-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
</appender>
<!-- 自定义配置__web请求入参、反参、请求时常 -->
<logger name="monitorLogger" additivity="false" level="info">
<appender-ref ref="monitorAppender"/>
</logger>
2. AbstractLogItem
package com.soyoung.ztdata.bi.api.model.log;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* @program: bi-main
* @description:
* @author: Leon
* @create: 2021-11-15 19:30
**/
@Getter
@Setter
public abstract class AbstractLogItem implements Serializable {
private static final long serialVersionUID = 9206074344981457062L;
private String requestId;
private String method;
private String projectName;
private String time;
public AbstractLogItem(String requestId, String method, String projectName) {
this.requestId = requestId;
this.method = method;
this.projectName = projectName;
}
}
3. MonitorLogItem
package com.soyoung.ztdata.bi.api.model.log;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
/**
* @program: bi-main
* @description:
* @author: Leon
* @create: 2021-11-15 19:42
**/
@Setter
@Getter
public class MonitorLogItem extends AbstractLogItem {
public MonitorLogItem(String requestId, String method, String projectName) {
super(requestId, method, projectName);
}
/**
* 请求的 userName
*/
private String userName;
/**
* 开始时间
*/
private String startTime;
/**
* 结束时间戳
*/
private String endTime;
/**
* 耗时
*/
private Integer costTime;
/**
* params接口入参对象
*/
private Map<String, String[]> params;
/**
* params接口入参对象
*/
private Map<String, Object> nameAndValue;
/**
* result接口返回结果
*/
private Object result;
}
4.LogCommand
package com.soyoung.ztdata.bi.api.model.log;
/**
* @program: bi-main
* @description:
* @author: Leon
* @create: 2021-11-12 16:58
**/
public interface LogCommand {
void execute();
}
5. AbstractLogCommand
package com.soyoung.ztdata.bi.api.model.log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @program: bi-main
* @description:
* @author: Leon
* @create: 2021-11-12 21:26
**/
@Slf4j
public abstract class AbstractLogCommand<LogItem extends AbstractLogItem> implements LogCommand {
private Logger receiver;
private LogItem logItem;
public AbstractLogCommand(Logger receiver, LogItem logItem) {
this.receiver = receiver;
this.logItem = logItem;
}
/**
* @desc: 打印入口
*/
@Override
public void execute() {
try {
obtainLog(logItem);
/**
* 日志打印的时间
*/
logItem.setTime(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
String msg = JSON.toJSONString(logItem, SerializerFeature.DisableCircularReferenceDetect);
receiver.info(msg);
} catch (Exception e) {
log.error("AbstractLogCommand execute error:{}, requestId:{}", e.getMessage(), logItem.getRequestId());
}
}
protected abstract void obtainLog(LogItem t);
}
6. MonitorLogCommand
package com.soyoung.ztdata.bi.api.model.log;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.util.CollectionUtils;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @program: bi-main
* @description:
* @author: Leon
* @create: 2021-11-12 21:32
**/
@Slf4j
@Setter
@Getter
@Accessors(chain = true)
public class MonitorLogCommand extends AbstractLogCommand<MonitorLogItem> {
public MonitorLogCommand(Logger receiver, String requestId, String method, String projectName) {
super(receiver, new MonitorLogItem(requestId, method, projectName));
}
@Override
protected void obtainLog(MonitorLogItem monitorLogItem) {
monitorLogItem.setUserName(this.userName);
monitorLogItem.setStartTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(this.startTime), ZoneId.systemDefault()).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
monitorLogItem.setEndTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(this.endTime), ZoneId.systemDefault()).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
if (Objects.nonNull(this.startTime) && Objects.nonNull(this.endTime)) {
monitorLogItem.setCostTime((int) (this.endTime - this.startTime));
}
Map<String, String[]> allParameterMap = new HashMap<>();
if (!CollectionUtils.isEmpty(parameterMap)) {
allParameterMap.putAll(parameterMap);
}
if (StringUtils.isNotBlank(queryString)) {
Map<String, String[]> queryStringMap = Arrays.stream(queryString.split("&")).collect(Collectors.toMap(s -> s.split("=")[0], s -> new String[]{
s.split("=")[1]
}));
allParameterMap.putAll(queryStringMap);
}
monitorLogItem.setParams(allParameterMap);
monitorLogItem.setNameAndValue(nameAndValue);
monitorLogItem.setResult(result);
}
/**
* 请求的 userName
*/
private String userName;
/**
* 开始时间戳
*/
private Long startTime;
/**
* 结束时间戳
*/
private Long endTime;
/**
* params接口入参对象
*/
private Map<String, String[]> parameterMap;
/**
* params接口入参对象
*/
private String queryString;
/**
* params接口入参对象
*/
private Map<String, Object> nameAndValue;
/**
* result接口返回结果
*/
private Object result;
}
7. AsyncExecuteInvoker
package com.soyoung.ztdata.smart.common;
import com.soyoung.ztdata.bi.api.model.log.LogCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* @program: bi-main
* @description:
* @author: Leon
* @create: 2021-11-12 18:22
**/
@Slf4j
@Component
public class AsyncExecuteInvoker {
@Async
public void invoke(LogCommand logCommand) {
logCommand.execute();
}
}
8. MonitorLogHandler
package com.soyoung.ztdata.smart.aop;
import com.soyoung.ztdata.bi.api.model.log.MonitorLogCommand;
import com.soyoung.ztdata.bi.core.enums.ResultCodeEnum;
import com.soyoung.ztdata.bi.core.result.OutputResult;
import com.soyoung.ztdata.bi.core.util.JsonUtil;
import com.soyoung.ztdata.smart.common.AsyncExecuteInvoker;
import com.soyoung.ztdata.smart.common.SsoHelper;
import lombok.extern.slf4j.Slf4j;
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.aspectj.lang.reflect.CodeSignature;
import org.slf4j.LoggerFactory;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
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.util.HashMap;
import java.util.Map;
/**
* @program: bi-main
* @description:
* @author: Leon
* @create: 2021-11-12 17:45
**/
@Slf4j
@Aspect
@Component
public class MonitorLogHandler {
@Autowired
private AsyncExecuteInvoker asyncExecuteInvoker;
@Pointcut("execution(public * com.soyoung.ztdata.smart.controller.*.*.*(..))")
private void controllerAspect() {
}
@Around("controllerAspect()")
public Object invokeResourceWithInterceptor(ProceedingJoinPoint pjp) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String requestId = null != request.getParameterMap().get("requestId") ? request.getParameterMap().get("requestId")[0] : null;
MonitorLogCommand monitorLogCommand = new MonitorLogCommand(LoggerFactory.getLogger("monitorLogger"), requestId, request.getRequestURI(), "projectName");
monitorLogCommand.setUserName(SsoHelper.getUserName());
monitorLogCommand.setParameterMap(request.getParameterMap());
monitorLogCommand.setQueryString(request.getQueryString());
Map<String, Object> nameAndValue = getNameAndValue(pjp);
monitorLogCommand.setNameAndValue(nameAndValue);
try {
monitorLogCommand.setStartTime(System.currentTimeMillis());
Object proceed = pjp.proceed();
monitorLogCommand.setEndTime(System.currentTimeMillis());
monitorLogCommand.setResult(proceed);
asyncExecuteInvoker.invoke(monitorLogCommand);
return proceed;
} catch (Throwable e) {
log.error("拦截器拦截异常 msg:{}", JsonUtil.writeValueAsString(monitorLogCommand), e);
return OutputResult.error(ResultCodeEnum.SYS_ERROR);
}
}
private Map<String, Object> getNameAndValue(ProceedingJoinPoint pjp) {
Map<String, Object> result = new HashMap<>();
final String[] parameterNames = ((CodeSignature) pjp.getSignature()).getParameterNames();
final Object[] args = pjp.getArgs();
for (int i = 0; i < parameterNames.length; i++) {
result.put(parameterNames[i], args[i]);
}
return result;
}
}