4 changed files with 317 additions and 40 deletions
@ -1,40 +1,166 @@ |
|||
//package com.epmet.jmreport.aop;
|
|||
//
|
|||
//import com.epmet.commons.tools.aspect.BaseRequestLogAspect;
|
|||
//import org.aspectj.lang.ProceedingJoinPoint;
|
|||
//import org.aspectj.lang.annotation.Around;
|
|||
//import org.aspectj.lang.annotation.Aspect;
|
|||
//import org.springframework.core.annotation.Order;
|
|||
//import org.springframework.stereotype.Component;
|
|||
//import org.springframework.web.context.request.RequestAttributes;
|
|||
//import org.springframework.web.context.request.RequestContextHolder;
|
|||
//import org.springframework.web.context.request.ServletRequestAttributes;
|
|||
//
|
|||
//import javax.servlet.http.HttpServletRequest;
|
|||
//
|
|||
///**
|
|||
// * 日志/异常处理切面实现,调用父类方法完成日志记录和异常处理。
|
|||
// */
|
|||
//@Aspect
|
|||
//@Component
|
|||
//@Order(0)
|
|||
//public class RequestLogAspect {
|
|||
//
|
|||
// @Override
|
|||
// @Around(value = "execution(* com...*Controller*.*(..)) ")
|
|||
// public Object proceed(ProceedingJoinPoint point) throws Throwable {
|
|||
// return super.proceed(point, getRequest());
|
|||
// }
|
|||
//
|
|||
// /**
|
|||
// * 获取Request对象
|
|||
// *
|
|||
// * @return
|
|||
// */
|
|||
// private HttpServletRequest getRequest() {
|
|||
// RequestAttributes ra = RequestContextHolder.getRequestAttributes();
|
|||
// ServletRequestAttributes sra = (ServletRequestAttributes) ra;
|
|||
// return sra.getRequest();
|
|||
// }
|
|||
//
|
|||
//}
|
|||
package com.epmet.jmreport.aop; |
|||
|
|||
import com.alibaba.fastjson.JSON; |
|||
import com.epmet.jmreport.constants.JmReportConstants; |
|||
import com.epmet.jmreport.constants.ThreadLocalConstant; |
|||
import com.epmet.jmreport.utils.ExceptionUtils; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.aspectj.lang.ProceedingJoinPoint; |
|||
import org.aspectj.lang.annotation.Around; |
|||
import org.aspectj.lang.annotation.Aspect; |
|||
import org.jeecg.modules.jmreport.common.vo.Result; |
|||
import org.slf4j.MDC; |
|||
import org.springframework.core.annotation.Order; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.web.context.request.RequestAttributes; |
|||
import org.springframework.web.context.request.RequestContextHolder; |
|||
import org.springframework.web.context.request.ServletRequestAttributes; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import javax.servlet.ServletRequest; |
|||
import javax.servlet.ServletResponse; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import java.time.Duration; |
|||
import java.time.LocalDateTime; |
|||
import java.util.Arrays; |
|||
import java.util.Enumeration; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 日志/异常处理切面实现,调用父类方法完成日志记录和异常处理。 |
|||
*/ |
|||
@Aspect |
|||
@Component |
|||
@Order(0) |
|||
@Slf4j |
|||
public class RequestLogAspect { |
|||
|
|||
@Around(value = "execution(* org.jeecg..*.*(..)) " + |
|||
"&& (@annotation(org.springframework.web.bind.annotation.RequestMapping)) " + |
|||
"|| @annotation(org.springframework.web.bind.annotation.GetMapping)" + |
|||
"|| @annotation(org.springframework.web.bind.annotation.PostMapping)") |
|||
public Object proceed(ProceedingJoinPoint point) throws Throwable { |
|||
HttpServletRequest request = getRequest(); |
|||
|
|||
String requestURI = request.getRequestURI(); |
|||
String method = request.getMethod(); |
|||
// 获取事务流水号
|
|||
String transactionSerial = request.getHeader(JmReportConstants.TRANSACTION_SERIAL_KEY); |
|||
|
|||
Map<String, String> requestHeaders = getRequestHeaders(request); |
|||
|
|||
// 设置traceId,日志链路追踪
|
|||
MDC.put(JmReportConstants.TRANSACTION_SERIAL_KEY, transactionSerial); |
|||
|
|||
Object result; |
|||
LocalDateTime startTime = LocalDateTime.now(); |
|||
|
|||
try { |
|||
Object[] args = point.getArgs(); |
|||
ThreadLocalConstant.requestParam.set(Arrays.toString(point.getArgs())); |
|||
log.info(">>>>>>>>请求信息>>>>>>>>:事务流水号:{},url:{} ,method:{},请求参数:{},请求头:{}", |
|||
transactionSerial, requestURI, method, objectsToString(args), requestHeaders); |
|||
result = point.proceed(); |
|||
resultInfoLog(transactionSerial, getExecPeriod(startTime), result); |
|||
} catch (Throwable e) { |
|||
result = Result.FAIL("请求失败", null); |
|||
String exceptionMsg = ExceptionUtils.getThrowableErrorStackTrace(e); |
|||
resultErrorLog(transactionSerial, getExecPeriod(startTime), result, e.getMessage(), exceptionMsg); |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 获取Request对象 |
|||
* |
|||
* @return |
|||
*/ |
|||
private HttpServletRequest getRequest() { |
|||
RequestAttributes ra = RequestContextHolder.getRequestAttributes(); |
|||
ServletRequestAttributes sra = (ServletRequestAttributes) ra; |
|||
return sra.getRequest(); |
|||
} |
|||
|
|||
/** |
|||
* @Description 获取请求头信息 |
|||
* @return |
|||
* @author wxz |
|||
* @date 2021.03.31 13:59 |
|||
*/ |
|||
private Map<String, String> getRequestHeaders(HttpServletRequest request) { |
|||
Enumeration<String> headerNames = request.getHeaderNames(); |
|||
HashMap<String, String> headerMap = new HashMap<>(); |
|||
while (headerNames.hasMoreElements()) { |
|||
String headerName = headerNames.nextElement(); |
|||
String headerValue = request.getHeader(headerName); |
|||
headerMap.put(headerName, headerValue); |
|||
} |
|||
return headerMap; |
|||
} |
|||
|
|||
/** |
|||
* 将请求对象转换为String |
|||
* @param args |
|||
* @return |
|||
*/ |
|||
private String objectsToString(Object[] args) { |
|||
if (args == null) { |
|||
return null; |
|||
} else { |
|||
StringBuilder builder = new StringBuilder("["); |
|||
for (Object object : args) { |
|||
if (object != null |
|||
&& !(object instanceof ServletRequest) |
|||
&& !(object instanceof ServletResponse) |
|||
&& !(object instanceof MultipartFile) |
|||
) { |
|||
try { |
|||
// 尝试作为json解析
|
|||
String objectString = JSON.toJSONString(object); |
|||
builder.append(objectString); |
|||
} catch (Exception e) { |
|||
builder.append(object.toString()); |
|||
} |
|||
builder.append(","); |
|||
} |
|||
} |
|||
builder.append("]"); |
|||
return builder.toString(); |
|||
} |
|||
} |
|||
/** |
|||
* info日志 |
|||
* @param transactionSerial |
|||
* @param execTimeMillis |
|||
* @param result |
|||
*/ |
|||
private void resultInfoLog(String transactionSerial, Long execTimeMillis, Object result) { |
|||
log.info("<<<<<<<<正常响应<<<<<<<<:事务流水号:{}, 执行时长:{}ms, 响应数据:{}", |
|||
transactionSerial, execTimeMillis, result == null ? result : result.toString()); |
|||
} |
|||
|
|||
/** |
|||
* 计算执行周期 |
|||
* @param startTime |
|||
* @return |
|||
*/ |
|||
private Long getExecPeriod(LocalDateTime startTime) { |
|||
LocalDateTime endTime = LocalDateTime.now(); |
|||
return Duration.between(startTime, endTime).toMillis(); |
|||
} |
|||
/** |
|||
* 异常错误级别日志 |
|||
* @param transactionSerial |
|||
* @param execTimeMillis |
|||
* @param result |
|||
* @param exceptionMsg |
|||
* @param exceptionDetail |
|||
*/ |
|||
private void resultErrorLog(String transactionSerial, Long execTimeMillis, Object result, String exceptionMsg, String exceptionDetail) { |
|||
log.error("<<<<<<<<异常响应<<<<<<<<:事务流水号:{}, 执行时长:{}ms, 响应数据:{}, 异常信息:{}, 堆栈信息:{}", |
|||
transactionSerial, execTimeMillis, result == null ? result : result.toString(), exceptionMsg, exceptionDetail); |
|||
} |
|||
|
|||
|
|||
} |
|||
|
@ -0,0 +1,71 @@ |
|||
package com.epmet.jmreport.constants; |
|||
|
|||
/** |
|||
* 公用参数常量 |
|||
*/ |
|||
public interface JmReportConstants { |
|||
|
|||
/** |
|||
* app类型-居民端端 |
|||
*/ |
|||
String APP_RESI = "resi"; |
|||
/** |
|||
* app类型-政府端 |
|||
*/ |
|||
String APP_GOV = "gov"; |
|||
/** |
|||
* app类型-运营端 |
|||
*/ |
|||
String APP_OPER = "oper"; |
|||
|
|||
/** |
|||
* 基层治理平台端 |
|||
*/ |
|||
String APP_IC = "ic"; |
|||
|
|||
/** |
|||
* PC端:web |
|||
*/ |
|||
String CLIENT_WEB = "web"; |
|||
/** |
|||
* 微信小程序:wxmp |
|||
*/ |
|||
String CLIENT_WXMP = "wxmp"; |
|||
|
|||
/** |
|||
* 客户来源App |
|||
* */ |
|||
String APP = "app"; |
|||
|
|||
/** |
|||
* 用户Id |
|||
* */ |
|||
String USER_ID = "userId"; |
|||
|
|||
/** |
|||
* 客户端 |
|||
* */ |
|||
String CLIENT = "client"; |
|||
|
|||
/** |
|||
* 客户ID |
|||
*/ |
|||
String CUSTOMER_ID = "customerId"; |
|||
|
|||
/** |
|||
* 事务流水号,每次请求串起来的多个服务拥有相同的流水号,便于日志追踪 |
|||
*/ |
|||
String TRANSACTION_SERIAL_KEY = "Transaction-Serial"; |
|||
/** |
|||
* app类型-工作端 |
|||
*/ |
|||
String APP_WORK = "work"; |
|||
/** |
|||
* 来源类型-话题:topic |
|||
*/ |
|||
String TOPIC = "topic"; |
|||
/** |
|||
* 来源类型-议题:issue |
|||
*/ |
|||
String ISSUE = "issue"; |
|||
} |
@ -0,0 +1,23 @@ |
|||
package com.epmet.jmreport.constants; |
|||
|
|||
/** |
|||
* ThreadLocal常亮 |
|||
*/ |
|||
public class ThreadLocalConstant { |
|||
|
|||
/** |
|||
* 存储所需操作权限的 ThreadLocal |
|||
*/ |
|||
public static final ThreadLocal<String> requirePermissionTl = new ThreadLocal<>(); |
|||
|
|||
/** |
|||
* 用于向DataFilterInterceptor传递权限过滤的sql片段(需要在Controller相关的AOP中进行清理,防止变量残留) |
|||
*/ |
|||
public static final ThreadLocal<String> sqlFilter = new ThreadLocal(); |
|||
|
|||
/** |
|||
* 用于本次的获取请求参数 |
|||
*/ |
|||
public static final ThreadLocal<String> requestParam = new ThreadLocal(); |
|||
|
|||
} |
@ -0,0 +1,57 @@ |
|||
/** |
|||
* Copyright (c) 2018 人人开源 All rights reserved. |
|||
* |
|||
* https://www.renren.io
|
|||
* |
|||
* 版权所有,侵权必究! |
|||
*/ |
|||
|
|||
package com.epmet.jmreport.utils; |
|||
|
|||
import java.io.IOException; |
|||
import java.io.PrintWriter; |
|||
import java.io.StringWriter; |
|||
|
|||
/** |
|||
* Exception工具类 |
|||
* |
|||
* @author Mark sunlightcs@gmail.com |
|||
*/ |
|||
public class ExceptionUtils { |
|||
|
|||
/** |
|||
* 获取异常信息 |
|||
* @param ex 异常 |
|||
* @return 返回异常信息 |
|||
*/ |
|||
public static String getErrorStackTrace(Exception ex){ |
|||
return getThrowableErrorStackTrace(ex); |
|||
} |
|||
|
|||
public static String getThrowableErrorStackTrace(Throwable ex) { |
|||
StringWriter sw = null; |
|||
PrintWriter pw = null; |
|||
try { |
|||
sw = new StringWriter(); |
|||
pw = new PrintWriter(sw, true); |
|||
ex.printStackTrace(pw); |
|||
}finally { |
|||
try { |
|||
if(pw != null) { |
|||
pw.close(); |
|||
} |
|||
} catch (Exception e) { |
|||
|
|||
} |
|||
try { |
|||
if(sw != null) { |
|||
sw.close(); |
|||
} |
|||
} catch (IOException e) { |
|||
|
|||
} |
|||
} |
|||
|
|||
return sw.toString(); |
|||
} |
|||
} |
Loading…
Reference in new issue