钉钉机器人如何实时监听项目异常信息

一 建立机器人步骤

进入群设置->点击智能群助手->点击添加机器人

钉钉机器人如何实时监听项目异常信息_第1张图片     钉钉机器人如何实时监听项目异常信息_第2张图片

 点击添加机器人->点击自定义->点击添加

钉钉机器人如何实时监听项目异常信息_第3张图片      钉钉机器人如何实时监听项目异常信息_第4张图片     钉钉机器人如何实时监听项目异常信息_第5张图片

重点牢记(秘钥、Webhook地址、access_access_token代码中会用到,需保存好):填写机器人信息,选择数据传输安全方式->获取机器请求地址

 钉钉机器人如何实时监听项目异常信息_第6张图片  钉钉机器人如何实时监听项目异常信息_第7张图片

二 机器人同步异常信息到钉钉指定群

如下为service所有代码,从execute(WarnContent content)实现类开始阅读即可,content后面全局异常调用会传入。

http主要的maven依赖

    org.apache.httpcomponents
    httpclient
    4.5.7


    org.apache.httpcomponents
    httpcore
    4.4.11
@Component
@Slf4j
public class DingTalkExceptionWarnImpl implements ExceptionWarn {
    /**
     * 执行同步钉钉任务
     * @param content
     */
    @Override
    public void execute(WarnContent content) {
        //数据安全加密秘钥
        String secret="SECad6f95819fcfd1620cb267d9850d0336b9e8e046234f5c3e7ef48c4b4dae7543";
        //请求通行认证
        String accessToken="8a9fcc774fe636f73c486c0d400b96a74d546d3d32f0f62abfef666b43609ec2";
        try {
            long timestamp = System.currentTimeMillis();
            String stringToSign = timestamp + "\n" +secret;
            Mac mac = Mac.getInstance("HmacSHA256");
            String charsetName = "UTF-8";
            mac.init(new SecretKeySpec(secret.getBytes(charsetName), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes(charsetName));
            //签名
            String signature = new String(Base64.encodeBase64(signData));

            Map headers = Maps.newHashMap();
            headers.put("Content-Type", "application/json");

            Map querys = Maps.newHashMap();
            querys.put("access_token", accessToken);
            querys.put("timestamp", timestamp + "");
            querys.put("sign", signature);
            HttpResponse response = doPost(
                    "https://oapi.dingtalk.com", "/robot/send", headers, querys, dingTalkFormat(content));

            WarnResult res = getResult(response, WarnResult.class);

            if (res.getErrcode() != 0) {
                log.error(res.getErrcode() + "", res.getErrmsg());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 转换钉钉格式
     */
    private String dingTalkFormat(WarnContent content) {
        String title = content.getTitle();
        content.setTitle("[dev 1.0][zjmProject]" + title);

        Map text = Maps.newHashMap();
        text.put("content", content.getTitle() + "\n" + content.getText());

        Map data = Maps.newLinkedHashMap();
        data.put("msgtype", "text");
        data.put("text", text);
        Map at = new HashMap<>();
        at.put("isAtAll", true);
        data.put("at", at);
        return JSON.toJSONString(data);
    }

    /**
     * 发送post请求
     */
    private static HttpResponse doPost(String host, String path,
                                      Map headers,
                                      Map querys,
                                      String body)
            throws Exception {
        HttpClient httpClient = wrapClient(host,path);
        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        if(headers != null) {
            for (Map.Entry e : headers.entrySet()) {
                request.addHeader(e.getKey(), e.getValue());
            }
        }
        if (StringUtils.isNotBlank(body)) {
            request.setEntity(new StringEntity(body, "utf-8"));
        }
        return httpClient.execute(request);
    }
    /**
     * 获取结果
     */
    private static  T getResult(HttpResponse httpResponse, Class cls) throws IOException {
        return JSON.parseObject(getString(httpResponse), cls);
    }

    /**
     * 将结果转换成string
     */
    private static String getString(HttpResponse httpResponse) throws IOException {
        HttpEntity entity = httpResponse.getEntity();
        String resp = EntityUtils.toString(entity, "UTF-8");
        EntityUtils.consume(entity);
        return resp;
    }
    /**
     * 获取 HttpClient
     */
    private static HttpClient wrapClient(String host,String path) {
        HttpClient httpClient = HttpClientBuilder.create().build();
        if (host != null && host.startsWith("https://")) {
            return sslClient();
        }else if (StringUtils.isBlank(host) && path != null && path.startsWith("https://")) {
            return sslClient();
        }
        return httpClient;
    }
    /**
     * 创建URL
     */
    private static String buildUrl(String host, String path, Map querys) throws UnsupportedEncodingException {
        StringBuilder sbUrl = new StringBuilder();
        if (!StringUtils.isBlank(host)) {
            sbUrl.append(host);
        }
        if (!StringUtils.isBlank(path)) {
            sbUrl.append(path);
        }
        if (null != querys) {
            StringBuilder sbQuery = new StringBuilder();
            for (Map.Entry query : querys.entrySet()) {
                if (0 < sbQuery.length()) {
                    sbQuery.append("&");
                }
                if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
                    sbQuery.append(query.getValue());
                }
                if (!StringUtils.isBlank(query.getKey())) {
                    sbQuery.append(query.getKey());
                    if (!StringUtils.isBlank(query.getValue())) {
                        sbQuery.append("=");
                        sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
                    }
                }
            }
            if (0 < sbQuery.length()) {
                sbUrl.append("?").append(sbQuery);
            }
        }
        return sbUrl.toString();
    }
    /**
     * 在调用SSL之前需要重写验证方法,取消检测SSL
     * 创建ConnectionManager,添加Connection配置信息
     * @return HttpClient 支持https
     */
    private static HttpClient sslClient() {
        try {
            // 在调用SSL之前需要重写验证方法,取消检测SSL
            X509TrustManager trustManager = new X509TrustManager() {
                @Override public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                @Override public void checkClientTrusted(X509Certificate[] xcs, String str) {}
                @Override public void checkServerTrusted(X509Certificate[] xcs, String str) {}
            };
            SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
            ctx.init(null, new TrustManager[] { trustManager }, null);
            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
            // 创建Registry
            RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT)
                    .setExpectContinueEnabled(Boolean.TRUE).setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM,AuthSchemes.DIGEST))
                    .setProxyPreferredAuthSchemes(Collections.singletonList(AuthSchemes.BASIC)).build();
            Registry socketFactoryRegistry = RegistryBuilder.create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https",socketFactory).build();
            // 创建ConnectionManager,添加Connection配置信息
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(connectionManager)
                    .setDefaultRequestConfig(requestConfig).build();
            return closeableHttpClient;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

三 全局异常捕获并同步到钉钉机器人

如下为全局异常同步service所有代码,至此项目中所有的运行时异常会同步到钉钉群中

@Slf4j
@RestControllerAdvice
public class GlobalException {

    @Autowired
    private ExceptionWarn exceptionWarn;

    /**
     * 运行时异常全局捕获,
      项目中所有运行时异常会同步到此方法
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public void handle(Exception e) {
        log.error("GlobalException handle() failed,error message {}", e.getMessage(), e);
        doWarn(e);
    }

    /**
     * 钉钉机器人同步
     */
    private void doWarn(Exception e) {
        try {
            //调用钉钉机器人传递异常信息
            exceptionWarn.execute(WarnContent.builder().title(e.getMessage()).text(getStackTraceAsString(e)).build());
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }
    }
    /**
     * 转换栈追踪信息
     */
    private static String getStackTraceAsString(Throwable ex) {
        StringWriter stringWriter = new StringWriter();
        ex.printStackTrace(new PrintWriter(stringWriter));
        return stringWriter.toString();
    }

}

四 两个代码额外的bean补充

@Data
@Builder
/**
 * 异常内容
 */
public class WarnContent implements Serializable {
    /**
     * 标题
     */
    private String title;

    /**
     * 内容
     */
    private String text;

}



/**
 * 提醒结果
 */
public class WarnResult implements Serializable {

    /**
     * 异常代码, 0 正常 其他正常
     */
    private Integer errcode;

    private String errmsg;

    public Integer getErrcode() {
        return errcode;
    }

    public void setErrcode(Integer errcode) {
        this.errcode = errcode;
    }

    public String getErrmsg() {
        return errmsg;
    }

    public void setErrmsg(String errmsg) {
        this.errmsg = errmsg;
    }

}

钉钉收到异常信息展示类似如下

钉钉机器人如何实时监听项目异常信息_第8张图片

 

你可能感兴趣的:(spring,钉钉机器人,实时监听异常信息)