從零學ELK系列(十一):SpringBoot項目接入ELK超級版(超詳細圖文教程)

前言

以前在《從零學ELK系列(十):SpringBoot項目接入ELK升級版(超詳細圖文教程)》中演示了SpringBoot項目接入ELK請求記錄及優化,本次針對於未知異常經過攔截進行記錄;java

優化前:git

  • 系統發生異常沒有記錄異常信息

優化後:github

  • 記錄本次請求的異常信息

目錄

架構圖&時序圖

  • 架構圖
    在這裏插入圖片描述
  • 程序寫入日誌時序圖
    在這裏插入圖片描述
  • ELK收集日誌及Kibina查詢日誌時序圖
    在這裏插入圖片描述

代碼實現

  • 完整代碼(GitHub,歡迎你們Star,Fork,Watch)spring

    https://github.com/dangnianchuntian/springbootjson

  • 主要代碼展現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)
    @Component
    public 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());
            }
        }
    }
    • 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;
    
    @Service
    public class RecordExcepitonLogServiceImpl implements RecordExcepitonLogService { 
    
        /** * 記錄異常 */
        @Override
        public Object recordExcepitonLog(RecordExceptionLogRequest recordExceptionLogRequest) { 
            Integer divisor = recordExceptionLogRequest.getDivisor();
            int consult = 2 / divisor;
            Map<String, Object> map = new HashMap();
            map.put("consult", consult);
            return WrapMapper.ok(map);
        }
    
    }
    • 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<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 = 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<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();
                    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<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);
        }
    }

測試

  • 在進行請求架構

    • 無異常請求
      在這裏插入圖片描述
      app

    • 有異常請求
      在這裏插入圖片描述
      ide

  • 在Kibina上進行查看測試

    • 發現日誌中新加的參數有警告
      在這裏插入圖片描述

    • 解決警告(設置中從新更新索引)
      在這裏插入圖片描述

    • 查看正常日誌(新加參數已無異常)
      在這裏插入圖片描述

    • 查看異常日誌
      在這裏插入圖片描述

    • 根據條件查看有異常請求
      在這裏插入圖片描述

總結

  • 能夠精準統計出系統中有多少請求出現異常,以及異常類方法,請求參數,異常信息
  • 會持續將生產項目中進行優化同步到本項目中並進行輸出
相關文章
相關標籤/搜索