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

一 建立机器人步骤

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

    

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

         

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

  

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

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

http主要的maven依赖
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.7</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.4.11</version>
</dependency>
@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<String, String> headers = Maps.newHashMap();
            headers.put("Content-Type", "application/json");

            Map<String, String> 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<String, String> text = Maps.newHashMap();
        text.put("content", content.getTitle() + "\n" + content.getText());

        Map<String, Object> data = Maps.newLinkedHashMap();
        data.put("msgtype", "text");
        data.put("text", text);
        Map<String, Object> 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<String, String> headers,
                                      Map<String, String> querys,
                                      String body)
            throws Exception {
        HttpClient httpClient = wrapClient(host,path);
        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        if(headers != null) {
            for (Map.Entry<String, String> 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> T getResult(HttpResponse httpResponse, Class<T> 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<String, String> 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<String, String> 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<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>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;
    }

}

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

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值