feat: 实现企业微信WebHook推送告警信息 #I4U9BT

This commit is contained in:
chenghua
2022-02-21 20:06:53 +08:00
parent d694fb9956
commit f2f5b2b680
5 changed files with 589 additions and 0 deletions

View File

@@ -51,6 +51,11 @@
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.0.1</version>
</dependency>
<!--network-->
<dependency>
<groupId>commons-net</groupId>

View File

@@ -0,0 +1,473 @@
package com.usthe.collector.collect.common.http;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Http各种请求方法的实现
*
* @author 花城
* @version 1.0
* @date 2022/2/21 7:16 下午
* @Description
*/
@Slf4j
public class HttpUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpUtils.class);
private CloseableHttpClient httpClient;
//连接超时时间为30s
private int connectionTimeout = 30000;
//读取超时时间为300s
private int socketTimeout = 300000;
private int MAX_TOTAL = 3000;
//单路由的最大并发连接数
private int MAX_PER_ROUTE = 1000;
//设置从链接池中获取连接时间为无限大
private int CONNECTION_REQUEST_TIMEOUT = 0;
private static ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
// asr返回格式为命名用下划线格式java为驼峰式json需要转换
// objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, false);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
}
public void init() {
RequestConfig config = RequestConfig.custom().setConnectTimeout(connectionTimeout).
setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT).setSocketTimeout(socketTimeout).build();
PoolingHttpClientConnectionManager pccm = new PoolingHttpClientConnectionManager();
pccm.setMaxTotal(MAX_TOTAL);
pccm.setDefaultMaxPerRoute(MAX_PER_ROUTE);
httpClient = HttpClients.custom().setConnectionManager(pccm).setDefaultRequestConfig(config).build();
}
public HttpResult doGet(String url, Map<String, String> params) {
try {
URIBuilder uriBuilder = new URIBuilder(url);
for (Map.Entry<String, String> entry : params.entrySet()) {
uriBuilder.addParameter(entry.getKey(), entry.getValue());
}
HttpGet httpget = new HttpGet(uriBuilder.build());
httpget.addHeader("contentEncoding", "UTF-8");
return doExecuteHttpRqeuestBase(httpget);
} catch (Exception e) {
LOGGER.error("Error when doGet : " + url, e);
return failHttp(e.getMessage());
}
}
public HttpResult doGetWithHeaders(String url, Map<String, String> params, Map<String, String> headers) {
try {
URIBuilder uriBuilder = new URIBuilder(url);
params.forEach(uriBuilder::addParameter);
HttpGet httpget = new HttpGet(uriBuilder.build());
httpget.addHeader("contentEncoding", "UTF-8");
headers.forEach(httpget::addHeader);
return doExecuteHttpRqeuestBase(httpget);
} catch (Exception e) {
LOGGER.error("Error when doGet : " + url, e);
return failHttp(e.getMessage());
}
}
public HttpResult doPutWithHeaders(String url, Map<String, String> params, Map<String, String> headers) {
try {
URIBuilder uriBuilder = new URIBuilder(url);
params.forEach(uriBuilder::addParameter);
HttpPut httpget = new HttpPut(uriBuilder.build());
httpget.addHeader("contentEncoding", "UTF-8");
headers.forEach(httpget::addHeader);
return doExecuteHttpRqeuestBase(httpget);
} catch (Exception e) {
LOGGER.error("Error when doPut : " + url, e);
return failHttp(e.getMessage());
}
}
public HttpResult doPost(String url, Map<String, String> formParams) {
// 创建httppost
HttpPost httpPost = new HttpPost(url);
// 设置参数
RequestConfig.Builder customReqConf = RequestConfig.custom();
customReqConf.setConnectTimeout(connectionTimeout);
customReqConf.setSocketTimeout(socketTimeout);
httpPost.setConfig(customReqConf.build());
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> entry : formParams.entrySet()) {
formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = null;
try {
entity = new UrlEncodedFormEntity(formparams, "UTF-8");
entity.setChunked(true);
} catch (UnsupportedEncodingException e) {
LOGGER.error("UrlEncode error : " + url, e);
}
httpPost.setEntity(entity);
return doExecuteHttpRqeuestBase(httpPost);
}
public HttpResult doPostWithHeader(String url, String bodyJsonString, Map<String, String> headers) {
// 创建httppost
HttpPost httpPost = new HttpPost(url);
// 设置参数
RequestConfig.Builder customReqConf = RequestConfig.custom();
customReqConf.setConnectTimeout(connectionTimeout);
customReqConf.setSocketTimeout(socketTimeout);
httpPost.setConfig(customReqConf.build());
headers.forEach(httpPost::addHeader);
StringEntity entity = new StringEntity(bodyJsonString, "UTF-8");//解决中文乱码问题
entity.setContentEncoding("UTF-8");
entity.setContentType(ContentType.APPLICATION_JSON.toString());
httpPost.setEntity(entity);
return doExecuteHttpRqeuestBase(httpPost);
}
public HttpResponse doPostWithOriginalResponse(String url, List<NameValuePair> nvpList, String charset) {
HttpResponse response = null;
try{
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader(HttpHeaders.CONNECTION, "close");
httpPost.setEntity(new UrlEncodedFormEntity(nvpList,charset));
response = httpClient.execute(httpPost);
}catch (Exception e){
LOGGER.error("doPostWithOriginalResponse error : ", e);
}
return response;
}
public HttpResult doPost(String url, String bodyJsonString) {
// 创建httppost
HttpPost httpPost = new HttpPost(url);
// 设置参数
RequestConfig.Builder customReqConf = RequestConfig.custom();
customReqConf.setConnectTimeout(connectionTimeout);
customReqConf.setSocketTimeout(socketTimeout);
httpPost.setConfig(customReqConf.build());
StringEntity entity = new StringEntity(bodyJsonString, "UTF-8");//解决中文乱码问题
entity.setContentEncoding("UTF-8");
entity.setContentType(ContentType.APPLICATION_JSON.toString());
httpPost.setEntity(entity);
return doExecuteHttpRqeuestBase(httpPost);
}
public HttpResult doPostWithEntity(String url, HttpEntity entity) {
// 创建httppost
HttpPost httpPost = new HttpPost(url);
// 设置参数
RequestConfig.Builder customReqConf = RequestConfig.custom();
customReqConf.setConnectTimeout(connectionTimeout);
customReqConf.setSocketTimeout(socketTimeout);
httpPost.setConfig(customReqConf.build());
httpPost.setEntity(entity);
return doExecuteHttpRqeuestBase(httpPost);
}
public HttpResult doDeleteWithHeaders(String url, Map<String, String> params, Map<String,String> headers) {
try {
URIBuilder uriBuilder = new URIBuilder(url);
params.forEach(uriBuilder::addParameter);
HttpDelete httpDelete = new HttpDelete(uriBuilder.build());
httpDelete.addHeader("contentEncoding", "UTF-8");
headers.forEach(httpDelete::addHeader);
return doExecuteHttpRqeuestBase(httpDelete);
} catch (Exception e) {
LOGGER.error("Error when doDelete : " + url, e);
return failHttp(e.getMessage());
}
}
private HttpResult doExecuteHttpRqeuestBase(HttpRequestBase httpRequestBase) {
try {
HttpResultResponseHandler sph = new HttpResultResponseHandler();
return httpClient.execute(httpRequestBase, sph);
} catch (Exception e) {
LOGGER.error("Error when " + httpRequestBase.getMethod() + " : " + httpRequestBase.getURI(), e);
return failHttp(e.getMessage());
} finally {
if (httpRequestBase != null) {
httpRequestBase.abort();
}
}
}
/**
* 请求体为json格式对象
*
* @param path
* @param form
* @return
*/
public static HttpPost newJsonBodyPostRequest(String path, Map<String, Object> form) {
HttpPost post = new HttpPost(path);
String json = toJsonString(form);
HttpEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
post.setEntity(entity);
post.addHeader(HttpHeaders.ACCEPT, CONTENT_TYPE);
post.addHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE);
return post;
}
static final String CONTENT_TYPE = "application/json";
public static String toJsonString(Object val) {
try {
byte[] bytes = objectMapper.writeValueAsBytes(val);
return new String(bytes, Charsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException("toJsonString error", e);
}
}
public static <T> T parseHttpResponseObject(String json, TypeReference<T> type) throws IOException {
if (Strings.isNullOrEmpty(json)) {
return null;
}
return objectMapper.readValue(json, type);
}
public static String toRequestString(HttpRequestBase r) {
if (r == null) {
return "null";
}
return r.getMethod() + " " + r.getURI();
}
private class HttpResultResponseHandler implements ResponseHandler<HttpResult> {
@Override
public HttpResult handleResponse(HttpResponse response) throws IOException {
HttpResult result = new HttpResult();
HttpEntity entity = response.getEntity();
Header[] headers = response.getAllHeaders();
if (isNotEmpty(headers)) {
HashMap<String, String> headerMap = new HashMap<String, String>();
for (Header h : headers) {
headerMap.put(h.getName(), h.getValue());
}
result.setHeader(headerMap);
}
InputStream i = entity.getContent();
String res = IOUtils.toString(new InputStreamReader(i, "UTF-8"));
result.setCode(response.getStatusLine().getStatusCode());
result.setBody(res);
i.close();
return result;
}
}
private boolean isNotEmpty(Object[] array) {
return array != null && array.length > 0;
}
private HttpResult failHttp(String message) {
HttpResult result = new HttpResult();
result.setCode(500);
result.setBody(message);
return result;
}
public static class HttpResult {
private String body;
private Map<String, String> header;
private int code;
public String getBody() {
return body;
}
void setBody(String body) {
this.body = body;
}
public Map<String, String> getHeader() {
return header;
}
void setHeader(Map<String, String> header) {
this.header = header;
}
public int getCode() {
return code;
}
void setCode(int code) {
this.code = code;
}
public boolean is200() {
return this.code == 200;
}
public boolean isNot200() {
return !this.is200();
}
public HttpResult checkHttpCode() {
if (isNot200()) {
throw new RuntimeException("执行http方法出错返回值非200body=" + body);
}
return this;
}
}
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public void setSocketTimeout(int socketTimeout) {
this.socketTimeout = socketTimeout;
}
public void setMAX_PER_ROUTE(int MAX_PER_ROUTE) {
this.MAX_PER_ROUTE = MAX_PER_ROUTE;
}
public void setMAX_TOTAL(int MAX_TOTAL) {
this.MAX_TOTAL = MAX_TOTAL;
}
public void setCONNECTION_REQUEST_TIMEOUT(int CONNECTION_REQUEST_TIMEOUT) {
this.CONNECTION_REQUEST_TIMEOUT = CONNECTION_REQUEST_TIMEOUT;
}
/**
* 发送post请求
*
* @param url 请求的url
* @param body json串
* @return
*/
public static String sendPostJsonBody(String url, String body) {
log.debug("[HttpClientUtil][sendPostJsonBody] 入参 url={} body={}", url, body);
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json;charset=utf-8");
StringEntity entity = new StringEntity(body, "utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
try {
HttpClient client = httpClientBuilder.build();
HttpResponse response = client.execute(httpPost);
if (response.getStatusLine() != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String result = EntityUtils.toString(response.getEntity(), "utf-8");
log.debug("[HttpClientUtil][sendPostJsonBody] 结果 url={} result={}", url, result);
return result;
}
log.warn("[HttpClientUtil][sendPostJsonBody] 请求失败 response={}", url, response.toString());
return "";
} catch (IOException ex) {
log.error("[HttpClientUtil][sendPostJsonBody] 请求异常 ex={}", url, ex);
return "";
}
}
/**
* 发送post请求
*
* @param url 请求的url
* @param body json串
* @return
*/
public static String sendPostJsonBodyNoEncoding(String url, String body) {
log.debug("[HttpClientUtil][sendPostJsonBody] 入参 url={} body={}", url, body);
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json;charset=utf-8");
StringEntity entity = new StringEntity(body, "utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
try {
HttpClient client = httpClientBuilder.build();
HttpResponse response = client.execute(httpPost);
if (response.getStatusLine() != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String result = EntityUtils.toString(response.getEntity(), "utf-8");
log.debug("[HttpClientUtil][sendPostJsonBody] 结果 url={} result={}", url, result);
return result;
}
log.warn("[HttpClientUtil][sendPostJsonBody] 请求失败 response={}", url, response.toString());
return "";
} catch (IOException ex) {
log.error("[HttpClientUtil][sendPostJsonBody] 请求异常 ex={}", url, ex);
return "";
}
}
public static String sendGet(String url) {
log.debug("[HttpClientUtil][sendPostJsonBody] 入参 url={} ", url);
HttpGet httpPost = new HttpGet(url);
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
try {
HttpClient client = httpClientBuilder.build();
HttpResponse response = client.execute(httpPost);
if (response.getStatusLine() != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String result = EntityUtils.toString(response.getEntity(), "utf-8");
log.debug("[HttpClientUtil][sendPostJsonBody] 结果 url={} result={}", url, result);
return result;
}
log.warn("[HttpClientUtil][sendPostJsonBody] 请求失败 response={}", url, response.toString());
return "";
} catch (IOException ex) {
log.error("[HttpClientUtil][sendPostJsonBody] 请求异常 ex={}", url, ex);
return "";
}
}
}

View File

@@ -0,0 +1,54 @@
package com.usthe.common.entity.dto;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author 花城
* @version 1.0
* @date 2022/2/21 6:55 下午
* @Description
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "企业微信WebHook模版")
public class WeChatWebHookDTO {
/**
* 消息类型
*/
private String msgtype;
private TextDTO text;
private MarkdownDTO markdown;
@Data
public static class TextDTO{
/**
* 消息内容
*/
private String content;
/**
* @人的名称英文拼写列表
*/
private List<String> mentioned_list;
}
@Data
public static class MarkdownDTO{
/**
* 消息内容
*/
private String content;
}
}

View File

@@ -0,0 +1,24 @@
package com.usthe.common.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
* @author 花城
* @version 1.0
* @date 2022/2/21 7:07 下午
* @Description
*/
@AllArgsConstructor
@Getter
public enum PriorityLevelEnum {
EMERGENCY(0,"紧急告警"),
CRITICAL(1,"严重告警"),
WARNING(2,"警告告警"),
;
private Integer level;
private String message;
}

View File

@@ -1,9 +1,14 @@
package com.usthe.manager.component.alerter;
import com.alibaba.fastjson.JSON;
import com.usthe.alert.AlerterDataQueue;
import com.usthe.alert.AlerterWorkerPool;
import com.usthe.collector.collect.common.http.HttpUtils;
import com.usthe.common.util.CommonUtil;
import com.usthe.common.util.PriorityLevelEnum;
import com.usthe.common.entity.alerter.Alert;
import com.usthe.alert.service.AlertService;
import com.usthe.common.entity.dto.WeChatWebHookDTO;
import com.usthe.common.util.CommonConstants;
import com.usthe.common.entity.manager.Monitor;
import com.usthe.common.entity.manager.NoticeReceiver;
@@ -121,11 +126,39 @@ public class DispatchAlarm {
case 1: sendEmailAlert(receiver, alert); break;
case 2: sendWebHookAlert(receiver, alert); break;
case 3: sendWeChatAlert(receiver, alert); break;
case 4: sendWeChatWebHookAlert(receiver, alert);break;
default: break;
}
}
}
/**
* 通过企业微信发送告警信息
* @param receiver 通知配置信息
* @param alert 告警信息
*/
private void sendWeChatWebHookAlert(NoticeReceiver receiver, Alert alert) {
WeChatWebHookDTO weChatWebHookDTO = new WeChatWebHookDTO();
weChatWebHookDTO.setMsgtype("markdown");
WeChatWebHookDTO.MarkdownDTO markdownDTO = new WeChatWebHookDTO.MarkdownDTO();
StringBuilder content = new StringBuilder();
content.append("\t\t\t\t<font color=\"info\">[TanCloud探云告警]</font>\n" +
"告警目标对象 : <font color=\"info\">" + alert.getTarget() + "</font>\n" +
"所属监控ID : " + alert.getMonitorId() + "\n" +
"所属监控名称 : " + alert.getMonitorName() + "\n");
if (alert.getPriority() < PriorityLevelEnum.WARNING.getLevel()){
content.append("告警级别 <font color=\"warning\">: " + CommonUtil.transferAlertPriority(alert.getPriority()) + "</font>\n");
}else {
content.append("告警级别 <font color=\"comment\">: " + CommonUtil.transferAlertPriority(alert.getPriority()) + "</font>\n");
}
content.append("内容详情 : " + alert.getContent());
markdownDTO.setContent(content.toString());
weChatWebHookDTO.setMarkdown(markdownDTO);
//TODO 以后转移到实体类中
String webHookUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=fcf9ddxxx-ebaf-48a2-810c-404xxxxxxd3bf";
HttpUtils.sendPostJsonBody(webHookUrl, JSON.toJSONString(weChatWebHookDTO));
}
private void sendWeChatAlert(NoticeReceiver receiver, Alert alert) {
}