spring cloud中实现日志追踪
程序员文章站
2022-03-05 08:08:53
...
- 网关中设置filter对每一个请求的header中进行设置traceID(用于追踪每一个请求),并将traceSort(用于对后续请求进行排序)存入redis中
- 在其余微服务中添加AOP对需要追踪的进行日志搜集
部分代码示例
package com.zy.zygateway.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.zy.core.model.RedisKey;
import com.zy.zygateway.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import java.util.UUID;
/**
* 〈为每一个请求添加traceid〉
*/
@Component
@Slf4j
public class TraceIDFilter extends ZuulFilter {
@Autowired
private RedisService redisService;
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
// 每一个请求都必须拦截
return true;
}
@Override
public Object run() throws ZuulException {
// 为每一个请求添加traceid
String traceId = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
String traceSort = new Integer(0).toString();
RequestContext requestContext = RequestContext.getCurrentContext();
requestContext.addZuulRequestHeader("Trace-Id", traceId);
// requestContext.addZuulRequestHeader("Request-Sort", traceSort);
redisService.set(RedisKey.LOG.OPERATIONLOG + traceId, traceSort, 20L);
log.info("请求【{}】,进入TraceIDFilter,成功分配Trace-Id【{}】",
requestContext.getRequest().getRequestURL(),
traceId);
return null;
}
}
package com.zy.zypayservice.config;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableDefault;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Configuration
public class HystrixCredentialsContext {
private static final HystrixRequestVariableDefault<Authentication> authentication = new HystrixRequestVariableDefault<>();
private static final HystrixRequestVariableDefault<HttpServletRequest> httpRequest = new HystrixRequestVariableDefault<>();
public static HystrixRequestVariableDefault<Authentication> getInstance() {
return authentication;
}
public static HystrixRequestVariableDefault<HttpServletRequest> getHttpRequestInstance() {
return httpRequest;
}
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
Authentication auth = HystrixCredentialsContext.getInstance().get();
HttpServletRequest request = HystrixCredentialsContext.getHttpRequestInstance().get();
if (auth != null) {
requestTemplate.header("Trace-Id",
request.getHeader("Trace-Id"));
// requestTemplate.header("Request-Sort",
// String.valueOf(Integer.valueOf(request.getHeader("Request-Sort")).intValue() + 1));
if (!StringUtils.isEmpty(auth.getPrincipal()) && !auth.getPrincipal().toString().equals("anonymousUser")) {
if (auth instanceof OAuth2Authentication && auth.getDetails() instanceof OAuth2AuthenticationDetails) {
requestTemplate.header("Authorization",
"bearer " + ((OAuth2AuthenticationDetails) auth.getDetails()).getTokenValue());
} else {
requestTemplate.header("Authorization", "");
}
} else {
requestTemplate.header("Authorization", "");
}
}
}
};
}
@Bean
public FilterRegistrationBean hystrixFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HystrixRequestContext.initializeContext();
SecurityContext securityContext = SecurityContextHolder.getContext();
if (securityContext != null) {
Authentication auth = (Authentication) securityContext.getAuthentication();
HystrixCredentialsContext.getInstance().set(auth);
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
});
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
package com.zy.zypayservice.aop;
import com.alibaba.fastjson.JSONObject;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.zy.api.client.ZyRemoteClient.log.ZyHistoryRecordClient;
import com.zy.common.log.ZYLoggerManage;
import com.zy.core.annotation.ZyBizAnnBean;
import com.zy.core.annotation.ZyBizAnnotation;
import com.zy.core.model.BDic;
import com.zy.core.model.RedisKey;
import com.zy.model.log.in.AddZyHistoryRecordIn;
import com.zy.model.utils.ZyUserUtil;
import com.zy.zypayservice.config.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.NamedThreadLocal;
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 javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.CompletableFuture;
@Component
@Aspect
@Slf4j
public class RsetAPIAspectj {
@Autowired
private ZyHistoryRecordClient zyHistoryRecordClient;
private static final ThreadLocal<AddZyHistoryRecordIn> paramThreadLocal = new NamedThreadLocal<AddZyHistoryRecordIn>("Param beginTime");
@Value("${spring.application.name}")
private String projectName;
@Autowired
private RedisService redisService;
@Pointcut("execution(* com.zy.zypayservice.controller..*.*(..)) || execution(* com.zy.core.base.ZyBaseController.exceptionHandler())")
public void resetAPIPointcut() {}
/**
* <方法执行之前>
*
* @param jp
* @return void
* @date 2019/1/3 10:22
*/
@Before(value = "resetAPIPointcut()")
public void restAPIBefore(JoinPoint jp) {
String httpReqParam = null;
String ip = null;
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
StringBuilder sb = new StringBuilder();
try {
AddZyHistoryRecordIn in = new AddZyHistoryRecordIn();
for (Object obj : jp.getArgs()) {
if (obj instanceof HttpServletRequest) {
in.setParams(JSONObject.toJSONString(((HttpServletRequest) obj).getParameterMap()));
} else if (obj instanceof HttpServletResponse) {
} else if (obj instanceof Throwable) {
in.setException(obj.getClass().getName());
in.setExceptionDescribe(((Throwable) obj).getMessage());
in.setType(BDic.LOG_LEVEL.ERROR);
} else {
ip = "ip:[" + request.getRemoteAddr() + "]";
httpReqParam = JSONObject.toJSONString(obj);
in.setParams(httpReqParam);
sb.append(ip).append(httpReqParam);
sb.append(JSONObject.toJSONString(obj));
}
}
// 获取方法中注释内容
ZyBizAnnBean mthodRemark = getMthodRemark(jp);
// 获取追踪ID
String traceId = request.getHeader("Trace-Id");
// 获取请求次序号
Integer requestSort = 0;
boolean flag = true;
do {
Object obj = null;
try {
obj = redisService.get(RedisKey.LOG.OPERATIONLOG + traceId);
if (obj != null) {
requestSort = Integer.valueOf(String.valueOf(obj));
redisService.set(RedisKey.LOG.OPERATIONLOG + traceId,
requestSort + 1,
200L);
flag = false;
}
} catch (Exception e) {
flag = false;
}
} while (flag);
// 判断是否有 ZyBizAnnBean 注解,有:执行历史记录 没有:不执行
if (mthodRemark != null) {
in.setTraceId(traceId);
in.setProjectName(projectName);
in.setSort(requestSort);
String account = "";
if (ZyUserUtil.getLoginUser() == null) {
account = "匿名";
} else {
account = ZyUserUtil.getLoginUser().getAccount();
}
in.setAccount(account);
in.setContent(mthodRemark.getOption());
in.setSource(BDic.LOG_MODULE.BACK_MANAGER);
in.setUrl(request.getRequestURL().toString());
in.setIp(request.getRemoteAddr());
in.setType(BDic.LOG_LEVEL.INFO);
in.setUrlType(request.getMethod());
in.setMethod(jp.getSignature().getName());
in.setClassname(jp.getTarget().getClass().getName());
in.setCreateTime(new Date());
// 将请求参数存储到本地线程中
paramThreadLocal.set(in);
}
}
catch(Exception e) {
log.error("AOP异常【{}】" + e.getMessage());
} finally {
log.info("====调用【{}】方法-开始:{}", jp.getSignature().toString(), sb);
}
}
/**
* <方法执行完成之后>
*
* @param jp
* @param returnVal
* @return void
* @date 2019/1/3 10:21
*/
@AfterReturning(pointcut = "resetAPIPointcut()", returning = "returnVal")
public void restAPIAfter(JoinPoint jp, Object returnVal) {
AddZyHistoryRecordIn addZyHistoryRecordIn = paramThreadLocal.get();
StringBuilder sb = new StringBuilder();
try {
if (addZyHistoryRecordIn != null) {
addZyHistoryRecordIn.setResParams(JSONObject.toJSONString(returnVal));
addZyHistoryRecordIn.setEndTime(new Date());
CompletableFuture.runAsync(() -> {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
zyHistoryRecordClient.addHistory(addZyHistoryRecordIn);
} catch (Exception e2) {
e2.printStackTrace();
} finally {
context.shutdown();
}
});
}
} catch(Exception e) {
log.error("AOP异常【{}】" + e.getMessage());
} finally {
sb.append(JSONObject.toJSONString(returnVal));
log.info("====调用【{}】方法-开始:{}", jp.getSignature().toString(), sb);
}
}
/**
* <方法抛出异常>
*
* @param joinPoint
* @param e
* @return void
* @date 2018/12/29 11:27
*/
@AfterThrowing(pointcut = "resetAPIPointcut()", throwing = "e")
public void restAPIAfterThrow(JoinPoint joinPoint, Throwable e) {
try {
AddZyHistoryRecordIn addZyHistoryRecordIn = paramThreadLocal.get();
addZyHistoryRecordIn.setType(BDic.LOG_LEVEL.ERROR);
addZyHistoryRecordIn.setException(e.toString());
addZyHistoryRecordIn.setEndTime(new Date());
zyHistoryRecordClient.addHistory(addZyHistoryRecordIn);
CompletableFuture.runAsync(() -> {
try {
HystrixRequestContext.initializeContext();
zyHistoryRecordClient.addHistory(addZyHistoryRecordIn);
} catch (Exception e2) {
e2.printStackTrace();
}
});
} catch (Exception e1) {
ZYLoggerManage.error(this.getClass(), "后置异常日志拦截异常", e1);
}
}
/**
* <获取方法的注释信息>
*
* @param joinPoint
* @return com.zy.core.annotation.ZyBizAnnBean
* @date 2018/12/28 16:16
*/
public ZyBizAnnBean getMthodRemark(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
ZyBizAnnBean zab = null;
for (Method m : method)
{
if (m.getName().equals(methodName))
{
Class[] tmpCs = m.getParameterTypes();
if (tmpCs.length == arguments.length)
{
ZyBizAnnotation methodCache = m.getAnnotation(ZyBizAnnotation.class);
if (methodCache != null)
{
String option = methodCache.option();
String name = methodCache.name();
zab = new ZyBizAnnBean();
zab.setName(name);
zab.setOption(option);
return zab;
}
}
}
}
return zab;
}
}
上一篇: python轨迹追踪、全链路日志追踪trace_id实现
下一篇: PHP 二维数组根据某个字段排序
推荐阅读
-
Spring Cloud Config 配置中心实践过程中,你需要了解这些细节!
-
[Spring cloud 一步步实现广告系统] 11. 使用Feign实现微服务调用
-
Spring Cloud Feign的文件上传实现的示例代码
-
普通对象使用spring容器中的对象的实现方法
-
Spring Cloud zuul自定义统一异常处理实现方法
-
spring boot devtools在Idea中实现热部署方法
-
spring cloud 入门系列八:使用spring cloud sleuth整合zipkin进行服务链路追踪
-
python脚本实现统计日志文件中的ip访问次数代码分享
-
spring框架中@PostConstruct的实现原理
-
Spring Cloud下使用Feign Form实现微服务之间的文件上传