之前在《从零学ELK系列(八):SpringBoot项目接入ELK(超详细图文教程)》中演示了SpringBoot项目接入ELK,后来项目中对这部分进行了优化,之前博文中也有读者问到,将优化整理成博文和大家共享;
优化前:
- 一次请求记录两条日志(request一条,response一条),通过UUID传连起来
优化后:
- 一次请求记录一条日志(request信息与response信息都在一起)
从零学ELK系列(一):为什么要跟我学从零学ELK系列
从零学ELK系列(二):VMware安装Centos(超详细图文教程)
从零学ELK系列(三):Centos安装Docker(超详细图文教程)
从零学ELK系列(四):Docker安装Elasticsearch(超详细图文教程)
从零学ELK系列(五):Docker安装Kibana(超详细图文教程)
从零学ELK系列(六):Docker安装Logstash(超详细图文教程)
从零学ELK系列(七):Centos安装Filebeat(超详细图文教程)
从零学ELK系列(八):SpringBoot项目接入ELK(超详细图文教程)
从零学ELK系列(九):Nginx接入ELK(超详细图文教程)
从零学ELK系列(十):SpringBoot项目接入ELK升级版(超详细图文教程)
完整代码(GitHub,欢迎大家Star,Fork,Watch)
https://github.com/dangnianchuntian/springboot
主要代码展示
/*
* Copyright (c) 2020. [email protected] All Rights Reserved.
* 项目名称:SpringBoot项目接入ELK
* 类名称:FileBeatLogUtil.java
* 创建人:张晗
* 联系方式:[email protected]
* 开源地址: https://github.com/dangnianchuntian/springboot
* 博客地址: https://zhanghan.blog.csdn.net
*/
package com.zhanghan.zhelkboot.util;
import com.alibaba.fastjson.JSON;
import com.zhanghan.zhelkboot.util.wrapper.Wrapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.MDC;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;
public class FileBeatLogUtil {
public static void writeRequestInfo(HttpServletRequest request, String applicationName, String reqName, String requestParams) {
String requestURI = request.getRequestURI();
//获取requestHeader
Enumeration<String> requestHeaderNames = request.getHeaderNames();
Map<String, Object> reuestHeaderMap = new HashMap<>();
while (requestHeaderNames.hasMoreElements()) {
String name = requestHeaderNames.nextElement();
String value = request.getHeaders(name).nextElement();
reuestHeaderMap.put(name, value);
}
String requestHeader = "";
if (null != reuestHeaderMap && reuestHeaderMap.size() > 0) {
requestHeader = JSON.toJSONString(reuestHeaderMap);
}
//防止MDC值空指针,所有入参不为null
applicationName = org.springframework.util.StringUtils.isEmpty(applicationName) ? "" : applicationName;
requestURI = org.springframework.util.StringUtils.isEmpty(requestURI) ? "" : requestURI;
reqName = org.springframework.util.StringUtils.isEmpty(reqName) ? "" : reqName;
requestParams = "null".equals(requestParams) ? "" : requestParams;
//MDC值为ES键值对JSON信息
MDC.put("applicationName", applicationName);
MDC.put("requestTime", getStringTodayTime());
MDC.put("requestURI", requestURI);
MDC.put("requestHeader", requestHeader);
MDC.put("sourceName", reqName);
MDC.put("requestParams", requestParams);
}
public static void writeResponseLog(Object o, Logger log, HttpServletResponse response) {
//取responseHeader内容
Map<String, Object> responseHeaderMap = new HashMap<>();
Collection<String> headerNames = response.getHeaderNames();
headerNames.forEach(name -> {
responseHeaderMap.put(name, response.getHeader(name));
});
String strResponseHeader = "";
if (null != responseHeaderMap && responseHeaderMap.size() > 0) {
strResponseHeader = JSON.toJSONString(responseHeaderMap);
}
//获取response内容
String responseCode = "";
String responseMsg = "";
String responseBody = "";
Wrapper wrapper;
if (null != o) {
wrapper = (Wrapper) o;
if (null != wrapper) {
responseCode = String.valueOf(wrapper.getCode());
responseMsg = wrapper.getMessage();
responseBody = wrapper.getResult().toString();
}
}
//MDC值为ES键值对JSON信息
MDC.put("responseHeader", strResponseHeader);
MDC.put("responseCode", responseCode);
MDC.put("responseMsg", responseMsg);
MDC.put("responseBody", responseBody);
MDC.put("responseTime", getStringTodayTime());
Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap();
String reqInfoJsonStr = JSON.toJSONString(copyOfContextMap);
log.info(reqInfoJsonStr);
}
/**
* 获取请求参数,处理为json字符串
*
* @param joinPoint
* @return
*/
public static String getParams(JoinPoint joinPoint) {
Object[] argValues = joinPoint.getArgs();
String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
LinkedHashMap<String, Object> linkedHashMap = new LinkedHashMap<>();
if (argNames != null && argNames.length > 0) {
for (int i = 0; i < argNames.length; i++) {
String thisArgName = argNames[i];
String thisArgValue = argValues[i].toString();
linkedHashMap.put(thisArgName, thisArgValue);
}
}
return JSON.toJSONString(linkedHashMap);
}
public static String getStringTodayTime() {
Date todat_date = new Date();
//将日期格式化
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
//转换成字符串格式
return simpleDateFormat.format(todat_date);
}
}
/*
* Copyright (c) 2020. [email protected] All Rights Reserved.
* 项目名称:SpringBoot项目接入ELK
* 类名称:RequestLogAspectConf.java
* 创建人:张晗
* 联系方式:[email protected]
* 开源地址: https://github.com/dangnianchuntian/springboot
* 博客地址: https://zhanghan.blog.csdn.net
*/
package com.zhanghan.zhelkboot.aop;
import com.zhanghan.zhelkboot.util.FileBeatLogUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Order(0)
@Component
public class RequestLogAspectConf {
@Autowired
private HttpServletRequest request;
@Autowired
private Environment env;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 范围切点方法
*/
@Pointcut("execution(* com.zhanghan.zhelkboot.controller..*.*(..))")
public void methodPointCut() {
}
@Before("methodPointCut()")
void doBefore(JoinPoint joinPoint) {
authLogic(joinPoint);
}
private void authLogic(JoinPoint joinPoint) {
try {
String applicationName = env.getProperty("spring.application.name");
//获取当前http请求
String reqName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
String requestParams = FileBeatLogUtil.getParams(joinPoint);
FileBeatLogUtil.writeRequestInfo(request, applicationName, reqName, requestParams);
} catch (Exception e) {
logger.error("authLogic;Exception:{}", e.getMessage());
}
}
}
/*
* Copyright (c) 2020. [email protected] All Rights Reserved.
* 项目名称:SpringBoot项目接入ELK
* 类名称:ResponseLogAdvice.java
* 创建人:张晗
* 联系方式:[email protected]
* 开源地址: https://github.com/dangnianchuntian/springboot
* 博客地址: https://zhanghan.blog.csdn.net
*/
package com.zhanghan.zhelkboot.aop;
import com.zhanghan.zhelkboot.util.FileBeatLogUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.servlet.http.HttpServletResponse;
@ControllerAdvice
public class ResponseLogAdvice implements ResponseBodyAdvice {
@Autowired
private HttpServletResponse response;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
try {
if (o != null) {
Logger log = LoggerFactory.getLogger("logstashInfo");
FileBeatLogUtil.writeResponseLog(o, log, response);
}
} catch (Exception e) {
logger.error("beforeBodyWrite;Exception:{}", e.getMessage());
}
return o;
}
}
/*
* Copyright (c) 2020. [email protected] All Rights Reserved.
* 项目名称:SpringBoot项目接入ELK
* 类名称:LombokController.java
* 创建人:张晗
* 联系方式:[email protected]
* 开源地址: https://github.com/dangnianchuntian/springboot
* 博客地址: https://zhanghan.blog.csdn.net
*/
package com.zhanghan.zhelkboot.controller;
import com.zhanghan.zhelkboot.controller.request.LombokRequest;
import com.zhanghan.zhelkboot.util.wrapper.WrapMapper;
import com.zhanghan.zhelkboot.util.wrapper.Wrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class LombokController {
private static Logger logger = LoggerFactory.getLogger(LombokController.class);
@RequestMapping(value = "/lombok", method = RequestMethod.POST)
public Wrapper lombok(@RequestBody LombokRequest lombokRequest) {
logger.info("lombok param {}", lombokRequest.toString());
Map<String, Object> map = new HashMap();
map.put("intLombok", lombokRequest.getIntLombok());
map.put("strLombok", lombokRequest.getStrLombok());
map.put("boleanLombok", lombokRequest.getBoleanLombok());
map.put("personLombok", lombokRequest.getPersonLombok());
return WrapMapper.ok(map);
}
}