:SpringBoot项目接入ELK超级版(超详细图文教程)

架构图&时序图

  • 架构图
    在这里插入图片描述
  • 程序写入日志时序图
    在这里插入图片描述
  • ELK收集日志及Kibina查询日志时序图
    在这里插入图片描述

代码实现

  • 完整代码(GitHub,欢迎大家 Star,Fork,Watch)

    https://github.com/dangnianchuntian/springboot

  • 主要代码展示

    • ExceptionLogAspect
    /*
     * Copyright (c) 2020. zhanghan_java@163.com All Rights Reserved.
     * 项目名称:SpringBoot项目接入ELK
     * 类名称:ExceptionLogAspect.java
     * 创建人:张晗
     * 联系方式:zhanghan_java@163.com
     * 开源地址: 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.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import java.util.Arrays;@Aspect@Order(1)@Componentpublic class ExceptionLogAspect {
        private final Logger logger = LoggerFactory.getLogger(this.getClass());
        /**
         * 范围切点方法
         */
        @Pointcut("execution(* com.zhanghan.zhelkboot..*.*(..))")
        public void methodPointCut() {
        }
        @AfterThrowing(throwing = "ex", pointcut = "methodPointCut()")
        public void throwss(JoinPoint joinPoint, Exception ex) {
            try {
                String methodArgs = Arrays.toString(joinPoint.getArgs());
                FileBeatLogUtil.writeExceptionLog(joinPoint.getSignature().toString(), methodArgs, ex.getMessage());
            } catch (Exception e) {
                logger.error("ExceptionLogAspect;writeExceptionLog;Exception:{}", e.getMessage());
            }
        }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
    • RecordExcepitonLogServiceImpl
    /*
     * Copyright (c) 2020. zhanghan_java@163.com All Rights Reserved.
     * 项目名称:SpringBoot项目接入ELK
     * 类名称:RecordExcepitonLogServiceImpl.java
     * 创建人:张晗
     * 联系方式:zhanghan_java@163.com
     * 开源地址: https://github.com/dangnianchuntian/springboot
     * 博客地址: https://zhanghan.blog.csdn.net
     */package com.zhanghan.zhelkboot.service.impl;import com.zhanghan.zhelkboot.controller.request.RecordExceptionLogRequest;import com.zhanghan.zhelkboot.service.RecordExcepitonLogService;import com.zhanghan.zhelkboot.util.wrapper.WrapMapper;import org.springframework.stereotype.Service;import java.util.HashMap;import java.util.Map;@Servicepublic class RecordExcepitonLogServiceImpl implements RecordExcepitonLogService {
        /**
         * 记录异常
         */
        @Override
        public Object recordExcepitonLog(RecordExceptionLogRequest recordExceptionLogRequest) {
            Integer divisor = recordExceptionLogRequest.getDivisor();
            int consult = 2 / divisor;
            Map map = new HashMap();
            map.put("consult", consult);
            return WrapMapper.ok(map);
        }}123456789101112131415161718192021222324252627282930313233343536
    • FileBeatLogUtil
    /*
     * Copyright (c) 2020. zhanghan_java@163.com All Rights Reserved.
     * 项目名称:SpringBoot项目接入ELK
     * 类名称:FileBeatLogUtil.java
     * 创建人:张晗
     * 联系方式:zhanghan_java@163.com
     * 开源地址: 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 org.springframework.util.StringUtils;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 requestHeaderNames = request.getHeaderNames();
            Map 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 = StringUtils.isEmpty(applicationName) ? "" : applicationName;
            requestURI = StringUtils.isEmpty(requestURI) ? "" : requestURI;
            reqName = 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);
            MDC.put("exceptionCount", "0");
        }
        public static void writeExceptionLog(String exceptionMethodName, String exceptionMethodArgs, String exceptionMessage) {
            MDC.put("exceptionCount", "1");
            exceptionMessage = String.format("MethodName:%s;Args:%s;Exception:%s", exceptionMethodName, exceptionMethodArgs, exceptionMessage);
            //MDC值为ES键值对JSON信息
            MDC.put("exceptionMessage", exceptionMessage);
        }
        public static void writeResponseLog(Object o, Logger log, HttpServletResponse response) {
            //取responseHeader内容
            Map responseHeaderMap = new HashMap<>();
            Collection 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();
                    Object result = wrapper.getResult();
                    if (null != result) {
                        responseBody = result.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 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 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);
        }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141

测试

  • 在进行请求

    • 无异常请求
      在这里插入图片描述

    • 有异常请求 http://zzdxb.baikezh.com/
      在这里插入图片描述

  • 在Kibina上进行查看

    • 发现日志中新加的参数有警告
      在这里插入图片描述

    • 解决警告(设置中重新更新索引) http://ask.baikezh.com/beijing/
      在这里插入图片描述

    • 查看正常日志(新加参数已无异常) http://dxb.myzx.cn/shanghai/
      在这里插入图片描述

    • 查看异常日志
      在这里插入图片描述

    • 根据条件查看有异常请求 http://zzdxb.baikezh.com/
      在这里插入图片描述

总结

  • 可以精准统计出系统中有多少请求出现异常,以及异常类方法,请求参数,异常信息
  • 会持续将生产项目中进行优化同步到本项目中并进行输出


请使用浏览器的分享功能分享到微信等