springboot + enterprise micro implementation project exception alarm

httpServletRequest.getParameterMap() is null_ Fan yicui's blog - CSDN blog

Group robot configuration description - interface document - enterprise wechat Developer Center (qq.com)

Because there is no access to the log system in the project, it is very inconvenient to view abnormal information at ordinary times. Moreover, the product is required every time. Only when it is found in the test can we know that there is an error, which has a bad impact.

Therefore, the real-time alarm combined with enterprise and micro is realized by combining the technologies of section + global exception interception.

I use the group robots provided by enterprises and micro enterprises to release abnormal information. A new robot will provide a Webhook address

Developers can initiate HTTP POST requests according to the provided Webhook to send messages to the group. For details, please refer to the article: Group robot configuration description - interface document - enterprise wechat Developer Center (qq.com)

Message content type used: markdown type

{
    "msgtype": "markdown",
    "markdown": {
        "content": "Real time new user feedback<font color=\"warning\">132 example</font>,Please pay attention to relevant colleagues.\n
        >type:<font color=\"comment\">User feedback</font>
        >General user feedback:<font color=\"comment\">117 example</font>
        >VIP User feedback:<font color=\"comment\">15 example</font>"
    }
}
parameterRequiredexplain
msgtypeyesThe message type is fixed as markdown at this time
contentyesThe maximum length of the markdown content is 4096 bytes, which must be utf8 encoded

Reason for use: there are few parameters and the content length is long.

Abnormal alarm robot code:

@Component
@Slf4j
public class ExceptionMsgBot {

    private static final String METHOD_GET = "GET";
    private static final String METHOD_POST = "POST";

    /**
     * Enterprise micro robot webhook address
     */
    @Value("${ExceptionMsgBot.url}")
    private String url;

    /**
     * Enable
     */
    @Value("${ExceptionMsgBot.isEnable:true}")
    private Boolean isEnable;

    /**
     * Maximum length
     */
    @Value("${ExceptionMsgBot.maxSize:2500}")
    private int maxSize;

    public void send(Exception e, HttpServletRequest request) {
        if (!isEnable) {
            return;
        }

        String title = "title";
        //time
        String now = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_FORMAT);
        //Request url
        String api = request.getRequestURL().toString();
        //Request parameters
        String params = JSONUtil.toJsonStr(request.getAttribute("params"));
        if (!StringUtils.isEmpty(params)) {
            //Convert json to normal string
            params = params.replace("\"","\\\"");
        }
        //Server IP
        String serverIP = NetUtil.getLocalhostStr();
        //Client IP
        String clientIP = request.getRemoteAddr();

        String textMsg = "{\n" +
            "    \"msgtype\": \"markdown\",\n" +
            "    \"markdown\": {\n" +
            "        \"content\": \"" + title + "\\n\n" +
            "         [url]: " + api + " \n" +
            "         [[parameter]: " + params + " \n" +
            "         [[time]: " + now + " \n" +
            "         [serverIp]: " + serverIP + " \n" +
            "         [clientIp]: " + clientIP + " \n" +
            "         [message]: " + e.getMessage() + " \n" +
            "         [cause]: " + e.getCause() + " \n" +
            "         [StackTrace]: " + e + "  \"\n" +
            "    }\n" +
            "}\n";

        //send message
        HttpResponse response = HttpRequest
            .post(url)
            .header(Header.CONTENT_TYPE, "application/json; charset=UTF-8")
            .body(textMsg)
            .execute();

        log.info("[Exception message sending result] {}", response.body());
    }
}

The abnormal information of this design mainly shows 8 points

  • Request interface path
  • Request parameters
  • current time
  • Server ip
  • Client ip
  • e.message
  • e.cause
  • e.stack

Except that the request parameters need special processing, other parameters can be easily obtained.

Because every time the interface is requested, there will be a global log section class in the project to print out the information of each request.

This global log aspect class will intercept before entering the controller, so that the parameters of each request can be obtained. Then the parameters are encapsulated in the request and passed to the internal web container for use, that is, the abnormal alarm robot in this article.

@Aspect
@Configuration
@Slf4j
public class GlobalControllerLogAspect {

    @Pointcut("execution (* com.*..controller..*.*(..))")
    public void controllers() {
    }

    @Around("controllers()")
    public Object aroundProcess(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        long startTime = System.currentTimeMillis();
        Object proceed = null;
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String uid = request.getHeader(HeaderConstant.UID);
            List<Object> params = new ArrayList<>();
            if (args != null && args.length > 0) {
                for (Object arg : args) {
                    if (arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
                        continue;
                    } else if (arg instanceof MultipartFile) {
                        continue;
                    } else {
                        params.add(arg);
                    }
                }
            }
            //Save request parameters
            request.setAttribute("params", JSONUtil.toJsonStr(params));
            log.info("Interface method:{},uid:{},Request parameters:{}", request.getRequestURL().toString(), uid, JSONUtil.toJsonStr(params));
            proceed = joinPoint.proceed(args);
            log.info("Response result:{},Time consuming:{}ms", JSONUtil.toJsonStr(proceed), System.currentTimeMillis() - startTime);
        } finally {
        }
        return proceed;
    }
}

The request parameters can be obtained at the joinPoint.

The abnormal alarm robot is buried in the global abnormal interceptor

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @Autowired
    private ExceptionMsgBot bot;

    @ExceptionHandler(value = Exception.class)
    public void handle(Exception e, HttpServletRequest request, HttpServletResponse response) {
        log.error("Interface[{}]abnormal, ", request.getRequestURI(), e);
        CommonResult<Object> result = CommonResult.failed("There is a small problem with the system");
        //Buried point
        bot.send(e, request);
        String json = JSONUtil.toJsonStr(result);
        response.setHeader("Content-Type", "application/json; charset=UTF-8");
        try {
            response.getWriter().write(json);
        } catch (IOException ex) {
            log.error("Interface[{}]IO abnormal, ", request.getRequestURI(), ex);
        }
    }
}

When abnormal information is captured by the global exception interceptor, save the exception log and send alarm information to notify relevant personnel such as developers for handling.

effect:

Abnormal alarm, please pay attention to relevant colleagues!
         [url]: http://172.18.139.x:9001/xxx 
         [[parameter]: ["uid",{"f1":9,"f2":2,"f3":2377,"f4":false,"f5":"","f6":1}] 
         [[time]: 2022-04-14 16:35:28 
         [serverIp]: 172.18.139.x 
         [clientIp]: 172.18.139.x 
         [message]: xxx Cannot be empty 
         [cause]: null 
         [StackTrace]: com.xxx.common.component.exception.ApiException: xxx Cannot be empty  

Perfect~

Tags: Java Spring Boot

Posted by masteroleary on Thu, 14 Apr 2022 18:17:38 +0930