未验证 提交 4e43f227 编写于 作者: H HendSame 提交者: GitHub

Support Alarm to feishu (#6193)

上级 9021e679
......@@ -67,6 +67,7 @@ Release Notes.
* Fix bug endpoint name grouping not work due to setting service name and endpoint name out of order.
* Fix receiver analysis error count metrics
* Log collecting and query implementation
* Support Alarm to feishu
#### UI
* Fix un-removed tags in trace query.
......
......@@ -237,6 +237,25 @@ dingtalkHooks:
secret: dummysecret
```
## Feishu Hook
To do this you need to follow the [Feishu Webhooks guide](https://www.feishu.cn/hc/zh-cn/articles/360024984973) and create new Webhooks.
For security issue, you can config optional secret for individual webhook url.
if you want to at someone, you can config `ats` which is the feishu's user_id and separated by "," .
The alarm message will send through HTTP post by `application/json` content type if you configured Feishu Webhooks as following:
```yml
feishuHooks:
textTemplate: |-
{
"msg_type": "text",
"content": {
"text": "Apache SkyWalking Alarm: \n %s."
},
"ats":"feishu_user_id_1,feishu_user_id_2"
}
webhooks:
- url: https://open.feishu.cn/open-apis/bot/v2/hook/dummy_token
secret: dummysecret
```
## Update the settings dynamically
Since 6.5.0, the alarm settings can be updated dynamically at runtime by [Dynamic Configuration](dynamic-config.md),
......
......@@ -31,6 +31,7 @@ import org.apache.skywalking.oap.server.core.alarm.AlarmModule;
import org.apache.skywalking.oap.server.core.alarm.provider.dingtalk.DingtalkSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.expression.Expression;
import org.apache.skywalking.oap.server.core.alarm.provider.expression.ExpressionContext;
import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.grpc.GRPCAlarmSetting;
import org.apache.skywalking.oap.server.core.alarm.provider.slack.SlackSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.wechat.WechatSettings;
......@@ -134,4 +135,8 @@ public class AlarmRulesWatcher extends ConfigChangeWatcher {
return this.rules.getDingtalks();
}
public FeishuSettings getFeishuSettings() {
return this.rules.getFeishus();
}
}
......@@ -32,6 +32,7 @@ import org.apache.skywalking.oap.server.core.alarm.MetricsNotify;
import org.apache.skywalking.oap.server.core.alarm.ServiceInstanceMetaInAlarm;
import org.apache.skywalking.oap.server.core.alarm.ServiceMetaInAlarm;
import org.apache.skywalking.oap.server.core.alarm.provider.dingtalk.DingtalkHookCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuHookCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.grpc.GRPCCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.slack.SlackhookCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.wechat.WechatHookCallback;
......@@ -164,6 +165,7 @@ public class NotifyHandler implements MetricsNotify {
allCallbacks.add(new SlackhookCallback(alarmRulesWatcher));
allCallbacks.add(new WechatHookCallback(alarmRulesWatcher));
allCallbacks.add(new DingtalkHookCallback(alarmRulesWatcher));
allCallbacks.add(new FeishuHookCallback(alarmRulesWatcher));
core.start(allCallbacks);
}
}
......@@ -24,6 +24,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.apache.skywalking.oap.server.core.alarm.provider.dingtalk.DingtalkSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.grpc.GRPCAlarmSetting;
import org.apache.skywalking.oap.server.core.alarm.provider.slack.SlackSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.wechat.WechatSettings;
......@@ -39,6 +40,7 @@ public class Rules {
private WechatSettings wecchats;
private List<CompositeAlarmRule> compositeRules;
private DingtalkSettings dingtalks;
private FeishuSettings feishus;
public Rules() {
this.rules = new ArrayList<>();
......
......@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.skywalking.oap.server.core.alarm.provider.dingtalk.DingtalkSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.grpc.GRPCAlarmSetting;
import org.apache.skywalking.oap.server.core.alarm.provider.slack.SlackSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.wechat.WechatSettings;
......@@ -61,6 +62,7 @@ public class RulesReader {
readWechatConfig(rules);
readCompositeRuleConfig(rules);
readDingtalkConfig(rules);
readFeishuConfig(rules);
}
return rules;
}
......@@ -90,9 +92,9 @@ public class RulesReader {
alarmRule.setIncludeNamesRegex((String) settings.getOrDefault("include-names-regex", ""));
alarmRule.setExcludeNamesRegex((String) settings.getOrDefault("exclude-names-regex", ""));
alarmRule.setIncludeLabels(
(ArrayList) settings.getOrDefault("include-labels", new ArrayList(0)));
(ArrayList) settings.getOrDefault("include-labels", new ArrayList(0)));
alarmRule.setExcludeLabels(
(ArrayList) settings.getOrDefault("exclude-labels", new ArrayList(0)));
(ArrayList) settings.getOrDefault("exclude-labels", new ArrayList(0)));
alarmRule.setIncludeLabelsRegex((String) settings.getOrDefault("include-labels-regex", ""));
alarmRule.setExcludeLabelsRegex((String) settings.getOrDefault("exclude-labels-regex", ""));
alarmRule.setThreshold(settings.get("threshold").toString());
......@@ -103,8 +105,8 @@ public class RulesReader {
alarmRule.setSilencePeriod((Integer) settings.getOrDefault("silence-period", alarmRule.getPeriod()));
alarmRule.setOnlyAsCondition((Boolean) settings.getOrDefault("only-as-condition", false));
alarmRule.setMessage(
(String) settings.getOrDefault("message", "Alarm caused by Rule " + alarmRule
.getAlarmRuleName()));
(String) settings.getOrDefault("message", "Alarm caused by Rule " + alarmRule
.getAlarmRuleName()));
rules.getRules().add(alarmRule);
}
......@@ -200,7 +202,7 @@ public class RulesReader {
}
compositeAlarmRule.setExpression(expression);
compositeAlarmRule.setMessage(
(String) settings.getOrDefault("message", "Alarm caused by Rule " + ruleName));
(String) settings.getOrDefault("message", "Alarm caused by Rule " + ruleName));
rules.getCompositeRules().add(compositeAlarmRule);
}
});
......@@ -226,4 +228,25 @@ public class RulesReader {
rules.setDingtalks(dingtalkSettings);
}
}
/**
* Read feishu hook config into {@link FeishuSettings}
*/
private void readFeishuConfig(Rules rules) {
Map feishuConfig = (Map) yamlData.get("feishuHooks");
if (feishuConfig != null) {
FeishuSettings feishuSettings = new FeishuSettings();
Object textTemplate = feishuConfig.getOrDefault("textTemplate", "");
feishuSettings.setTextTemplate((String) textTemplate);
List<Map<String, Object>> wechatWebhooks = (List<Map<String, Object>>) feishuConfig.get("webhooks");
if (wechatWebhooks != null) {
wechatWebhooks.forEach(wechatWebhook -> {
Object secret = wechatWebhook.getOrDefault("secret", "");
Object url = wechatWebhook.getOrDefault("url", "");
feishuSettings.getWebhooks().add(new FeishuSettings.WebHookUrl((String) secret, (String) url));
});
}
rules.setFeishus(feishuSettings);
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.alarm.provider.feishu;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.netty.handler.codec.http.HttpHeaderValues;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
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.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.skywalking.apm.util.StringUtil;
import org.apache.skywalking.oap.server.core.alarm.AlarmCallback;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
import org.apache.skywalking.oap.server.core.alarm.provider.AlarmRulesWatcher;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Use SkyWalking alarm feishu webhook API.
*/
@Slf4j
public class FeishuHookCallback implements AlarmCallback {
private static final int HTTP_CONNECT_TIMEOUT = 1000;
private static final int HTTP_CONNECTION_REQUEST_TIMEOUT = 1000;
private static final int HTTP_SOCKET_TIMEOUT = 10000;
private AlarmRulesWatcher alarmRulesWatcher;
private RequestConfig requestConfig;
public FeishuHookCallback(final AlarmRulesWatcher alarmRulesWatcher) {
this.alarmRulesWatcher = alarmRulesWatcher;
this.requestConfig = RequestConfig.custom()
.setConnectTimeout(HTTP_CONNECT_TIMEOUT)
.setConnectionRequestTimeout(HTTP_CONNECTION_REQUEST_TIMEOUT)
.setSocketTimeout(HTTP_SOCKET_TIMEOUT)
.build();
}
/**
* Send alarm message if the settings not empty
*/
@Override
public void doAlarm(List<AlarmMessage> alarmMessages) {
if (this.alarmRulesWatcher.getFeishuSettings() == null || this.alarmRulesWatcher.getFeishuSettings().getWebhooks().isEmpty()) {
return;
}
CloseableHttpClient httpClient = HttpClients.custom().build();
try {
FeishuSettings feishuSettings = this.alarmRulesWatcher.getFeishuSettings();
feishuSettings.getWebhooks().forEach(webHookUrl -> {
alarmMessages.forEach(alarmMessage -> {
String requestBody = getRequestBody(webHookUrl, alarmMessage);
sendAlarmMessage(httpClient, webHookUrl.getUrl(), requestBody);
});
});
} finally {
try {
httpClient.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
/**
* deal requestBody,if has sign set the sign
*/
private String getRequestBody(FeishuSettings.WebHookUrl webHookUrl, AlarmMessage alarmMessage) {
String requestBody = String.format(
this.alarmRulesWatcher.getFeishuSettings().getTextTemplate(), alarmMessage.getAlarmMessage()
);
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(requestBody, JsonObject.class);
Map<String, Object> content = buildContent(jsonObject);
if (!StringUtil.isBlank(webHookUrl.getSecret())) {
Long timestamp = System.currentTimeMillis() / 1000;
content.put("timestamp", timestamp);
try {
content.put("sign", sign(timestamp, webHookUrl.getSecret()));
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException(e);
}
}
return gson.toJson(content);
}
/**
* build content,if has ats someone set the ats
*/
private Map<String, Object> buildContent(JsonObject jsonObject) {
Map<String, Object> content = new HashMap<>();
content.put("msg_type", jsonObject.get("msg_type").getAsString());
if (jsonObject.get("ats") != null) {
String ats = jsonObject.get("ats").getAsString();
String text = jsonObject.get("content").getAsJsonObject().get("text").getAsString();
List<String> collect = Arrays.stream(ats.split(","))
.map(String::trim).collect(Collectors.toList());
for (String userId : collect) {
text += "<at user_id=\"" + userId + "\"></at>";
}
jsonObject.get("content").getAsJsonObject().addProperty("text", text);
}
content.put("content", jsonObject.get("content").getAsJsonObject());
return content;
}
/**
* Sign webhook url using HmacSHA256 algorithm
*/
private String sign(final Long timestamp, String secret) throws NoSuchAlgorithmException, InvalidKeyException {
String stringToSign = timestamp + "\n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(stringToSign.getBytes(), "HmacSHA256"));
byte[] signData = mac.doFinal();
return Base64.encodeBase64String(signData);
}
/**
* Send alarm message to remote endpoint
*/
private void sendAlarmMessage(CloseableHttpClient httpClient, String url, String requestBody) {
try {
HttpPost post = new HttpPost(url);
post.setConfig(requestConfig);
post.setHeader(HttpHeaders.ACCEPT, HttpHeaderValues.APPLICATION_JSON.toString());
post.setHeader(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON.toString());
StringEntity entity = new StringEntity(requestBody, ContentType.APPLICATION_JSON);
post.setEntity(entity);
CloseableHttpResponse httpResponse = httpClient.execute(post);
StatusLine statusLine = httpResponse.getStatusLine();
if (statusLine != null && statusLine.getStatusCode() != HttpStatus.SC_OK) {
log.error("send feishu alarm to {} failure. Response code: {}, Response content: {}", url, statusLine.getStatusCode(),
EntityUtils.toString(httpResponse.getEntity()));
}
} catch (Throwable e) {
log.error("send feishu alarm to {} failure.", url, e);
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.alarm.provider.feishu;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import java.util.ArrayList;
import java.util.List;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class FeishuSettings {
private String textTemplate;
@Builder.Default
private List<WebHookUrl> webhooks = new ArrayList<>();
@AllArgsConstructor
@Setter
@Getter
@ToString
public static class WebHookUrl {
private final String secret;
private final String url;
}
}
......@@ -19,6 +19,7 @@
package org.apache.skywalking.oap.server.core.alarm.provider;
import org.apache.skywalking.oap.server.core.alarm.provider.dingtalk.DingtalkSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.grpc.GRPCAlarmSetting;
import org.apache.skywalking.oap.server.core.alarm.provider.slack.SlackSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.wechat.WechatSettings;
......@@ -86,5 +87,14 @@ public class RulesReaderTest {
assertThat(webHookUrls.get(0).getSecret(), is("dummysecret"));
assertThat(webHookUrls.get(1).getUrl(), is("https://oapi.dingtalk.com/robot/send?access_token=dummy_token2"));
assertNull(webHookUrls.get(1).getSecret());
FeishuSettings feishuSettings = rules.getFeishus();
assertThat(feishuSettings.getTextTemplate(), any(String.class));
List<FeishuSettings.WebHookUrl> feishuSettingsWebhooks = feishuSettings.getWebhooks();
assertThat(feishuSettingsWebhooks.size(), is(2));
assertThat(feishuSettingsWebhooks.get(0).getUrl(), is("https://open.feishu.cn/open-apis/bot/v2/hook/dummy_token"));
assertThat(feishuSettingsWebhooks.get(0).getSecret(), is("dummysecret"));
assertThat(feishuSettingsWebhooks.get(1).getUrl(), is("https://open.feishu.cn/open-apis/bot/v2/hook/dummy_token2"));
assertNull(feishuSettingsWebhooks.get(1).getSecret());
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.alarm.provider.feishu;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.apache.skywalking.apm.util.StringUtil;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
import org.apache.skywalking.oap.server.core.alarm.provider.AlarmRulesWatcher;
import org.apache.skywalking.oap.server.core.alarm.provider.Rules;
import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertTrue;
public class FeishuHookCallbackTest implements Servlet {
private Server server;
private int port;
private volatile boolean isSuccess = false;
private int count;
private volatile boolean checkSign = false;
private final String secret = "dummy-secret";
@Before
public void init() throws Exception {
server = new Server(new InetSocketAddress("127.0.0.1", 0));
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
servletContextHandler.setContextPath("/feishuhook");
server.setHandler(servletContextHandler);
ServletHolder servletHolder = new ServletHolder();
servletHolder.setServlet(this);
servletContextHandler.addServlet(servletHolder, "/receiveAlarm");
server.start();
port = server.getURI().getPort();
assertTrue(port > 0);
}
@Test
public void testFeishuWebhookWithoutSign() {
List<FeishuSettings.WebHookUrl> webHooks = new ArrayList<>();
webHooks.add(new FeishuSettings.WebHookUrl("", "http://127.0.0.1:" + port + "/feishuhook/receiveAlarm?token=dummy_token"));
Rules rules = new Rules();
String template = "{\"msg_type\":\"text\",\"content\":{\"text\":\"Skywaling alarm: %s\"}}";
rules.setFeishus(FeishuSettings.builder().webhooks(webHooks).textTemplate(template).build());
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
FeishuHookCallback feishuHookCallback = new FeishuHookCallback(alarmRulesWatcher);
List<AlarmMessage> alarmMessages = new ArrayList<>(2);
AlarmMessage alarmMessage = new AlarmMessage();
alarmMessage.setScopeId(DefaultScopeDefine.ALL);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
alarmMessages.add(anotherAlarmMessage);
feishuHookCallback.doAlarm(alarmMessages);
Assert.assertTrue(isSuccess);
}
@Test
public void testFeishuWebhookWithSign() {
checkSign = true;
List<FeishuSettings.WebHookUrl> webHooks = new ArrayList<>();
webHooks.add(new FeishuSettings.WebHookUrl(secret, "http://127.0.0.1:" + port + "/feishuhook/receiveAlarm?token=dummy_token"));
Rules rules = new Rules();
String template = "{\"msg_type\":\"text\",\"content\":{\"text\":\"Skywaling alarm: %s\"}}";
rules.setFeishus(FeishuSettings.builder().webhooks(webHooks).textTemplate(template).build());
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
FeishuHookCallback feishuHookCallback = new FeishuHookCallback(alarmRulesWatcher);
List<AlarmMessage> alarmMessages = new ArrayList<>(2);
AlarmMessage alarmMessage = new AlarmMessage();
alarmMessage.setScopeId(DefaultScopeDefine.ALL);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
alarmMessages.add(anotherAlarmMessage);
feishuHookCallback.doAlarm(alarmMessages);
Assert.assertTrue(isSuccess);
}
@Test
public void testFeishuWebhookWithSignAndAt() {
checkSign = true;
List<FeishuSettings.WebHookUrl> webHooks = new ArrayList<>();
webHooks.add(new FeishuSettings.WebHookUrl(secret, "http://127.0.0.1:" + port + "/feishuhook/receiveAlarm?token=dummy_token"));
Rules rules = new Rules();
String template = "{\"msg_type\":\"text\",\"content\":{\"text\":\"Skywaling alarm: %s\"},\"ats\":\"123\"}";
rules.setFeishus(FeishuSettings.builder().webhooks(webHooks).textTemplate(template).build());
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
FeishuHookCallback feishuHookCallback = new FeishuHookCallback(alarmRulesWatcher);
List<AlarmMessage> alarmMessages = new ArrayList<>(2);
AlarmMessage alarmMessage = new AlarmMessage();
alarmMessage.setScopeId(DefaultScopeDefine.ALL);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
alarmMessages.add(anotherAlarmMessage);
feishuHookCallback.doAlarm(alarmMessages);
Assert.assertTrue(isSuccess);
}
@After
public void stop() throws Exception {
server.stop();
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
if (httpServletRequest.getContentType().equals("application/json")) {
InputStream inputStream = request.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int readCntOnce;
while ((readCntOnce = inputStream.read(buffer)) >= 0) {
out.write(buffer, 0, readCntOnce);
}
JsonObject jsonObject = new Gson().fromJson(new String(out.toByteArray()), JsonObject.class);
String type = jsonObject.get("msg_type").getAsString();
if (checkSign) {
String timestamp = jsonObject.get("timestamp").getAsString();
String sign = jsonObject.get("sign").getAsString();
if (StringUtil.isEmpty(timestamp) || StringUtil.isEmpty(sign)) {
((HttpServletResponse) response).setStatus(500);
return;
}
}
if (type.equalsIgnoreCase("text")) {
((HttpServletResponse) response).setStatus(200);
count = count + 1;
if (count == 2) {
isSuccess = true;
}
return;
}
((HttpServletResponse) response).setStatus(500);
}
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
......@@ -107,3 +107,17 @@ dingtalkHooks:
secret: dummysecret
- url: https://oapi.dingtalk.com/robot/send?access_token=dummy_token2
secret:
feishuHooks:
textTemplate: |-
{
"msg_type": "text",
"content": {
"text": "Apache SkyWalking Alarm: \n %s."
}
}
webhooks:
- url: https://open.feishu.cn/open-apis/bot/v2/hook/dummy_token
secret: dummysecret
- url: https://open.feishu.cn/open-apis/bot/v2/hook/dummy_token2
secret:
......@@ -81,3 +81,17 @@ dingtalkHooks:
webhooks:
# - url: https://oapi.dingtalk.com/robot/send?access_token=dummy_token
# secret: dummysecret
feishuHooks:
textTemplate: |-
{
"msg_type": "text",
# at someone with feishu_user_ids
# "ats": "feishu_user_id_1,feishu_user_id_2",
"content": {
"text": "Apache SkyWalking Alarm: \n %s."
}
}
webhooks:
# - url: https://open.feishu.cn/open-apis/bot/v2/hook/dummy_token
# secret: dummysecret
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册