You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2023/07/27 16:12:54 UTC
[skywalking] branch master updated: Support multiple configs for each hook types and specifying the hooks in the alarm rule. (#11137)
This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git
The following commit(s) were added to refs/heads/master by this push:
new 9c2376a960 Support multiple configs for each hook types and specifying the hooks in the alarm rule. (#11137)
9c2376a960 is described below
commit 9c2376a960e82dafd1b4f50caad2048f2b22be52
Author: Wan Kai <wa...@foxmail.com>
AuthorDate: Fri Jul 28 00:12:47 2023 +0800
Support multiple configs for each hook types and specifying the hooks in the alarm rule. (#11137)
* [Breaking change] Adjust the structure of hooks in the `alarm-settings.yml`. Support multiple configs for each hook types and specifying the hooks in the alarm rule.
---
dist-material/alarm-settings.yml | 10 +-
docs/en/changes/changes.md | 1 +
docs/en/setup/backend/backend-alarm.md | 189 +++++++----
...positeAlarmRule.java => AlarmHookSettings.java} | 29 +-
.../core/alarm/provider/AlarmHooksType.java} | 19 +-
.../oap/server/core/alarm/provider/AlarmRule.java | 29 +-
.../core/alarm/provider/AlarmRulesWatcher.java | 37 +-
.../core/alarm/provider/CompositeAlarmRule.java | 2 +
.../alarm/provider/CompositeRuleEvaluator.java | 1 +
.../server/core/alarm/provider/NotifyHandler.java | 1 +
.../oap/server/core/alarm/provider/Rules.java | 31 +-
.../server/core/alarm/provider/RulesReader.java | 375 ++++++++++++++-------
.../server/core/alarm/provider/RunningRule.java | 4 +
.../provider/dingtalk/DingtalkHookCallback.java | 29 +-
.../alarm/provider/dingtalk/DingtalkSettings.java | 16 +-
.../provider/discord/DiscordHookCallback.java | 28 +-
.../alarm/provider/discord/DiscordSettings.java | 16 +-
.../alarm/provider/feishu/FeishuHookCallback.java | 28 +-
.../core/alarm/provider/feishu/FeishuSettings.java | 14 +-
.../core/alarm/provider/grpc/GRPCAlarmSetting.java | 12 +-
.../core/alarm/provider/grpc/GRPCCallback.java | 98 ++++--
.../provider/pagerduty/PagerDutyHookCallback.java | 34 +-
.../provider/pagerduty/PagerDutySettings.java | 17 +-
.../core/alarm/provider/slack/SlackSettings.java | 17 +-
.../alarm/provider/slack/SlackhookCallback.java | 33 +-
.../provider/{ => webhook}/WebhookCallback.java | 23 +-
.../WebhookSettings.java} | 32 +-
.../alarm/provider/wechat/WechatHookCallback.java | 27 +-
.../core/alarm/provider/wechat/WechatSettings.java | 17 +-
.../alarm/provider/welink/WeLinkHookCallback.java | 33 +-
.../core/alarm/provider/welink/WeLinkSettings.java | 28 +-
.../server/core/alarm/provider/AlarmCoreTest.java | 1 -
.../core/alarm/provider/AlarmRulesWatcherTest.java | 9 +-
.../alarm/provider/CompositeRuleEvaluatorTest.java | 15 +-
.../core/alarm/provider/RulesReaderTest.java | 42 ++-
.../dingtalk/DingtalkHookCallbackTest.java | 23 +-
.../provider/feishu/FeishuHookCallbackTest.java | 34 +-
.../alarm/provider/grpc/GRPChookCallbackTest.java | 37 +-
.../pagerduty/PagerDutyHookCallbackTest.java | 41 ++-
.../SlackHookCallbackTest.java} | 41 ++-
.../{ => webhook}/WebhookCallbackTest.java | 14 +-
.../provider/wechat/WechatHookCallbackTest.java | 12 +-
.../provider/welink/WeLinkHookCallbackTest.java | 32 +-
.../src/test/resources/alarm-settings.yml | 189 +++++++----
.../oap/server/core/alarm/AlarmCallback.java | 18 +-
.../oap/server/core/alarm/AlarmMessage.java | 3 +
.../src/main/resources/alarm-settings.yml | 206 ++++++-----
test/e2e-v2/cases/alarm/alarm-settings.yml | 13 +-
48 files changed, 1278 insertions(+), 682 deletions(-)
diff --git a/dist-material/alarm-settings.yml b/dist-material/alarm-settings.yml
index c5e0646093..d955a6f081 100644
--- a/dist-material/alarm-settings.yml
+++ b/dist-material/alarm-settings.yml
@@ -80,7 +80,11 @@ rules:
# silence-period: 5
# message: Response time of endpoint {name} is more than 1000ms in 2 minutes of last 10 minutes
-webhooks:
-# - http://127.0.0.1/notify/
-# - http://127.0.0.1/go-wechat/
+#hooks:
+# webhook:
+# default:
+# is-default: true
+# urls:
+# - http://127.0.0.1/notify/
+# - http://127.0.0.1/go-wechat/
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index 27cefe9a4c..b625fc3adf 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -55,6 +55,7 @@
* Move created the latest index before retrieval indexes by aliases to avoid the 404 exception. This just prevents some interference from manual operations.
* Add more Go VM metrics, as new skywalking-go agent provided since its 0.2 release.
* Add component ID for Lock (ID=5016).
+* [Breaking change] Adjust the structure of hooks in the `alarm-settings.yml`. Support multiple configs for each hook types and specifying the hooks in the alarm rule.
* Bump up Armeria to 1.24.3.
#### UI
diff --git a/docs/en/setup/backend/backend-alarm.md b/docs/en/setup/backend/backend-alarm.md
index f93856fbd4..6e81eeba24 100644
--- a/docs/en/setup/backend/backend-alarm.md
+++ b/docs/en/setup/backend/backend-alarm.md
@@ -5,8 +5,7 @@ Alerting kernel is an in-memory, time-window based queue.
The alerting core is driven by a collection of rules defined in `config/alarm-settings.yml.`
There are three parts to alerting rule definitions.
1. [alerting rules](#rules). They define how metrics alerting should be triggered and what conditions should be considered.
-1. [Webhooks](#webhook). The list of web service endpoints, which should be called after an alerting is triggered.
-1. [gRPCHook](#grpchook). The host and port of the remote gRPC method, which should be called after an alerting is triggered.
+1. [hooks](#hooks). The list of hooks, which should be called after an alerting is triggered.
## Entity name
Defines the relation between scope and entity name.
@@ -47,6 +46,9 @@ For example, in **percentile**, `value1` is the threshold of P50, and `-, -, val
- **Period**. The size of metrics cache in minutes for checking the alarm conditions. This is a time window that corresponds to the backend deployment env time.
- **Count**. Within a period window, if the number of times which **value** goes over the threshold (based on OP) reaches `count`, then an alarm will be sent.
- **Only as condition**. Indicates if the rule can send notifications or if it simply serves as a condition of the composite rule.
+- **Hooks**. Binding the specific names of the hooks when the alarm is triggered.
+ The name format is `{hookType}.{hookName}` (slack.custom1 e.g.) and must be defined in the `hooks` section of the `alarm-settings.yml` file.
+ If the hook name is not specified, the global hook will be used.
- **Silence period**. After the alarm is triggered at Time-N (TN), there will be silence during the **TN -> TN + period**.
By default, it works in the same manner as **period**. The same Alarm (having the same ID in the same metrics name) may only be triggered once within a period.
@@ -69,6 +71,10 @@ A composite rule is made up of the following elements:
- **Expression**. Specifies how to compose rules, and supports `&&`, `||`, and `()`.
- **Message**. The notification message to be sent out when the rule is triggered.
- **Tags**. Tags are key/value pairs that are attached to alarms. Tags are used to specify distinguishing attributes of alarms that are meaningful and relevant to users.
+- **Hooks**. Binding the specific names of the hooks when the alarm is triggered.
+ The name format is `{hookType}.{hookName}` (slack.custom1 e.g.) and must be defined in the `hooks` section of the `alarm-settings.yml` file.
+ If the hook name is not specified, the global hooks will be used.
+
```yaml
rules:
# Rule unique name, must be ended with `_rule`.
@@ -123,6 +129,9 @@ rules:
silence-period: 5
message: The request number of entity {name} non-200 status is more than expected.
only-as-condition: false
+ hooks:
+ - "slack.custom1"
+ - "pagerduty.custom1"
composite-rules:
comp_rule:
# Must satisfied percent rule and resp time rule
@@ -130,6 +139,10 @@ composite-rules:
message: Service {name} successful rate is less than 80% and P50 of response time is over 1000ms
tags:
level: CRITICAL
+ hooks:
+ - "slack.default"
+ - "slack.custom1"
+ - "pagerduty.custom1"
```
@@ -152,7 +165,44 @@ Currently, metrics from the **Service**, **Service Instance**, **Endpoint**, **S
Submit an issue or a pull request if you want to support any other scopes in Alarm.
-## Webhook
+## Hooks
+Hooks are a way to send alarm messages to the outside world. SkyWalking supports multiple hooks of the same type, each hook can support different configurations.
+For example, you can configure two Slack hooks, one named `default` and set `is-default: true` means this hook will apply on all `Alarm Rules` **without config** `hooks`.
+Another named `custom1` will only apply on the `Alarm Rules` which **with config** `hooks` and include the name `slack.custom1`.
+
+```yaml
+hooks:
+ slack:
+ # default here is just a name, set the field 'is-default: true' if this notification hook is expected to be default globally.
+ default:
+ # If true, this hook will apply on all rules, unless a rule has its own specific hook. Could have more than one default hooks in the same hook type.
+ is-default: true
+ text-template: |-
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
+ }
+ }
+ webhooks:
+ - https://hooks.slack.com/services/x/y/zssss
+ custom1:
+ text-template: |-
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
+ }
+ }
+ webhooks:
+ - https://hooks.slack.com/services/x/y/custom1
+```
+
+Currently, SkyWalking supports the following hook types:
+
+### Webhook
The Webhook requires the peer to be a web container. The alarm message will be sent through HTTP post by `application/json` content type. The JSON format is based on `List<org.apache.skywalking.oap.server.core.alarm.AlarmMessage>` with the following key information:
- **scopeId**, **scope**. All scopes are defined in `org.apache.skywalking.oap.server.core.source.DefaultScopeDefine`.
- **name**. Target scope entity name. Please follow the [entity name definitions](#entity-name).
@@ -194,7 +244,7 @@ See the following example:
}]
```
-## gRPCHook
+### gRPC
The alarm message will be sent through remote gRPC method by `Protobuf` content type.
The message contains key information which are defined in `oap-server/server-alarm-plugin/src/main/proto/alarm-hook.proto`.
@@ -223,120 +273,134 @@ message KeyStringValuePair {
}
```
-## Slack Chat Hook
+### Slack Chat
Follow the [Getting Started with Incoming Webhooks guide](https://api.slack.com/messaging/webhooks) and create new Webhooks.
The alarm message will be sent through HTTP post by `application/json` content type if you have configured Slack Incoming Webhooks as follows:
```yml
-slackHooks:
- textTemplate: |-
- {
- "type": "section",
- "text": {
- "type": "mrkdwn",
- "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
+slack:
+ default:
+ is-default: true
+ text-template: |-
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
+ }
}
- }
- webhooks:
+ webhooks:
- https://hooks.slack.com/services/x/y/z
```
-## WeChat Hook
+### WeChat
Note that only the WeChat Company Edition (WeCom) supports WebHooks. To use the WeChat WebHook, follow the [Wechat Webhooks guide](https://work.weixin.qq.com/help?doc_id=13376).
The alarm message will be sent through HTTP post by `application/json` content type after you have set up Wechat Webhooks as follows:
```yml
-wechatHooks:
- textTemplate: |-
- {
- "msgtype": "text",
- "text": {
- "content": "Apache SkyWalking Alarm: \n %s."
+wechat:
+ default:
+ is-default: true
+ text-template: |-
+ {
+ "msgtype": "text",
+ "text": {
+ "content": "Apache SkyWalking Alarm: \n %s."
+ }
}
- }
- webhooks:
+ webhooks:
- https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=dummy_key
```
-## DingTalk Hook
+### DingTalk
Follow the [Dingtalk Webhooks guide](https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/uKPlK) and create new Webhooks.
You can configure an optional secret for an individual webhook URL for security purposes.
The alarm message will be sent through HTTP post by `application/json` content type if you have configured DingTalk Webhooks as follows:
```yml
-dingtalkHooks:
- textTemplate: |-
- {
- "msgtype": "text",
- "text": {
- "content": "Apache SkyWalking Alarm: \n %s."
+dingtalk:
+ default:
+ is-default: true
+ text-template: |-
+ {
+ "msgtype": "text",
+ "text": {
+ "content": "Apache SkyWalking Alarm: \n %s."
+ }
}
- }
- webhooks:
+ webhooks:
- url: https://oapi.dingtalk.com/robot/send?access_token=dummy_token
secret: dummysecret
```
-## Feishu Hook
+### Feishu
Follow the [Feishu Webhooks guide](https://www.feishu.cn/hc/zh-cn/articles/360024984973) and create new Webhooks.
You can configure an optional secret for an individual webhook URL for security purposes.
If you want to direct a text to a user, you can configure `ats`, which is Feishu's user_id and separated by "," .
The alarm message will be sent through HTTP post by `application/json` content type if you have configured Feishu Webhooks as follows:
```yml
-feishuHooks:
- textTemplate: |-
- {
- "msg_type": "text",
- "content": {
- "text": "Apache SkyWalking Alarm: \n %s."
- },
- "ats":"feishu_user_id_1,feishu_user_id_2"
- }
- webhooks:
+feishu:
+ default:
+ is-default: true
+ text-template: |-
+ {
+ "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
```
-## WeLink Hook
+### WeLink
Follow the [WeLink Webhooks guide](https://open.welink.huaweicloud.com/apiexplorer/#/apiexplorer?type=internal&method=POST&path=/welinkim/v1/im-service/chat/group-chat) and create new Webhooks.
The alarm message will be sent through HTTP post by `application/json` content type if you have configured WeLink Webhooks as follows:
```yml
-welinkHooks:
- textTemplate: "Apache SkyWalking Alarm: \n %s."
- webhooks:
+welink:
+ default:
+ is-default: true
+ text-template: "Apache SkyWalking Alarm: \n %s."
+ webhooks:
# you may find your own client_id and client_secret in your app, below are dummy, need to change.
- - client_id: "dummy_client_id"
- client_secret: dummy_secret_key
- access_token_url: https://open.welink.huaweicloud.com/api/auth/v2/tickets
- message_url: https://open.welink.huaweicloud.com/api/welinkim/v1/im-service/chat/group-chat
+ - client-id: "dummy_client_id"
+ client-secret: dummy_secret_key
+ access-token-url: https://open.welink.huaweicloud.com/api/auth/v2/tickets
+ message-url: https://open.welink.huaweicloud.com/api/welinkim/v1/im-service/chat/group-chat
# if you send to multi group at a time, separate group_ids with commas, e.g. "123xx","456xx"
- group_ids: "dummy_group_id"
+ group-ids: "dummy_group_id"
# make a name you like for the robot, it will display in group
- robot_name: robot
+ robot-name: robot
```
-## PagerDuty Hook
+### PagerDuty
The PagerDuty hook is based on [Events API v2](https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgw-events-api-v2-overview).
Follow the [Getting Started](https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgw-events-api-v2-overview#getting-started) section to create an **Events API v2** integration on your PagerDuty service and copy the integration key.
Then configure as follows:
```yml
-pagerDutyHooks:
- textTemplate: "Apache SkyWalking Alarm: \n %s."
- integrationKeys:
+pagerduty:
+ default:
+ is-default: true
+ text-template: "Apache SkyWalking Alarm: \n %s."
+ integration-keys:
- 5c6d805c9dcf4e03d09dfa81e8789ba1
```
You can also configure multiple integration keys.
-## Discord Hook
+### Discord
Follow the [Discord Webhooks guide](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) and create a new webhook.
Then configure as follows:
```yml
-discordHooks:
- textTemplate: "Apache SkyWalking Alarm: \n %s."
- webhooks:
+discord:
+ default:
+ is-default: true
+ text-template: "Apache SkyWalking Alarm: \n %s."
+ webhooks:
- url: https://discordapp.com/api/webhooks/1008166889777414645/8e0Am4Zb-YGbBqqbiiq0jSHPTEEaHa4j1vIC-zSSm231T8ewGxgY0_XUYpY-k1nN4HBl
username: robot
```
@@ -368,4 +432,5 @@ the sliding window will be destroyed and re-created, causing the Alarm of this s
| Count | count | int | |
| Only as condition | only-as-condition | boolean | |
| Silence period | silence-period | int | |
-| Message | message | string | |
\ No newline at end of file
+| Message | message | string | |
+| Hooks | hooks | string array | |
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeAlarmRule.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmHookSettings.java
similarity index 69%
copy from oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeAlarmRule.java
copy to oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmHookSettings.java
index 116a19253c..efb0d7e1a2 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeAlarmRule.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmHookSettings.java
@@ -18,24 +18,19 @@
package org.apache.skywalking.oap.server.core.alarm.provider;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import lombok.ToString;
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.oap.server.core.Const;
-import java.util.Map;
+@RequiredArgsConstructor
+public abstract class AlarmHookSettings {
+ private final String name;
+ @Getter
+ private final AlarmHooksType type;
+ @Getter
+ private final boolean isDefault;
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-@Setter
-@Getter
-@ToString
-public class CompositeAlarmRule {
- private String alarmRuleName;
- private String expression;
- private String message;
- private Map<String, String> tags;
+ public String getFormattedName() {
+ return this.type.name() + Const.POINT + name;
+ }
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmHooksType.java
similarity index 74%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java
copy to oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmHooksType.java
index d4730876a0..0e9c0276a9 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmHooksType.java
@@ -16,13 +16,16 @@
*
*/
-package org.apache.skywalking.oap.server.core.alarm;
+package org.apache.skywalking.oap.server.core.alarm.provider;
-import java.util.List;
-
-/**
- * Alarm call back will be called by alarm implementor, after it decided alarm should be sent.
- */
-public interface AlarmCallback {
- void doAlarm(List<AlarmMessage> alarmMessage) throws Exception;
+public enum AlarmHooksType {
+ webhook,
+ gRPC,
+ wechat,
+ slack,
+ dingtalk,
+ feishu,
+ welink,
+ discord,
+ pagerduty
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRule.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRule.java
index 70a9c43ff5..0da0698ea3 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRule.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRule.java
@@ -20,9 +20,10 @@ package org.apache.skywalking.oap.server.core.alarm.provider;
import java.util.ArrayList;
import java.util.Map;
-import java.util.Objects;
+import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Builder;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -34,6 +35,7 @@ import lombok.ToString;
@Setter
@Getter
@ToString
+@EqualsAndHashCode
public class AlarmRule {
private String alarmRuleName;
private String metricsName;
@@ -53,28 +55,5 @@ public class AlarmRule {
private String message;
private boolean onlyAsCondition;
private Map<String, String> tags;
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) {
- return true;
- }
-
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- final AlarmRule alarmRule = (AlarmRule) o;
-
- return period == alarmRule.period && count == alarmRule.count && silencePeriod == alarmRule.silencePeriod && Objects
- .equals(alarmRuleName, alarmRule.alarmRuleName) && Objects.equals(metricsName, alarmRule.metricsName) && Objects
- .equals(includeNames, alarmRule.includeNames) && Objects.equals(excludeNames, alarmRule.excludeNames) && Objects
- .equals(threshold, alarmRule.threshold) && Objects.equals(op, alarmRule.op) && Objects.equals(message, alarmRule.message)
- && Objects.equals(includeNamesRegex, alarmRule.includeNamesRegex) && Objects.equals(excludeNamesRegex, alarmRule.excludeNamesRegex);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(alarmRuleName, metricsName, includeNames, excludeNames, threshold, op, period, count, silencePeriod, message);
- }
+ private Set<String> hooks;
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRulesWatcher.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRulesWatcher.java
index 19938ba33f..f27ea3f475 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRulesWatcher.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRulesWatcher.java
@@ -35,6 +35,7 @@ import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuSetting
import org.apache.skywalking.oap.server.core.alarm.provider.grpc.GRPCAlarmSetting;
import org.apache.skywalking.oap.server.core.alarm.provider.pagerduty.PagerDutySettings;
import org.apache.skywalking.oap.server.core.alarm.provider.slack.SlackSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.webhook.WebhookSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.wechat.WechatSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.welink.WeLinkSettings;
import org.apache.skywalking.oap.server.library.module.ModuleProvider;
@@ -117,39 +118,39 @@ public class AlarmRulesWatcher extends ConfigChangeWatcher {
return this.rules.getCompositeRules();
}
- public List<String> getWebHooks() {
- return this.rules.getWebhooks();
+ public Map<String, WebhookSettings> getWebHooks() {
+ return this.rules.getWebhookSettingsMap();
}
- public GRPCAlarmSetting getGrpchookSetting() {
- return this.rules.getGrpchookSetting();
+ public Map<String, GRPCAlarmSetting> getGrpchookSetting() {
+ return this.rules.getGrpcAlarmSettingMap();
}
- public SlackSettings getSlackSettings() {
- return this.rules.getSlacks();
+ public Map<String, SlackSettings> getSlackSettings() {
+ return this.rules.getSlackSettingsMap();
}
- public WechatSettings getWechatSettings() {
- return this.rules.getWecchats();
+ public Map<String, WechatSettings> getWechatSettings() {
+ return this.rules.getWechatSettingsMap();
}
- public DingtalkSettings getDingtalkSettings() {
- return this.rules.getDingtalks();
+ public Map<String, DingtalkSettings> getDingtalkSettings() {
+ return this.rules.getDingtalkSettingsMap();
}
- public FeishuSettings getFeishuSettings() {
- return this.rules.getFeishus();
+ public Map<String, FeishuSettings> getFeishuSettings() {
+ return this.rules.getFeishuSettingsMap();
}
- public WeLinkSettings getWeLinkSettings() {
- return this.rules.getWelinks();
+ public Map<String, WeLinkSettings> getWeLinkSettings() {
+ return this.rules.getWeLinkSettingsMap();
}
- public PagerDutySettings getPagerDutySettings() {
- return this.rules.getPagerDutySettings();
+ public Map<String, PagerDutySettings> getPagerDutySettings() {
+ return this.rules.getPagerDutySettingsMap();
}
- public DiscordSettings getDiscordSettings() {
- return this.rules.getDiscordSettings();
+ public Map<String, DiscordSettings> getDiscordSettings() {
+ return this.rules.getDiscordSettingsMap();
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeAlarmRule.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeAlarmRule.java
index 116a19253c..3a8c1050b5 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeAlarmRule.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeAlarmRule.java
@@ -18,6 +18,7 @@
package org.apache.skywalking.oap.server.core.alarm.provider;
+import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@@ -38,4 +39,5 @@ public class CompositeAlarmRule {
private String expression;
private String message;
private Map<String, String> tags;
+ private Set<String> hooks;
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeRuleEvaluator.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeRuleEvaluator.java
index 7fa761d7b8..f0d0440b8e 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeRuleEvaluator.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeRuleEvaluator.java
@@ -88,6 +88,7 @@ public class CompositeRuleEvaluator {
message.setAlarmMessage(alarmMessage);
message.setPeriod(headMsg.getPeriod());
message.setTags(compositeAlarmRule.getTags().entrySet().stream().map(e -> new Tag(e.getKey(), e.getValue())).collect(Collectors.toList()));
+ message.getHooks().addAll(compositeAlarmRule.getHooks());
compositeRuleMessages.add(message);
}
});
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/NotifyHandler.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/NotifyHandler.java
index ee14741476..79984b2fa3 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/NotifyHandler.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/NotifyHandler.java
@@ -37,6 +37,7 @@ import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuHookCal
import org.apache.skywalking.oap.server.core.alarm.provider.grpc.GRPCCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.pagerduty.PagerDutyHookCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.slack.SlackhookCallback;
+import org.apache.skywalking.oap.server.core.alarm.provider.webhook.WebhookCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.wechat.WechatHookCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.welink.WeLinkHookCallback;
import org.apache.skywalking.oap.server.core.analysis.IDManager;
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Rules.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Rules.java
index 537bab99c1..9179d9ea26 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Rules.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Rules.java
@@ -19,7 +19,9 @@
package org.apache.skywalking.oap.server.core.alarm.provider;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@@ -29,6 +31,7 @@ import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuSetting
import org.apache.skywalking.oap.server.core.alarm.provider.grpc.GRPCAlarmSetting;
import org.apache.skywalking.oap.server.core.alarm.provider.pagerduty.PagerDutySettings;
import org.apache.skywalking.oap.server.core.alarm.provider.slack.SlackSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.webhook.WebhookSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.wechat.WechatSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.welink.WeLinkSettings;
@@ -37,20 +40,28 @@ import org.apache.skywalking.oap.server.core.alarm.provider.welink.WeLinkSetting
@ToString
public class Rules {
private List<AlarmRule> rules;
- private List<String> webhooks;
- private GRPCAlarmSetting grpchookSetting;
- private SlackSettings slacks;
- private WechatSettings wecchats;
+ private Map<String, WebhookSettings> webhookSettingsMap;
+ private Map<String, GRPCAlarmSetting> grpcAlarmSettingMap;
+ private Map<String, SlackSettings> slackSettingsMap;
+ private Map<String, WechatSettings> wechatSettingsMap;
private List<CompositeAlarmRule> compositeRules;
- private DingtalkSettings dingtalks;
- private FeishuSettings feishus;
- private WeLinkSettings welinks;
- private PagerDutySettings pagerDutySettings;
- private DiscordSettings discordSettings;
+ private Map<String, DingtalkSettings> dingtalkSettingsMap;
+ private Map<String, FeishuSettings> feishuSettingsMap;
+ private Map<String, WeLinkSettings> weLinkSettingsMap;
+ private Map<String, PagerDutySettings> pagerDutySettingsMap;
+ private Map<String, DiscordSettings> discordSettingsMap;
public Rules() {
this.rules = new ArrayList<>();
- this.webhooks = new ArrayList<>();
+ this.webhookSettingsMap = new HashMap<>();
this.compositeRules = new ArrayList<>();
+ this.grpcAlarmSettingMap = new HashMap<>();
+ this.slackSettingsMap = new HashMap<>();
+ this.wechatSettingsMap = new HashMap<>();
+ this.dingtalkSettingsMap = new HashMap<>();
+ this.feishuSettingsMap = new HashMap<>();
+ this.weLinkSettingsMap = new HashMap<>();
+ this.pagerDutySettingsMap = new HashMap<>();
+ this.discordSettingsMap = new HashMap<>();
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReader.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReader.java
index 924c04894f..4c18623951 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReader.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReader.java
@@ -23,13 +23,15 @@ import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.stream.Collectors;
-
import org.apache.skywalking.oap.server.core.alarm.provider.discord.DiscordSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.pagerduty.PagerDutySettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.webhook.WebhookSettings;
import org.apache.skywalking.oap.server.library.util.StringUtil;
import org.apache.skywalking.oap.server.core.alarm.provider.dingtalk.DingtalkSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuSettings;
@@ -47,6 +49,8 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
*/
public class RulesReader {
private Map yamlData;
+ private final Set<String> defaultHooks = new HashSet<>();
+ private final Set<String> allHooks = new HashSet<>();
public RulesReader(InputStream inputStream) {
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
@@ -65,17 +69,10 @@ public class RulesReader {
Rules rules = new Rules();
if (Objects.nonNull(yamlData)) {
+ // Should read hooks config first.
+ readHooksConfig(rules);
readRulesConfig(rules);
- readWebHookConfig(rules);
- readGrpcConfig(rules);
- readSlackConfig(rules);
- readWechatConfig(rules);
readCompositeRuleConfig(rules);
- readDingtalkConfig(rules);
- readFeishuConfig(rules);
- readWeLinkConfig(rules);
- readPagerDutyConfig(rules);
- readDiscordConfig(rules);
}
return rules;
}
@@ -121,83 +118,156 @@ public class RulesReader {
(String) settings.getOrDefault("message", "Alarm caused by Rule " + alarmRule
.getAlarmRuleName()));
alarmRule.setTags((Map) settings.getOrDefault("tags", new HashMap<String, String>()));
+
+ Set<String> specificHooks = new HashSet<>((ArrayList) settings.getOrDefault("hooks", new ArrayList<>()));
+ checkSpecificHooks(alarmRule.getAlarmRuleName(), specificHooks);
+ alarmRule.setHooks(specificHooks);
+ // If no specific hooks, use global hooks.
+ if (alarmRule.getHooks().isEmpty()) {
+ alarmRule.getHooks().addAll(defaultHooks);
+ }
rules.getRules().add(alarmRule);
}
});
}
+ private void readHooksConfig(Rules rules) {
+ Map hooks = (Map) yamlData.getOrDefault("hooks", Collections.EMPTY_MAP);
+ if (CollectionUtils.isEmpty(hooks)) {
+ return;
+ }
+ readWebHookConfig(hooks, rules);
+ readGrpcConfig(hooks, rules);
+ readSlackConfig(hooks, rules);
+ readWechatConfig(hooks, rules);
+ readDingtalkConfig(hooks, rules);
+ readFeishuConfig(hooks, rules);
+ readWeLinkConfig(hooks, rules);
+ readPagerDutyConfig(hooks, rules);
+ readDiscordConfig(hooks, rules);
+ }
+
/**
* Read web hook config
*/
- private void readWebHookConfig(Rules rules) {
- List webhooks = (List) yamlData.get("webhooks");
- if (webhooks != null) {
- rules.setWebhooks(new ArrayList<>());
- webhooks.forEach(url -> {
- rules.getWebhooks().add((String) url);
- });
+ @SuppressWarnings("unchecked")
+ private void readWebHookConfig(Map hooks, Rules rules) {
+ Map configs = (Map) hooks.get(AlarmHooksType.webhook.name());
+ if (configs == null) {
+ return;
}
+ configs.forEach((k, v) -> {
+ Map<String, Object> config = (Map<String, Object>) v;
+ WebhookSettings settings = new WebhookSettings(
+ k.toString(), AlarmHooksType.webhook, (Boolean) config.getOrDefault("is-default", false));
+
+ List<String> urls = (List<String>) config.get("urls");
+ if (urls != null) {
+ settings.getUrls().addAll(urls);
+ }
+ rules.getWebhookSettingsMap().put(settings.getFormattedName(), settings);
+ if (settings.isDefault()) {
+ this.defaultHooks.add(settings.getFormattedName());
+ }
+ this.allHooks.add(settings.getFormattedName());
+ });
}
/**
* Read grpc hook config into {@link GRPCAlarmSetting}
*/
- private void readGrpcConfig(Rules rules) {
- Map grpchooks = (Map) yamlData.get("gRPCHook");
- if (grpchooks != null) {
- GRPCAlarmSetting grpcAlarmSetting = new GRPCAlarmSetting();
- Object targetHost = grpchooks.get("target_host");
+ @SuppressWarnings("unchecked")
+ private void readGrpcConfig(Map hooks, Rules rules) {
+ Map configs = (Map) hooks.get(AlarmHooksType.gRPC.name());
+ if (configs == null) {
+ return;
+ }
+ configs.forEach((k, v) -> {
+ Map config = (Map) v;
+ GRPCAlarmSetting setting = new GRPCAlarmSetting(
+ k.toString(), AlarmHooksType.gRPC, (Boolean) config.getOrDefault("is-default", false));
+
+ Object targetHost = config.get("target-host");
if (targetHost != null) {
- grpcAlarmSetting.setTargetHost((String) targetHost);
+ setting.setTargetHost((String) targetHost);
}
- Object targetPort = grpchooks.get("target_port");
+ Object targetPort = config.get("target-port");
if (targetPort != null) {
- grpcAlarmSetting.setTargetPort((Integer) targetPort);
+ setting.setTargetPort((Integer) targetPort);
}
- rules.setGrpchookSetting(grpcAlarmSetting);
- }
+ rules.getGrpcAlarmSettingMap().put(setting.getFormattedName(), setting);
+
+ if (setting.isDefault()) {
+ this.defaultHooks.add(setting.getFormattedName());
+ }
+ this.allHooks.add(setting.getFormattedName());
+ });
}
/**
* Read slack hook config into {@link SlackSettings}
*/
- private void readSlackConfig(Rules rules) {
- Map slacks = (Map) yamlData.get("slackHooks");
- if (slacks != null) {
- SlackSettings slackSettings = new SlackSettings();
- Object textTemplate = slacks.getOrDefault("textTemplate", "");
- slackSettings.setTextTemplate((String) textTemplate);
-
- List<String> slackWebhooks = (List<String>) slacks.get("webhooks");
- if (slackWebhooks != null) {
- slackSettings.getWebhooks().addAll(slackWebhooks);
- }
- rules.setSlacks(slackSettings);
+ @SuppressWarnings("unchecked")
+ private void readSlackConfig(Map hooks, Rules rules) {
+ Map configs = (Map) hooks.get(AlarmHooksType.slack.name());
+ if (configs == null) {
+ return;
}
+ configs.forEach((k, v) -> {
+ Map<String, Object> config = (Map<String, Object>) v;
+ SlackSettings settings = new SlackSettings(
+ k.toString(), AlarmHooksType.slack, (Boolean) config.getOrDefault("is-default", false));
+
+ Object textTemplate = config.getOrDefault("text-template", "");
+ settings.setTextTemplate((String) textTemplate);
+
+ List<String> webhooks = (List<String>) config.get("webhooks");
+ if (webhooks != null) {
+ settings.getWebhooks().addAll(webhooks);
+ }
+ rules.getSlackSettingsMap().put(settings.getFormattedName(), settings);
+ if (settings.isDefault()) {
+ this.defaultHooks.add(settings.getFormattedName());
+ }
+ this.allHooks.add(settings.getFormattedName());
+ });
}
/**
* Read wechat hook config into {@link WechatSettings}
*/
- private void readWechatConfig(Rules rules) {
- Map wechatConfig = (Map) yamlData.get("wechatHooks");
- if (wechatConfig != null) {
- WechatSettings wechatSettings = new WechatSettings();
- Object textTemplate = wechatConfig.getOrDefault("textTemplate", "");
- wechatSettings.setTextTemplate((String) textTemplate);
- List<String> wechatWebhooks = (List<String>) wechatConfig.get("webhooks");
- if (wechatWebhooks != null) {
- wechatSettings.getWebhooks().addAll(wechatWebhooks);
- }
- rules.setWecchats(wechatSettings);
+ @SuppressWarnings("unchecked")
+ private void readWechatConfig(Map hooks, Rules rules) {
+ Map configs = (Map) hooks.get(AlarmHooksType.wechat.name());
+ if (configs == null) {
+ return;
}
+ configs.forEach((k, v) -> {
+ Map<String, Object> config = (Map<String, Object>) v;
+ WechatSettings settings = new WechatSettings(
+ k.toString(), AlarmHooksType.wechat, (Boolean) config.getOrDefault("is-default", false));
+
+ Object textTemplate = config.getOrDefault("text-template", "");
+ settings.setTextTemplate((String) textTemplate);
+
+ List<String> webhooks = (List<String>) config.get("webhooks");
+ if (webhooks != null) {
+ settings.getWebhooks().addAll(webhooks);
+ }
+ rules.getWechatSettingsMap().put(settings.getFormattedName(), settings);
+ if (settings.isDefault()) {
+ this.defaultHooks.add(settings.getFormattedName());
+ }
+ this.allHooks.add(settings.getFormattedName());
+ });
}
/**
* Read composite rule config into {@link CompositeAlarmRule}
*/
+ @SuppressWarnings("unchecked")
private void readCompositeRuleConfig(Rules rules) {
Map compositeRulesData = (Map) yamlData.get("composite-rules");
if (compositeRulesData == null) {
@@ -217,6 +287,14 @@ public class RulesReader {
compositeAlarmRule.setMessage(
(String) settings.getOrDefault("message", "Alarm caused by Rule " + ruleName));
compositeAlarmRule.setTags((Map) settings.getOrDefault("tags", new HashMap<String, String>(0)));
+
+ Set<String> specificHooks = new HashSet<>((ArrayList) settings.getOrDefault("hooks", new ArrayList<>()));
+ checkSpecificHooks(compositeAlarmRule.getAlarmRuleName(), specificHooks);
+ compositeAlarmRule.setHooks(specificHooks);
+ // If no specific hooks, use global hooks.
+ if (compositeAlarmRule.getHooks().isEmpty()) {
+ compositeAlarmRule.getHooks().addAll(defaultHooks);
+ }
rules.getCompositeRules().add(compositeAlarmRule);
}
});
@@ -225,109 +303,168 @@ public class RulesReader {
/**
* Read dingtalk hook config into {@link DingtalkSettings}
*/
- private void readDingtalkConfig(Rules rules) {
- Map dingtalkConfig = (Map) yamlData.get("dingtalkHooks");
- if (dingtalkConfig != null) {
- DingtalkSettings dingtalkSettings = new DingtalkSettings();
- Object textTemplate = dingtalkConfig.getOrDefault("textTemplate", "");
- dingtalkSettings.setTextTemplate((String) textTemplate);
- List<Map<String, Object>> wechatWebhooks = (List<Map<String, Object>>) dingtalkConfig.get("webhooks");
- if (wechatWebhooks != null) {
- wechatWebhooks.forEach(wechatWebhook -> {
- Object secret = wechatWebhook.getOrDefault("secret", "");
- Object url = wechatWebhook.getOrDefault("url", "");
- dingtalkSettings.getWebhooks().add(new DingtalkSettings.WebHookUrl((String) secret, (String) url));
+ @SuppressWarnings("unchecked")
+ private void readDingtalkConfig(Map hooks, Rules rules) {
+ Map configs = (Map) hooks.get(AlarmHooksType.dingtalk.name());
+ if (configs == null) {
+ return;
+ }
+ configs.forEach((k, v) -> {
+ Map<String, Object> config = (Map<String, Object>) v;
+ DingtalkSettings settings = new DingtalkSettings(
+ k.toString(), AlarmHooksType.dingtalk, (Boolean) config.getOrDefault("is-default", false));
+
+ Object textTemplate = config.getOrDefault("text-template", "");
+ settings.setTextTemplate((String) textTemplate);
+
+ List<Map<String, Object>> webhooks = (List<Map<String, Object>>) config.get("webhooks");
+ if (webhooks != null) {
+ webhooks.forEach(webhook -> {
+ Object secret = webhook.getOrDefault("secret", "");
+ Object url = webhook.getOrDefault("url", "");
+ settings.getWebhooks().add(new DingtalkSettings.WebHookUrl((String) secret, (String) url));
});
}
- rules.setDingtalks(dingtalkSettings);
- }
+ rules.getDingtalkSettingsMap().put(settings.getFormattedName(), settings);
+ if (settings.isDefault()) {
+ this.defaultHooks.add(settings.getFormattedName());
+ }
+ this.allHooks.add(settings.getFormattedName());
+ });
}
/**
* 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));
+ @SuppressWarnings("unchecked")
+ private void readFeishuConfig(Map hooks, Rules rules) {
+ Map configs = (Map) hooks.get(AlarmHooksType.feishu.name());
+ if (configs == null) {
+ return;
+ }
+ configs.forEach((k, v) -> {
+ Map<String, Object> config = (Map<String, Object>) v;
+ FeishuSettings settings = new FeishuSettings(
+ k.toString(), AlarmHooksType.feishu, (Boolean) config.getOrDefault("is-default", false));
+
+ Object textTemplate = config.getOrDefault("text-template", "");
+ settings.setTextTemplate((String) textTemplate);
+
+ List<Map<String, Object>> webhooks = (List<Map<String, Object>>) config.get("webhooks");
+ if (webhooks != null) {
+ webhooks.forEach(webhook -> {
+ Object secret = webhook.getOrDefault("secret", "");
+ Object url = webhook.getOrDefault("url", "");
+ settings.getWebhooks().add(new FeishuSettings.WebHookUrl((String) secret, (String) url));
});
}
- rules.setFeishus(feishuSettings);
- }
+ rules.getFeishuSettingsMap().put(settings.getFormattedName(), settings);
+ if (settings.isDefault()) {
+ this.defaultHooks.add(settings.getFormattedName());
+ }
+ this.allHooks.add(settings.getFormattedName());
+ });
}
/**
* Read WeLink hook config into {@link WeLinkSettings}
*/
@SuppressWarnings("unchecked")
- private void readWeLinkConfig(Rules rules) {
- Map<String, Object> welinkConfig = (Map<String, Object>) yamlData.getOrDefault(
- "welinkHooks",
- Collections.EMPTY_MAP
- );
- String textTemplate = (String) welinkConfig.get("textTemplate");
- List<Map<String, String>> welinkWebHooks = (List<Map<String, String>>) welinkConfig.get("webhooks");
- if (StringUtil.isBlank(textTemplate) || CollectionUtils.isEmpty(welinkWebHooks)) {
+ private void readWeLinkConfig(Map hooks, Rules rules) {
+ Map configs = (Map) hooks.get(AlarmHooksType.welink.name());
+ if (configs == null) {
return;
}
- List<WeLinkSettings.WebHookUrl> webHookUrls = welinkWebHooks.stream().map(
- WeLinkSettings.WebHookUrl::generateFromMap
- ).collect(Collectors.toList());
-
- WeLinkSettings welinkSettings = new WeLinkSettings();
- welinkSettings.setTextTemplate(textTemplate);
- welinkSettings.setWebhooks(webHookUrls);
- rules.setWelinks(welinkSettings);
+ configs.forEach((k, v) -> {
+ Map<String, Object> config = (Map<String, Object>) v;
+ String textTemplate = (String) config.get("text-template");
+ List<Map<String, String>> webhooks = (List<Map<String, String>>) config.get("webhooks");
+ if (StringUtil.isBlank(textTemplate) || CollectionUtils.isEmpty(webhooks)) {
+ return;
+ }
+ List<WeLinkSettings.WebHookUrl> webHookUrls = webhooks.stream().map(
+ WeLinkSettings.WebHookUrl::generateFromMap
+ ).collect(Collectors.toList());
+
+ WeLinkSettings settings = new WeLinkSettings(
+ k.toString(), AlarmHooksType.welink, (Boolean) config.getOrDefault("is-default", false));
+ settings.setTextTemplate(textTemplate);
+ settings.setWebhooks(webHookUrls);
+
+ rules.getWeLinkSettingsMap().put(settings.getFormattedName(), settings);
+ if (settings.isDefault()) {
+ this.defaultHooks.add(settings.getFormattedName());
+ }
+ this.allHooks.add(settings.getFormattedName());
+ });
}
/**
* Read PagerDuty hook config into {@link PagerDutySettings}
*/
- private void readPagerDutyConfig(Rules rules) {
- Map<String, Object> pagerDutyConfig = (Map<String, Object>) yamlData.get("pagerDutyHooks");
- if (pagerDutyConfig != null) {
- PagerDutySettings pagerDutySettings = new PagerDutySettings();
- String textTemplate = (String) pagerDutyConfig.getOrDefault("textTemplate", "");
- pagerDutySettings.setTextTemplate(textTemplate);
-
- List<String> integrationKeys = (List<String>) pagerDutyConfig.get("integrationKeys");
+ @SuppressWarnings("unchecked")
+ private void readPagerDutyConfig(Map hooks, Rules rules) {
+ Map configs = (Map) hooks.get(AlarmHooksType.pagerduty.name());
+ if (configs == null) {
+ return;
+ }
+ configs.forEach((k, v) -> {
+ Map<String, Object> config = (Map<String, Object>) v;
+ PagerDutySettings settings = new PagerDutySettings(
+ k.toString(), AlarmHooksType.pagerduty, (Boolean) config.getOrDefault("is-default", false));
+ Object textTemplate = config.getOrDefault("text-template", "");
+ settings.setTextTemplate((String) textTemplate);
+
+ List<String> integrationKeys = (List<String>) config.get("integration-keys");
if (integrationKeys != null) {
- pagerDutySettings.getIntegrationKeys().addAll(integrationKeys);
+ settings.getIntegrationKeys().addAll(integrationKeys);
}
- rules.setPagerDutySettings(pagerDutySettings);
- }
+ rules.getPagerDutySettingsMap().put(settings.getFormattedName(), settings);
+ if (settings.isDefault()) {
+ this.defaultHooks.add(settings.getFormattedName());
+ }
+ this.allHooks.add(settings.getFormattedName());
+ });
}
/**
* Read Discord hook config into {@link DiscordSettings}
*/
@SuppressWarnings("unchecked")
- private void readDiscordConfig(Rules rules) {
- Map<String, Object> discordConfig = (Map<String, Object>) yamlData.getOrDefault(
- "discordHooks",
- Collections.EMPTY_MAP
- );
- String textTemplate = (String) discordConfig.get("textTemplate");
- List<Map<String, String>> discordWebHooks = (List<Map<String, String>>) discordConfig.get("webhooks");
- if (StringUtil.isBlank(textTemplate) || CollectionUtils.isEmpty(discordWebHooks)) {
+ private void readDiscordConfig(Map hooks, Rules rules) {
+ Map configs = (Map) hooks.get(AlarmHooksType.discord.name());
+ if (configs == null) {
return;
}
- List<DiscordSettings.WebHookUrl> webHookUrls = discordWebHooks.stream().map(
+ configs.forEach((k, v) -> {
+ Map<String, Object> config = (Map<String, Object>) v;
+ String textTemplate = (String) config.get("text-template");
+ List<Map<String, String>> webhooks = (List<Map<String, String>>) config.get("webhooks");
+ if (StringUtil.isBlank(textTemplate) || CollectionUtils.isEmpty(webhooks)) {
+ return;
+ }
+ List<DiscordSettings.WebHookUrl> webHookUrls = webhooks.stream().map(
DiscordSettings.WebHookUrl::generateFromMap
- ).collect(Collectors.toList());
+ ).collect(Collectors.toList());
- DiscordSettings discordSettings = new DiscordSettings();
- discordSettings.setTextTemplate(textTemplate);
- discordSettings.setWebhooks(webHookUrls);
- rules.setDiscordSettings(discordSettings);
+ DiscordSettings settings = new DiscordSettings(
+ k.toString(), AlarmHooksType.discord, (Boolean) config.getOrDefault("is-default", false));
+ settings.setTextTemplate(textTemplate);
+ settings.setWebhooks(webHookUrls);
+
+ rules.getDiscordSettingsMap().put(settings.getFormattedName(), settings);
+ if (settings.isDefault()) {
+ this.defaultHooks.add(settings.getFormattedName());
+ }
+ this.allHooks.add(settings.getFormattedName());
+ });
+ }
+
+ private void checkSpecificHooks(String ruleName, Set<String> hooks) {
+ if (!this.allHooks.containsAll(hooks)) {
+ throw new IllegalArgumentException("rule: [" + ruleName + "] contains invalid hooks." +
+ " Please check the hook is exist and name format is {hookType}.{hookName}");
+ }
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
index 2c4261e31e..a9bbdaabe1 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
@@ -25,6 +25,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
@@ -76,6 +77,7 @@ public class RunningRule {
private final AlarmMessageFormatter formatter;
private final boolean onlyAsCondition;
private final List<Tag> tags;
+ private final Set<String> hooks;
public RunningRule(AlarmRule alarmRule) {
metricsName = alarmRule.getMetricsName();
@@ -111,6 +113,7 @@ public class RunningRule {
.stream()
.map(e -> new Tag(e.getKey(), e.getValue()))
.collect(Collectors.toList());
+ this.hooks = alarmRule.getHooks();
}
/**
@@ -248,6 +251,7 @@ public class RunningRule {
alarmMessage.setStartTime(System.currentTimeMillis());
alarmMessage.setPeriod(this.period);
alarmMessage.setTags(this.tags);
+ alarmMessage.setHooks(this.hooks);
alarmMessageList.add(alarmMessage);
}
});
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkHookCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkHookCallback.java
index 46a2ae7370..ab2c7efb32 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkHookCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkHookCallback.java
@@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
import org.apache.skywalking.oap.server.core.alarm.HttpAlarmCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.AlarmRulesWatcher;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
import org.apache.skywalking.oap.server.library.util.StringUtil;
import javax.crypto.Mac;
@@ -50,17 +51,27 @@ public class DingtalkHookCallback extends HttpAlarmCallback {
*/
@Override
public void doAlarm(List<AlarmMessage> alarmMessages) throws Exception {
- if (alarmRulesWatcher.getDingtalkSettings() == null || alarmRulesWatcher.getDingtalkSettings().getWebhooks().isEmpty()) {
+ Map<String, DingtalkSettings> settingsMap = alarmRulesWatcher.getDingtalkSettings();
+ if (settingsMap == null || settingsMap.isEmpty()) {
return;
}
- final var dingtalkSettings = alarmRulesWatcher.getDingtalkSettings();
- for (final var webHookUrl : dingtalkSettings.getWebhooks()) {
- final var url = getUrl(webHookUrl);
- for (final var alarmMessage : alarmMessages) {
- final var requestBody = String.format(
- alarmRulesWatcher.getDingtalkSettings().getTextTemplate(), alarmMessage.getAlarmMessage()
- );
- post(URI.create(url), requestBody, Map.of());
+ Map<String, List<AlarmMessage>> groupedMessages = groupMessagesByHook(alarmMessages);
+ for (Map.Entry<String, List<AlarmMessage>> entry : groupedMessages.entrySet()) {
+ var hookName = entry.getKey();
+ var messages = entry.getValue();
+ var setting = settingsMap.get(hookName);
+ if (setting == null || CollectionUtils.isEmpty(setting.getWebhooks()) || CollectionUtils.isEmpty(
+ messages)) {
+ continue;
+ }
+ for (final var webHookUrl : setting.getWebhooks()) {
+ final var url = getUrl(webHookUrl);
+ for (final var alarmMessage : messages) {
+ final var requestBody = String.format(
+ setting.getTextTemplate(), alarmMessage.getAlarmMessage()
+ );
+ post(URI.create(url), requestBody, Map.of());
+ }
}
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkSettings.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkSettings.java
index ba1d7501fe..475c44329c 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkSettings.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkSettings.java
@@ -19,27 +19,29 @@
package org.apache.skywalking.oap.server.core.alarm.provider.dingtalk;
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;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHookSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
@Setter
@Getter
@ToString
-public class DingtalkSettings {
+public class DingtalkSettings extends AlarmHookSettings {
private String textTemplate;
- @Builder.Default
private List<WebHookUrl> webhooks = new ArrayList<>();
+ public DingtalkSettings(final String name,
+ final AlarmHooksType type,
+ final boolean isDefault) {
+ super(name, type, isDefault);
+ }
+
@AllArgsConstructor
@Setter
@Getter
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/discord/DiscordHookCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/discord/DiscordHookCallback.java
index a0527690d0..44d53dcc6a 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/discord/DiscordHookCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/discord/DiscordHookCallback.java
@@ -29,6 +29,7 @@ import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Map;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
/**
* Use SkyWalking alarm Discord webhook API.
@@ -43,17 +44,28 @@ public class DiscordHookCallback extends HttpAlarmCallback {
*/
@Override
public void doAlarm(List<AlarmMessage> alarmMessages) throws Exception {
- final var discordSettings = alarmRulesWatcher.getDiscordSettings();
- if (discordSettings == null || discordSettings.getWebhooks().isEmpty()) {
+ Map<String, DiscordSettings> settingsMap = alarmRulesWatcher.getDiscordSettings();
+ if (settingsMap == null || settingsMap.isEmpty()) {
return;
}
- for (final var webHookUrl : discordSettings.getWebhooks()) {
- for (final var alarmMessage : alarmMessages) {
- final var content = String.format(
- discordSettings.getTextTemplate(),
+
+ Map<String, List<AlarmMessage>> groupedMessages = groupMessagesByHook(alarmMessages);
+ for (Map.Entry<String, List<AlarmMessage>> entry : groupedMessages.entrySet()) {
+ var hookName = entry.getKey();
+ var messages = entry.getValue();
+ var setting = settingsMap.get(hookName);
+ if (setting == null || CollectionUtils.isEmpty(setting.getWebhooks()) || CollectionUtils.isEmpty(
+ messages)) {
+ continue;
+ }
+ for (final var webHookUrl : setting.getWebhooks()) {
+ for (final var alarmMessage : messages) {
+ final var content = String.format(
+ setting.getTextTemplate(),
alarmMessage.getAlarmMessage()
- );
- sendAlarmMessage(webHookUrl, content);
+ );
+ sendAlarmMessage(webHookUrl, content);
+ }
}
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/discord/DiscordSettings.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/discord/DiscordSettings.java
index 1c5b9e2b26..ddaea51704 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/discord/DiscordSettings.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/discord/DiscordSettings.java
@@ -19,28 +19,30 @@
package org.apache.skywalking.oap.server.core.alarm.provider.discord;
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;
import java.util.Map;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHookSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
@Setter
@Getter
@ToString
-public class DiscordSettings {
+public class DiscordSettings extends AlarmHookSettings {
private String textTemplate;
- @Builder.Default
private List<WebHookUrl> webhooks = new ArrayList<>();
+ public DiscordSettings(final String name,
+ final AlarmHooksType type,
+ final boolean isDefault) {
+ super(name, type, isDefault);
+ }
+
@AllArgsConstructor
@Setter
@Getter
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuHookCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuHookCallback.java
index deb47cbf51..97eb6baa4d 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuHookCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuHookCallback.java
@@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
import org.apache.skywalking.oap.server.core.alarm.HttpAlarmCallback;
import org.apache.skywalking.oap.server.core.alarm.provider.AlarmRulesWatcher;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
import org.apache.skywalking.oap.server.library.util.StringUtil;
import javax.crypto.Mac;
@@ -52,14 +53,24 @@ public class FeishuHookCallback extends HttpAlarmCallback {
*/
@Override
public void doAlarm(List<AlarmMessage> alarmMessages) throws Exception {
- if (alarmRulesWatcher.getFeishuSettings() == null || alarmRulesWatcher.getFeishuSettings().getWebhooks().isEmpty()) {
+ Map<String, FeishuSettings> settingsMap = alarmRulesWatcher.getFeishuSettings();
+ if (settingsMap == null || settingsMap.isEmpty()) {
return;
}
- final var feishuSettings = alarmRulesWatcher.getFeishuSettings();
- for (final var webHookUrl : feishuSettings.getWebhooks()) {
- for (final var alarmMessage : alarmMessages) {
- final var requestBody = getRequestBody(webHookUrl, alarmMessage);
- post(URI.create(webHookUrl.getUrl()), requestBody, Map.of());
+ Map<String, List<AlarmMessage>> groupedMessages = groupMessagesByHook(alarmMessages);
+ for (Map.Entry<String, List<AlarmMessage>> entry : groupedMessages.entrySet()) {
+ var hookName = entry.getKey();
+ var messages = entry.getValue();
+ var setting = settingsMap.get(hookName);
+ if (setting == null || CollectionUtils.isEmpty(setting.getWebhooks()) || CollectionUtils.isEmpty(
+ messages)) {
+ continue;
+ }
+ for (final var webHookUrl : setting.getWebhooks()) {
+ for (final var alarmMessage : messages) {
+ final var requestBody = getRequestBody(webHookUrl, alarmMessage, setting.getTextTemplate());
+ post(URI.create(webHookUrl.getUrl()), requestBody, Map.of());
+ }
}
}
}
@@ -67,9 +78,8 @@ public class FeishuHookCallback extends HttpAlarmCallback {
/**
* deal requestBody,if it has sign set the sign
*/
- private String getRequestBody(FeishuSettings.WebHookUrl webHookUrl, AlarmMessage alarmMessage) {
- final var requestBody = String.format(
- alarmRulesWatcher.getFeishuSettings().getTextTemplate(), alarmMessage.getAlarmMessage()
+ private String getRequestBody(FeishuSettings.WebHookUrl webHookUrl, AlarmMessage alarmMessage, String textTemplate) {
+ final var requestBody = String.format(textTemplate, alarmMessage.getAlarmMessage()
);
final var gson = new Gson();
final var jsonObject = gson.fromJson(requestBody, JsonObject.class);
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuSettings.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuSettings.java
index fa66b9560e..b4a3cef558 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuSettings.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuSettings.java
@@ -21,24 +21,28 @@ 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;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHookSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
@Setter
@Getter
@ToString
-public class FeishuSettings {
+public class FeishuSettings extends AlarmHookSettings {
private String textTemplate;
@Builder.Default
private List<WebHookUrl> webhooks = new ArrayList<>();
+ public FeishuSettings(final String name,
+ final AlarmHooksType type,
+ final boolean isDefault) {
+ super(name, type, isDefault);
+ }
+
@AllArgsConstructor
@Setter
@Getter
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPCAlarmSetting.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPCAlarmSetting.java
index 46975b6c0e..631d03269e 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPCAlarmSetting.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPCAlarmSetting.java
@@ -22,14 +22,22 @@ import java.util.Objects;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHookSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
@Setter
@Getter
-@EqualsAndHashCode
-public class GRPCAlarmSetting {
+@EqualsAndHashCode(callSuper = true)
+public class GRPCAlarmSetting extends AlarmHookSettings {
private String targetHost;
private int targetPort;
+ public GRPCAlarmSetting(final String name,
+ final AlarmHooksType type,
+ final boolean isDefault) {
+ super(name, type, isDefault);
+ }
+
public boolean isEmptySetting() {
return Objects.isNull(targetHost);
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPCCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPCCallback.java
index 1eb3246441..2ae872f2f1 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPCCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPCCallback.java
@@ -19,7 +19,9 @@
package org.apache.skywalking.oap.server.core.alarm.provider.grpc;
import io.grpc.stub.StreamObserver;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.core.alarm.AlarmCallback;
@@ -30,6 +32,7 @@ import org.apache.skywalking.oap.server.core.alarm.grpc.KeyStringValuePair;
import org.apache.skywalking.oap.server.core.alarm.grpc.Response;
import org.apache.skywalking.oap.server.core.alarm.provider.AlarmRulesWatcher;
import org.apache.skywalking.oap.server.library.client.grpc.GRPCClient;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
import org.apache.skywalking.oap.server.library.util.GRPCStreamStatus;
/**
@@ -40,33 +43,52 @@ public class GRPCCallback implements AlarmCallback {
private AlarmRulesWatcher alarmRulesWatcher;
- private GRPCAlarmSetting alarmSetting;
+ private Map<String, GRPCAlarmSetting> alarmSettingMap;
- private AlarmServiceGrpc.AlarmServiceStub alarmServiceStub;
+ private Map<String, AlarmServiceGrpc.AlarmServiceStub> alarmServiceStubMap;
- private GRPCClient grpcClient;
+ private Map<String, GRPCClient> grpcClientMap;
public GRPCCallback(AlarmRulesWatcher alarmRulesWatcher) {
this.alarmRulesWatcher = alarmRulesWatcher;
- alarmSetting = alarmRulesWatcher.getGrpchookSetting();
-
- if (alarmSetting != null && !alarmSetting.isEmptySetting()) {
- grpcClient = new GRPCClient(alarmSetting.getTargetHost(), alarmSetting.getTargetPort());
- grpcClient.connect();
- alarmServiceStub = AlarmServiceGrpc.newStub(grpcClient.getChannel());
+ this.alarmSettingMap = new HashMap<>();
+ this.alarmServiceStubMap = new HashMap<>();
+ this.grpcClientMap = new HashMap<>();
+ Map<String, GRPCAlarmSetting> alarmSettingMap = alarmRulesWatcher.getGrpchookSetting();
+ if (CollectionUtils.isNotEmpty(alarmSettingMap)) {
+ alarmSettingMap.forEach((name, alarmSetting) -> {
+ if (alarmSetting != null && !alarmSetting.isEmptySetting()) {
+ GRPCClient grpcClient = new GRPCClient(alarmSetting.getTargetHost(), alarmSetting.getTargetPort());
+ grpcClient.connect();
+ grpcClientMap.put(name, grpcClient);
+ alarmServiceStubMap.put(name, AlarmServiceGrpc.newStub(grpcClient.getChannel()));
+ }
+ });
}
}
@Override
- public void doAlarm(List<AlarmMessage> alarmMessage) {
-
+ public void doAlarm(List<AlarmMessage> alarmMessages) {
// recreate gRPC client and stub if host and port configuration changed.
- onGRPCAlarmSettingUpdated(alarmRulesWatcher.getGrpchookSetting());
+ Map<String, GRPCAlarmSetting> settinsMap = alarmRulesWatcher.getGrpchookSetting();
+ onGRPCAlarmSettingUpdated(settinsMap);
- if (alarmSetting == null || alarmSetting.isEmptySetting() || alarmServiceStub == null) {
+ if (settinsMap == null || settinsMap.isEmpty()) {
return;
}
+ Map<String, List<AlarmMessage>> groupedMessages = groupMessagesByHook(alarmMessages);
+ groupedMessages.forEach((hook, messages) -> {
+ if (alarmServiceStubMap.containsKey(hook)) {
+ sendAlarmMessages(alarmServiceStubMap.get(hook), messages, settinsMap.get(hook));
+ }
+ });
+
+ }
+
+ private void sendAlarmMessages(AlarmServiceGrpc.AlarmServiceStub alarmServiceStub,
+ List<AlarmMessage> alarmMessages,
+ GRPCAlarmSetting alarmSetting) {
GRPCStreamStatus status = new GRPCStreamStatus();
StreamObserver<org.apache.skywalking.oap.server.core.alarm.grpc.AlarmMessage> streamObserver =
@@ -93,7 +115,7 @@ public class GRPCCallback implements AlarmCallback {
}
});
- alarmMessage.forEach(message -> {
+ alarmMessages.forEach(message -> {
org.apache.skywalking.oap.server.core.alarm.grpc.AlarmMessage.Builder builder =
org.apache.skywalking.oap.server.core.alarm.grpc.AlarmMessage.newBuilder();
@@ -125,41 +147,51 @@ public class GRPCCallback implements AlarmCallback {
}
if (log.isDebugEnabled()) {
- log.debug("Send {} alarm message to {}:{}.", alarmMessage.size(),
+ log.debug("Send {} alarm message to {}:{}.", alarmMessages.size(),
alarmSetting.getTargetHost(), alarmSetting.getTargetPort()
);
}
if (sleepTime > 2000L) {
- log.warn("Send {} alarm message to {}:{}, wait {} milliseconds.", alarmMessage.size(),
+ log.warn("Send {} alarm message to {}:{}, wait {} milliseconds.", alarmMessages.size(),
alarmSetting.getTargetHost(), alarmSetting.getTargetPort(), sleepTime
);
cycle = 2000L;
}
}
- }
+}
- private void onGRPCAlarmSettingUpdated(GRPCAlarmSetting grpcAlarmSetting) {
- if (grpcAlarmSetting == null) {
- if (grpcClient != null) {
- grpcClient.shutdown();
- log.debug("gRPC alarm hook target is empty, shutdown the old gRPC client.");
+ private void onGRPCAlarmSettingUpdated(Map<String, GRPCAlarmSetting> newAlarmSettingMap) {
+ if (newAlarmSettingMap == null || newAlarmSettingMap.isEmpty()) {
+ if (grpcClientMap != null) {
+ grpcClientMap.forEach((name, grpcClient) -> {
+ grpcClient.shutdown();
+ log.debug("gRPC alarm hook target is empty, shutdown the old gRPC client.");
+ });
}
- alarmServiceStub = null;
- alarmSetting = null;
+ alarmServiceStubMap = null;
+ alarmSettingMap = null;
return;
}
- if (!grpcAlarmSetting.equals(alarmSetting)) {
- alarmSetting = grpcAlarmSetting;
- if (grpcClient != null) {
- grpcClient.shutdown();
- log.debug("gRPC alarm hook target is changed, shutdown the old gRPC client.");
+ newAlarmSettingMap.forEach((name, newAlarmSetting) -> {
+ if (!newAlarmSetting.equals(alarmSettingMap.get(name))) {
+ GRPCClient grpcClient = grpcClientMap.get(name);
+ if (grpcClient != null) {
+ grpcClient.shutdown();
+ grpcClientMap.remove(name);
+ alarmServiceStubMap.remove(name);
+ log.debug("gRPC alarm hook target is changed, shutdown the old gRPC client.");
+ }
+ if (newAlarmSetting.isEmptySetting()) {
+ return;
+ }
+ grpcClient = new GRPCClient(newAlarmSetting.getTargetHost(), newAlarmSetting.getTargetPort());
+ grpcClient.connect();
+ grpcClientMap.put(name, grpcClient);
+ alarmServiceStubMap.put(name, AlarmServiceGrpc.newStub(grpcClient.getChannel()));
}
- grpcClient = new GRPCClient(grpcAlarmSetting.getTargetHost(), grpcAlarmSetting.getTargetPort());
- grpcClient.connect();
- alarmServiceStub = AlarmServiceGrpc.newStub(grpcClient.getChannel());
- }
+ });
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutyHookCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutyHookCallback.java
index 40610e56bf..35ba9b11d2 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutyHookCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutyHookCallback.java
@@ -31,32 +31,47 @@ import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
@Slf4j
@RequiredArgsConstructor
public class PagerDutyHookCallback extends HttpAlarmCallback {
- private static final String PAGER_DUTY_EVENTS_API_V2_URL = "https://events.pagerduty.com/v2/enqueue";
+ private static final String PAGER_DUTY_EVENTS_API_V2_URL = "http://events.pagerduty.com/v2/enqueue";
private static final Gson GSON = new Gson();
private final AlarmRulesWatcher alarmRulesWatcher;
@Override
public void doAlarm(List<AlarmMessage> alarmMessages) throws Exception {
- if (alarmRulesWatcher.getPagerDutySettings() == null || alarmRulesWatcher.getPagerDutySettings().getIntegrationKeys().isEmpty()) {
+ Map<String, PagerDutySettings> settingsMap = alarmRulesWatcher.getPagerDutySettings();
+ if (settingsMap == null || settingsMap.isEmpty()) {
return;
}
- for (final var integrationKey : alarmRulesWatcher.getPagerDutySettings().getIntegrationKeys()) {
- for (final var alarmMessage : alarmMessages) {
- post(URI.create(PAGER_DUTY_EVENTS_API_V2_URL), getMessageBody(alarmMessage, integrationKey), Map.of());
+ Map<String, List<AlarmMessage>> groupedMessages = groupMessagesByHook(alarmMessages);
+ for (Map.Entry<String, List<AlarmMessage>> entry : groupedMessages.entrySet()) {
+ var hookName = entry.getKey();
+ var messages = entry.getValue();
+ var setting = settingsMap.get(hookName);
+ if (setting == null || CollectionUtils.isEmpty(setting.getIntegrationKeys()) || CollectionUtils.isEmpty(
+ messages)) {
+ continue;
+ }
+ for (final var integrationKey : setting.getIntegrationKeys()) {
+ for (final var alarmMessage : messages) {
+ post(
+ URI.create(PAGER_DUTY_EVENTS_API_V2_URL),
+ getMessageBody(alarmMessage, integrationKey, setting.getTextTemplate()), Map.of()
+ );
+ }
}
}
}
- private String getMessageBody(AlarmMessage alarmMessage, String integrationKey) {
+ private String getMessageBody(AlarmMessage alarmMessage, String integrationKey, String textTemplate) {
final var body = new JsonObject();
final var payload = new JsonObject();
- payload.add("summary", new JsonPrimitive(getFormattedMessage(alarmMessage)));
+ payload.add("summary", new JsonPrimitive(getFormattedMessage(alarmMessage, textTemplate)));
payload.add("severity", new JsonPrimitive("warning"));
payload.add("source", new JsonPrimitive("Skywalking"));
body.add("payload", payload);
@@ -67,9 +82,8 @@ public class PagerDutyHookCallback extends HttpAlarmCallback {
return GSON.toJson(body);
}
- private String getFormattedMessage(AlarmMessage alarmMessage) {
- return String.format(
- alarmRulesWatcher.getPagerDutySettings().getTextTemplate(), alarmMessage.getAlarmMessage()
+ private String getFormattedMessage(AlarmMessage alarmMessage, String textTemplate) {
+ return String.format(textTemplate, alarmMessage.getAlarmMessage()
);
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutySettings.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutySettings.java
index 69f06c4167..d36f0577e2 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutySettings.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutySettings.java
@@ -18,26 +18,27 @@
package org.apache.skywalking.oap.server.core.alarm.provider.pagerduty;
-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;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHookSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
@Setter
@Getter
@ToString
-public class PagerDutySettings {
+public class PagerDutySettings extends AlarmHookSettings {
private String textTemplate;
- @Builder.Default
private List<String> integrationKeys = new ArrayList<>();
+
+ public PagerDutySettings(final String name,
+ final AlarmHooksType type,
+ final boolean isDefault) {
+ super(name, type, isDefault);
+ }
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackSettings.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackSettings.java
index 9c3df1cbbe..c87d60d378 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackSettings.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackSettings.java
@@ -20,23 +20,24 @@ package org.apache.skywalking.oap.server.core.alarm.provider.slack;
import java.util.ArrayList;
import java.util.List;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
import lombok.Getter;
-import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHookSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
@Setter
@Getter
@ToString
-public class SlackSettings {
+public class SlackSettings extends AlarmHookSettings {
private String textTemplate;
- @Builder.Default
private List<String> webhooks = new ArrayList<>();
+
+ public SlackSettings(final String name,
+ final AlarmHooksType type,
+ final boolean isDefault) {
+ super(name, type, isDefault);
+ }
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackhookCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackhookCallback.java
index 9974880074..99ecdb6081 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackhookCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackhookCallback.java
@@ -30,6 +30,7 @@ import org.apache.skywalking.oap.server.core.alarm.provider.AlarmRulesWatcher;
import java.net.URI;
import java.util.List;
import java.util.Map;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
/**
* Use SkyWalking alarm slack webhook API calls a remote endpoints.
@@ -43,22 +44,34 @@ public class SlackhookCallback extends HttpAlarmCallback {
@Override
public void doAlarm(List<AlarmMessage> alarmMessages) throws Exception {
- if (alarmRulesWatcher.getSlackSettings() == null || alarmRulesWatcher.getSlackSettings().getWebhooks().isEmpty()) {
+ Map<String, SlackSettings> settingsMap = alarmRulesWatcher.getSlackSettings();
+ if (settingsMap == null || settingsMap.isEmpty()) {
return;
}
- for (final var url : alarmRulesWatcher.getSlackSettings().getWebhooks()) {
- final var jsonObject = new JsonObject();
- final var jsonElements = new JsonArray();
- for (AlarmMessage item : alarmMessages) {
- jsonElements.add(GSON.fromJson(
+ Map<String, List<AlarmMessage>> groupedMessages = groupMessagesByHook(alarmMessages);
+ for (Map.Entry<String, List<AlarmMessage>> entry : groupedMessages.entrySet()) {
+ var hookName = entry.getKey();
+ var messages = entry.getValue();
+ var setting = settingsMap.get(hookName);
+ if (setting == null || CollectionUtils.isEmpty(setting.getWebhooks()) || CollectionUtils.isEmpty(
+ messages)) {
+ continue;
+ }
+
+ for (final var url : setting.getWebhooks()) {
+ final var jsonObject = new JsonObject();
+ final var jsonElements = new JsonArray();
+ for (AlarmMessage item : messages) {
+ jsonElements.add(GSON.fromJson(
String.format(
- alarmRulesWatcher.getSlackSettings().getTextTemplate(), item.getAlarmMessage()
+ setting.getTextTemplate(), item.getAlarmMessage()
), JsonObject.class));
+ }
+ jsonObject.add("blocks", jsonElements);
+ final var body = GSON.toJson(jsonObject);
+ post(URI.create(url), body, Map.of());
}
- jsonObject.add("blocks", jsonElements);
- final var body = GSON.toJson(jsonObject);
- post(URI.create(url), body, Map.of());
}
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/WebhookCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/webhook/WebhookCallback.java
similarity index 56%
rename from oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/WebhookCallback.java
rename to oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/webhook/WebhookCallback.java
index 407b88c1e0..f4b022fb05 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/WebhookCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/webhook/WebhookCallback.java
@@ -16,7 +16,7 @@
*
*/
-package org.apache.skywalking.oap.server.core.alarm.provider;
+package org.apache.skywalking.oap.server.core.alarm.provider.webhook;
import com.google.gson.Gson;
import lombok.RequiredArgsConstructor;
@@ -28,6 +28,8 @@ import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Map;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmRulesWatcher;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
/**
* Use SkyWalking alarm webhook API calls a remote endpoints.
@@ -39,13 +41,24 @@ public class WebhookCallback extends HttpAlarmCallback {
private final Gson gson = new Gson();
@Override
- public void doAlarm(List<AlarmMessage> alarmMessage) throws IOException, InterruptedException {
- if (alarmRulesWatcher.getWebHooks().isEmpty()) {
+ public void doAlarm(List<AlarmMessage> alarmMessages) throws IOException, InterruptedException {
+ Map<String, WebhookSettings> settingsMap = alarmRulesWatcher.getWebHooks();
+ if (settingsMap == null || settingsMap.isEmpty()) {
return;
}
- for (String url : alarmRulesWatcher.getWebHooks()) {
- post(URI.create(url), gson.toJson(alarmMessage), Map.of());
+ Map<String, List<AlarmMessage>> groupedMessages = groupMessagesByHook(alarmMessages);
+ for (Map.Entry<String, List<AlarmMessage>> entry : groupedMessages.entrySet()) {
+ var hookName = entry.getKey();
+ var messages = entry.getValue();
+ var setting = settingsMap.get(hookName);
+ if (setting == null || CollectionUtils.isEmpty(setting.getUrls()) || CollectionUtils.isEmpty(
+ messages)) {
+ continue;
+ }
+ for (final var url : setting.getUrls()) {
+ post(URI.create(url), gson.toJson(alarmMessages), Map.of());
+ }
}
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuSettings.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/webhook/WebhookSettings.java
similarity index 64%
copy from oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuSettings.java
copy to oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/webhook/WebhookSettings.java
index fa66b9560e..4daa76075f 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuSettings.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/webhook/WebhookSettings.java
@@ -16,35 +16,25 @@
*
*/
-package org.apache.skywalking.oap.server.core.alarm.provider.feishu;
+package org.apache.skywalking.oap.server.core.alarm.provider.webhook;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
+import java.util.ArrayList;
+import java.util.List;
import lombok.Getter;
-import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
-import java.util.ArrayList;
-import java.util.List;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHookSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
@Setter
@Getter
@ToString
-public class FeishuSettings {
-
- private String textTemplate;
- @Builder.Default
- private List<WebHookUrl> webhooks = new ArrayList<>();
+public class WebhookSettings extends AlarmHookSettings {
+ private List<String> urls = new ArrayList<>();
- @AllArgsConstructor
- @Setter
- @Getter
- @ToString
- public static class WebHookUrl {
- private final String secret;
- private final String url;
+ public WebhookSettings(final String name,
+ final AlarmHooksType type,
+ final boolean isDefault) {
+ super(name, type, isDefault);
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallback.java
index a5e1a716ae..42858ae52f 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallback.java
@@ -27,6 +27,7 @@ import org.apache.skywalking.oap.server.core.alarm.provider.AlarmRulesWatcher;
import java.net.URI;
import java.util.List;
import java.util.Map;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
/**
* Use SkyWalking alarm wechat webhook API.
@@ -38,15 +39,27 @@ public class WechatHookCallback extends HttpAlarmCallback {
@Override
public void doAlarm(List<AlarmMessage> alarmMessages) throws Exception {
- if (alarmRulesWatcher.getWechatSettings() == null || alarmRulesWatcher.getWechatSettings().getWebhooks().isEmpty()) {
+ Map<String, WechatSettings> settingsMap = alarmRulesWatcher.getWechatSettings();
+ if (settingsMap == null || settingsMap.isEmpty()) {
return;
}
- for (final var url : alarmRulesWatcher.getWechatSettings().getWebhooks()) {
- for (final var alarmMessage : alarmMessages) {
- final var requestBody = String.format(
- alarmRulesWatcher.getWechatSettings().getTextTemplate(), alarmMessage.getAlarmMessage()
- );
- post(URI.create(url), requestBody, Map.of());
+
+ Map<String, List<AlarmMessage>> groupedMessages = groupMessagesByHook(alarmMessages);
+ for (Map.Entry<String, List<AlarmMessage>> entry : groupedMessages.entrySet()) {
+ var hookName = entry.getKey();
+ var messages = entry.getValue();
+ var setting = settingsMap.get(hookName);
+ if (setting == null || CollectionUtils.isEmpty(setting.getWebhooks()) || CollectionUtils.isEmpty(
+ messages)) {
+ continue;
+ }
+ for (final var url : setting.getWebhooks()) {
+ for (final var alarmMessage : messages) {
+ final var requestBody = String.format(
+ setting.getTextTemplate(), alarmMessage.getAlarmMessage()
+ );
+ post(URI.create(url), requestBody, Map.of());
+ }
}
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatSettings.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatSettings.java
index 03063534be..f29b897d41 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatSettings.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatSettings.java
@@ -20,23 +20,24 @@ package org.apache.skywalking.oap.server.core.alarm.provider.wechat;
import java.util.ArrayList;
import java.util.List;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
import lombok.Getter;
-import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHookSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
@Setter
@Getter
@ToString
-public class WechatSettings {
+public class WechatSettings extends AlarmHookSettings {
private String textTemplate;
- @Builder.Default
private List<String> webhooks = new ArrayList<>();
+
+ public WechatSettings(final String name,
+ final AlarmHooksType type,
+ final boolean isDefault) {
+ super(name, type, isDefault);
+ }
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkHookCallback.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkHookCallback.java
index 0d7dc51ff8..5505a05b95 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkHookCallback.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkHookCallback.java
@@ -22,6 +22,7 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
+import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
@@ -36,6 +37,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.UUID;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
/**
* Use SkyWalking alarm WeLink webhook API.
@@ -50,19 +52,28 @@ public class WeLinkHookCallback extends HttpAlarmCallback {
*/
@Override
public void doAlarm(List<AlarmMessage> alarmMessages) throws Exception {
- if (alarmRulesWatcher.getWeLinkSettings() == null
- || alarmRulesWatcher.getWeLinkSettings().getWebhooks().isEmpty()) {
+ Map<String, WeLinkSettings> settingsMap = alarmRulesWatcher.getWeLinkSettings();
+ if (settingsMap == null || settingsMap.isEmpty()) {
return;
}
- final var welinkSettings = alarmRulesWatcher.getWeLinkSettings();
- for (final var webHookUrl : welinkSettings.getWebhooks()) {
- final var accessToken = getAccessToken(webHookUrl);
- for (final var alarmMessage : alarmMessages) {
- final var content = String.format(
- alarmRulesWatcher.getWeLinkSettings().getTextTemplate(),
- alarmMessage.getAlarmMessage()
- );
- sendAlarmMessage(webHookUrl, accessToken, content);
+ Map<String, List<AlarmMessage>> groupedMessages = groupMessagesByHook(alarmMessages);
+ for (Map.Entry<String, List<AlarmMessage>> entry : groupedMessages.entrySet()) {
+ var hookName = entry.getKey();
+ var messages = entry.getValue();
+ var setting = settingsMap.get(hookName);
+ if (setting == null || CollectionUtils.isEmpty(setting.getWebhooks()) || CollectionUtils.isEmpty(
+ messages)) {
+ continue;
+ }
+ for (final var webHookUrl : setting.getWebhooks()) {
+ final var accessToken = getAccessToken(webHookUrl);
+ for (final var alarmMessage : messages) {
+ final var content = String.format(
+ setting.getTextTemplate(),
+ alarmMessage.getAlarmMessage()
+ );
+ sendAlarmMessage(webHookUrl, accessToken, content);
+ }
}
}
}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkSettings.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkSettings.java
index 4c7f2b8d14..5c46093199 100644
--- a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkSettings.java
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkSettings.java
@@ -22,24 +22,26 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
-import lombok.Builder;
import lombok.Getter;
-import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHookSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
@Setter
@Getter
@ToString
-public class WeLinkSettings {
+public class WeLinkSettings extends AlarmHookSettings {
private String textTemplate;
- @Builder.Default
private List<WebHookUrl> webhooks = new ArrayList<>();
+ public WeLinkSettings(final String name,
+ final AlarmHooksType type,
+ final boolean isDefault) {
+ super(name, type, isDefault);
+ }
+
@AllArgsConstructor
@Setter
@Getter
@@ -59,12 +61,12 @@ public class WeLinkSettings {
private final String groupIds;
public static WebHookUrl generateFromMap(Map<String, String> params) {
- String clientId = params.get("client_id");
- String clientSecret = params.get("client_secret");
- String accessTokenUrl = params.get("access_token_url");
- String messageUrl = params.get("message_url");
- String groupIds = params.get("group_ids");
- String robotName = params.getOrDefault("robot_name", "robot");
+ String clientId = params.get("client-id");
+ String clientSecret = params.get("client-secret");
+ String accessTokenUrl = params.get("access-token-url");
+ String messageUrl = params.get("message-url");
+ String groupIds = params.get("group-ids");
+ String robotName = params.getOrDefault("robot-name", "robot");
return new WebHookUrl(clientId, clientSecret, accessTokenUrl, messageUrl,
robotName, groupIds
);
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmCoreTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmCoreTest.java
index 27d95863e7..69dce8cbe6 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmCoreTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmCoreTest.java
@@ -49,7 +49,6 @@ public class AlarmCoreTest {
Rules emptyRules = new Rules();
emptyRules.setRules(new ArrayList<>(0));
- emptyRules.setWebhooks(new ArrayList<>(0));
AlarmCore core = new AlarmCore(new AlarmRulesWatcher(emptyRules, null));
Map<String, List<RunningRule>> runningContext = Whitebox.getInternalState(core, "runningContext");
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRulesWatcherTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRulesWatcherTest.java
index 9f2914e30c..bc0acc0d0b 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRulesWatcherTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRulesWatcherTest.java
@@ -19,6 +19,7 @@
package org.apache.skywalking.oap.server.core.alarm.provider;
import org.apache.skywalking.oap.server.configuration.api.ConfigChangeWatcher;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
import org.apache.skywalking.oap.server.library.util.ResourceUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -83,13 +84,13 @@ public class AlarmRulesWatcherTest {
alarmRulesWatcher.notify(new ConfigChangeWatcher.ConfigChangeEvent(new String(chars, 0, length), ConfigChangeWatcher.EventType.MODIFY));
assertEquals(3, alarmRulesWatcher.getRules().size());
- assertEquals(2, alarmRulesWatcher.getWebHooks().size());
+ assertEquals(2, alarmRulesWatcher.getWebHooks().get(AlarmHooksType.webhook.name() + ".default").getUrls().size());
assertNotNull(alarmRulesWatcher.getGrpchookSetting());
- assertEquals(9888, alarmRulesWatcher.getGrpchookSetting().getTargetPort());
+ assertEquals(9888, alarmRulesWatcher.getGrpchookSetting().get(AlarmHooksType.gRPC.name() + ".default").getTargetPort());
assertEquals(2, alarmRulesWatcher.getRunningContext().size());
assertNotNull(alarmRulesWatcher.getDingtalkSettings());
assertNotNull(alarmRulesWatcher.getWechatSettings());
- assertNotNull(alarmRulesWatcher.getSlackSettings());
+ assertEquals(2, alarmRulesWatcher.getSlackSettings().size());
assertNotNull(alarmRulesWatcher.getWeLinkSettings());
}
@@ -104,7 +105,7 @@ public class AlarmRulesWatcherTest {
assertEquals(0, alarmRulesWatcher.getRules().size());
assertEquals(0, alarmRulesWatcher.getWebHooks().size());
- assertNull(alarmRulesWatcher.getGrpchookSetting());
+ assertTrue(CollectionUtils.isEmpty(alarmRulesWatcher.getGrpchookSetting()));
assertEquals(0, alarmRulesWatcher.getRunningContext().size());
}
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeRuleEvaluatorTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeRuleEvaluatorTest.java
index 27fcf1e65a..9ccddc0747 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeRuleEvaluatorTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/CompositeRuleEvaluatorTest.java
@@ -18,6 +18,7 @@
package org.apache.skywalking.oap.server.core.alarm.provider;
+import java.util.HashSet;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
import org.apache.skywalking.oap.server.core.alarm.provider.expression.Expression;
import org.apache.skywalking.oap.server.core.alarm.provider.expression.ExpressionContext;
@@ -45,7 +46,7 @@ public class CompositeRuleEvaluatorTest {
List<CompositeAlarmRule> compositeAlarmRules = new ArrayList<>();
CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "a_rule && b_rule", "composite rule {name},{id} triggered!", new HashMap<String, String>() {{
put("key", "value");
- }});
+ }}, new HashSet<>());
compositeAlarmRules.add(compositeAlarmRule);
List<AlarmMessage> alarmMessages = getAlarmMessages();
List<AlarmMessage> compositeMsgs = ruleEvaluate.evaluate(compositeAlarmRules, alarmMessages);
@@ -64,7 +65,7 @@ public class CompositeRuleEvaluatorTest {
List<CompositeAlarmRule> compositeAlarmRules = new ArrayList<>();
CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "a_rule && b_rule", "composite rule {name} triggered!", new HashMap<String, String>() {{
put("key", "value");
- }});
+ }}, new HashSet<>());
compositeAlarmRules.add(compositeAlarmRule);
List<AlarmMessage> alarmMessages = getAlarmMessages();
List<AlarmMessage> compositeMsgs = ruleEvaluate.evaluate(compositeAlarmRules, alarmMessages);
@@ -81,7 +82,7 @@ public class CompositeRuleEvaluatorTest {
@Test
public void testEvaluateMessageWithNotExistsRule() {
List<CompositeAlarmRule> compositeAlarmRules = new ArrayList<>();
- CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "a_rule && not_exist_rule", "composite rule triggered!", new HashMap<>());
+ CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "a_rule && not_exist_rule", "composite rule triggered!", new HashMap<>(), new HashSet<>());
compositeAlarmRules.add(compositeAlarmRule);
List<AlarmMessage> alarmMessages = getAlarmMessages();
List<AlarmMessage> compositeMsgs = ruleEvaluate.evaluate(compositeAlarmRules, alarmMessages);
@@ -91,7 +92,7 @@ public class CompositeRuleEvaluatorTest {
@Test
public void testEvaluateMessageWithException() {
List<CompositeAlarmRule> compositeAlarmRules = new ArrayList<>();
- CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "a_rule + b_rule", "composite rule triggered!", new HashMap<>());
+ CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "a_rule + b_rule", "composite rule triggered!", new HashMap<>(), new HashSet<>());
compositeAlarmRules.add(compositeAlarmRule);
List<AlarmMessage> alarmMessages = getAlarmMessages();
List<AlarmMessage> compositeMsgs = ruleEvaluate.evaluate(compositeAlarmRules, alarmMessages);
@@ -135,7 +136,7 @@ public class CompositeRuleEvaluatorTest {
List<CompositeAlarmRule> compositeAlarmRules = new ArrayList<>();
CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "a_rule || b_rule", "composite rule triggered!", new HashMap<String, String>() {{
put("key", "value");
- }});
+ }}, new HashSet<>());
compositeAlarmRules.add(compositeAlarmRule);
List<AlarmMessage> alarmMessages = getAlarmMessages();
alarmMessages.remove(0);
@@ -153,7 +154,7 @@ public class CompositeRuleEvaluatorTest {
@Test
public void testEvaluateMessageWithParenthesisAndOp() {
List<CompositeAlarmRule> compositeAlarmRules = new ArrayList<>();
- CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "(a_rule || b_rule) && c_rule", "composite rule triggered!", new HashMap<>());
+ CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "(a_rule || b_rule) && c_rule", "composite rule triggered!", new HashMap<>(), new HashSet<>());
compositeAlarmRules.add(compositeAlarmRule);
List<AlarmMessage> alarmMessages = getAlarmMessages();
alarmMessages.remove(alarmMessages.size() - 1);
@@ -164,7 +165,7 @@ public class CompositeRuleEvaluatorTest {
@Test
public void testEvaluateMessageWithParenthesisAndOrOp() {
List<CompositeAlarmRule> compositeAlarmRules = new ArrayList<>();
- CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "(a_rule && b_rule) || c_rule", "composite rule triggered!", new HashMap<>());
+ CompositeAlarmRule compositeAlarmRule = new CompositeAlarmRule("dummy", "(a_rule && b_rule) || c_rule", "composite rule triggered!", new HashMap<>(), new HashSet<>());
compositeAlarmRules.add(compositeAlarmRule);
List<AlarmMessage> alarmMessages = getAlarmMessages();
List<AlarmMessage> compositeMsgs = ruleEvaluate.evaluate(compositeAlarmRules, alarmMessages);
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReaderTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReaderTest.java
index 28800ce5a4..2a757c5406 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReaderTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReaderTest.java
@@ -23,7 +23,9 @@ import org.apache.skywalking.oap.server.core.alarm.provider.feishu.FeishuSetting
import org.apache.skywalking.oap.server.core.alarm.provider.grpc.GRPCAlarmSetting;
import org.apache.skywalking.oap.server.core.alarm.provider.pagerduty.PagerDutySettings;
import org.apache.skywalking.oap.server.core.alarm.provider.slack.SlackSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.webhook.WebhookSettings;
import org.apache.skywalking.oap.server.core.alarm.provider.wechat.WechatSettings;
+import org.apache.skywalking.oap.server.core.alarm.provider.welink.WeLinkSettings;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -54,32 +56,41 @@ public class RulesReaderTest {
Assertions.assertEquals("service_c", ruleList.get(1).getExcludeNames().get(0));
Assertions.assertEquals("Alarm caused by Rule service_percent_rule", ruleList.get(1).getMessage());
- List<String> rulesWebhooks = rules.getWebhooks();
- Assertions.assertEquals(2, rulesWebhooks.size());
- Assertions.assertEquals("http://127.0.0.1/go-wechat/", rulesWebhooks.get(1));
+ //endpoint_percent_rule's hooks
+ Assertions.assertEquals(8, ruleList.get(0).getHooks().size());
+ //endpoint_percent_more_rule's hooks
+ Assertions.assertEquals(2, ruleList.get(2).getHooks().size());
- GRPCAlarmSetting grpcAlarmSetting = rules.getGrpchookSetting();
+ WebhookSettings rulesWebhooks = rules.getWebhookSettingsMap().get(AlarmHooksType.webhook.name() + ".default");
+ Assertions.assertEquals(2, rulesWebhooks.getUrls().size());
+ Assertions.assertEquals("http://127.0.0.1/go-wechat/", rulesWebhooks.getUrls().get(1));
+
+ GRPCAlarmSetting grpcAlarmSetting = rules.getGrpcAlarmSettingMap().get(AlarmHooksType.gRPC.name() + ".default");
assertNotNull(grpcAlarmSetting);
assertThat(grpcAlarmSetting.getTargetHost()).isEqualTo("127.0.0.1");
assertThat(grpcAlarmSetting.getTargetPort()).isEqualTo(9888);
- SlackSettings slackSettings = rules.getSlacks();
+ SlackSettings slackSettings = rules.getSlackSettingsMap().get(AlarmHooksType.slack.name() + ".default");
assertNotNull(slackSettings);
assertThat(slackSettings.getWebhooks().size()).isEqualTo(1);
assertThat(slackSettings.getWebhooks().get(0)).isEqualTo("https://hooks.slack.com/services/x/y/zssss");
assertThat(slackSettings.getTextTemplate()).isInstanceOfAny(String.class);
- WechatSettings wechatSettings = rules.getWecchats();
+ WechatSettings wechatSettings = rules.getWechatSettingsMap().get(AlarmHooksType.wechat.name() + ".default");
assertNotNull(wechatSettings);
assertThat(wechatSettings.getWebhooks().size()).isEqualTo(1);
assertThat(wechatSettings.getWebhooks().get(0)).isEqualTo("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=dummy_key");
assertThat(slackSettings.getTextTemplate()).isInstanceOfAny(String.class);
List<CompositeAlarmRule> compositeRules = rules.getCompositeRules();
- Assertions.assertEquals(1, compositeRules.size());
+ Assertions.assertEquals(2, compositeRules.size());
Assertions.assertEquals("endpoint_percent_more_rule && endpoint_percent_rule", compositeRules.get(0).getExpression());
+ //comp1_rule's hooks
+ Assertions.assertEquals(8, compositeRules.get(0).getHooks().size());
+ //comp2_rule's hooks
+ Assertions.assertEquals(3, compositeRules.get(1).getHooks().size());
- DingtalkSettings dingtalkSettings = rules.getDingtalks();
+ DingtalkSettings dingtalkSettings = rules.getDingtalkSettingsMap().get(AlarmHooksType.dingtalk.name() + ".default");
assertThat(dingtalkSettings.getTextTemplate()).isInstanceOfAny(String.class);
List<DingtalkSettings.WebHookUrl> webHookUrls = dingtalkSettings.getWebhooks();
assertThat(webHookUrls.size()).isEqualTo(2);
@@ -88,7 +99,7 @@ public class RulesReaderTest {
assertThat(webHookUrls.get(1).getUrl()).isEqualTo("https://oapi.dingtalk.com/robot/send?access_token=dummy_token2");
assertNull(webHookUrls.get(1).getSecret());
- FeishuSettings feishuSettings = rules.getFeishus();
+ FeishuSettings feishuSettings = rules.getFeishuSettingsMap().get(AlarmHooksType.feishu.name() + ".default");
assertThat(feishuSettings.getTextTemplate()).isInstanceOfAny(String.class);
List<FeishuSettings.WebHookUrl> feishuSettingsWebhooks = feishuSettings.getWebhooks();
assertThat(feishuSettingsWebhooks.size()).isEqualTo(2);
@@ -97,11 +108,22 @@ public class RulesReaderTest {
assertThat(feishuSettingsWebhooks.get(1).getUrl()).isEqualTo("https://open.feishu.cn/open-apis/bot/v2/hook/dummy_token2");
assertNull(feishuSettingsWebhooks.get(1).getSecret());
- PagerDutySettings pagerDutySettings = rules.getPagerDutySettings();
+ PagerDutySettings pagerDutySettings = rules.getPagerDutySettingsMap().get(AlarmHooksType.pagerduty.name() + ".default");
assertEquals("dummy_text_template", pagerDutySettings.getTextTemplate());
List<String> pagerDutyIntegrationKeys = pagerDutySettings.getIntegrationKeys();
assertEquals(2, pagerDutyIntegrationKeys.size());
assertEquals("dummy_key", pagerDutyIntegrationKeys.get(0));
assertEquals("dummy_key2", pagerDutyIntegrationKeys.get(1));
+
+ WeLinkSettings weLinkSettings = rules.getWeLinkSettingsMap().get(AlarmHooksType.welink.name() + ".default");
+ assertThat(weLinkSettings.getTextTemplate()).isInstanceOfAny(String.class);
+ List<WeLinkSettings.WebHookUrl> weiWebHookUrls = weLinkSettings.getWebhooks();
+ assertThat(weiWebHookUrls.size()).isEqualTo(1);
+ assertThat(weiWebHookUrls.get(0).getAccessTokenUrl()).isEqualTo("https://open.welink.huaweicloud.com/api/auth/v2/tickets");
+ assertThat(weiWebHookUrls.get(0).getMessageUrl()).isEqualTo("https://open.welink.huaweicloud.com/api/welinkim/v1/im-service/chat/group-chat");
+ assertThat(weiWebHookUrls.get(0).getClientId()).isEqualTo("dummy_client_id");
+ assertThat(weiWebHookUrls.get(0).getClientSecret()).isEqualTo("dummy_secret_key");
+ assertThat(weiWebHookUrls.get(0).getRobotName()).isEqualTo("robot");
+ assertThat(weiWebHookUrls.get(0).getGroupIds()).isEqualTo("dummy_group_id");
}
}
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkHookCallbackTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkHookCallbackTest.java
index a15a0269c5..175d3349bb 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkHookCallbackTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/dingtalk/DingtalkHookCallbackTest.java
@@ -25,6 +25,7 @@ import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
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;
@@ -80,7 +81,14 @@ public class DingtalkHookCallbackTest {
webHooks.add(new DingtalkSettings.WebHookUrl("", "http://127.0.0.1:" + SERVER.httpPort() + "/dingtalkhook/receiveAlarm?token=dummy_token"));
Rules rules = new Rules();
String template = "{\"msgtype\":\"text\",\"text\":{\"content\":\"Skywaling alarm: %s\"}}";
- rules.setDingtalks(DingtalkSettings.builder().webhooks(webHooks).textTemplate(template).build());
+ DingtalkSettings setting1 = new DingtalkSettings("setting1", AlarmHooksType.dingtalk, true);
+ setting1.setWebhooks(webHooks);
+ setting1.setTextTemplate(template);
+ DingtalkSettings setting2 = new DingtalkSettings("setting2", AlarmHooksType.dingtalk, false);
+ setting2.setWebhooks(webHooks);
+ setting2.setTextTemplate(template);
+ rules.getDingtalkSettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getDingtalkSettingsMap().put(setting2.getFormattedName(), setting2);
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
DingtalkHookCallback dingtalkCallBack = new DingtalkHookCallback(alarmRulesWatcher);
@@ -89,11 +97,13 @@ public class DingtalkHookCallbackTest {
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
+ alarmMessage.getHooks().add(setting1.getFormattedName());
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
alarmMessages.add(anotherAlarmMessage);
dingtalkCallBack.doAlarm(alarmMessages);
Assertions.assertTrue(IS_SUCCESS.get());
@@ -106,7 +116,14 @@ public class DingtalkHookCallbackTest {
webHooks.add(new DingtalkSettings.WebHookUrl(secret, "http://127.0.0.1:" + SERVER.httpPort() + "/dingtalkhook/receiveAlarm?token=dummy_token"));
Rules rules = new Rules();
String template = "{\"msgtype\":\"text\",\"text\":{\"content\":\"Skywaling alarm: %s\"}}";
- rules.setDingtalks(DingtalkSettings.builder().webhooks(webHooks).textTemplate(template).build());
+ DingtalkSettings setting1 = new DingtalkSettings("setting1", AlarmHooksType.dingtalk, true);
+ setting1.setWebhooks(webHooks);
+ setting1.setTextTemplate(template);
+ DingtalkSettings setting2 = new DingtalkSettings("setting2", AlarmHooksType.dingtalk, false);
+ setting2.setWebhooks(webHooks);
+ setting2.setTextTemplate(template);
+ rules.getDingtalkSettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getDingtalkSettingsMap().put(setting2.getFormattedName(), setting2);
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
DingtalkHookCallback dingtalkCallBack = new DingtalkHookCallback(alarmRulesWatcher);
@@ -115,11 +132,13 @@ public class DingtalkHookCallbackTest {
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
+ alarmMessage.getHooks().add(setting1.getFormattedName());
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
alarmMessages.add(anotherAlarmMessage);
dingtalkCallBack.doAlarm(alarmMessages);
Assertions.assertTrue(IS_SUCCESS.get());
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuHookCallbackTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuHookCallbackTest.java
index 36d5cfe8a9..371e4f06e1 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuHookCallbackTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/feishu/FeishuHookCallbackTest.java
@@ -25,6 +25,7 @@ import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
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;
@@ -78,7 +79,14 @@ public class FeishuHookCallbackTest {
webHooks.add(new FeishuSettings.WebHookUrl("", "http://127.0.0.1:" + SERVER.httpPort() + "/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());
+ FeishuSettings setting1 = new FeishuSettings("setting1", AlarmHooksType.feishu, true);
+ setting1.setWebhooks(webHooks);
+ setting1.setTextTemplate(template);
+ FeishuSettings setting2 = new FeishuSettings("setting2", AlarmHooksType.feishu, false);
+ setting2.setWebhooks(webHooks);
+ setting2.setTextTemplate(template);
+ rules.getFeishuSettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getFeishuSettingsMap().put(setting2.getFormattedName(), setting2);
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
FeishuHookCallback feishuHookCallback = new FeishuHookCallback(alarmRulesWatcher);
@@ -87,11 +95,13 @@ public class FeishuHookCallbackTest {
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
+ alarmMessage.getHooks().add(setting1.getFormattedName());
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
alarmMessages.add(anotherAlarmMessage);
feishuHookCallback.doAlarm(alarmMessages);
Assertions.assertTrue(IS_SUCCESS.get());
@@ -104,7 +114,14 @@ public class FeishuHookCallbackTest {
webHooks.add(new FeishuSettings.WebHookUrl(secret, "http://127.0.0.1:" + SERVER.httpPort() + "/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());
+ FeishuSettings setting1 = new FeishuSettings("setting1", AlarmHooksType.feishu, true);
+ setting1.setWebhooks(webHooks);
+ setting1.setTextTemplate(template);
+ FeishuSettings setting2 = new FeishuSettings("setting2", AlarmHooksType.feishu, false);
+ setting2.setWebhooks(webHooks);
+ setting2.setTextTemplate(template);
+ rules.getFeishuSettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getFeishuSettingsMap().put(setting2.getFormattedName(), setting2);
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
FeishuHookCallback feishuHookCallback = new FeishuHookCallback(alarmRulesWatcher);
@@ -113,11 +130,13 @@ public class FeishuHookCallbackTest {
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
+ alarmMessage.getHooks().add(setting1.getFormattedName());
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
alarmMessages.add(anotherAlarmMessage);
feishuHookCallback.doAlarm(alarmMessages);
Assertions.assertTrue(IS_SUCCESS.get());
@@ -130,7 +149,14 @@ public class FeishuHookCallbackTest {
webHooks.add(new FeishuSettings.WebHookUrl(secret, "http://127.0.0.1:" + SERVER.httpPort() + "/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());
+ FeishuSettings setting1 = new FeishuSettings("setting1", AlarmHooksType.feishu, true);
+ setting1.setWebhooks(webHooks);
+ setting1.setTextTemplate(template);
+ FeishuSettings setting2 = new FeishuSettings("setting2", AlarmHooksType.feishu, false);
+ setting2.setWebhooks(webHooks);
+ setting2.setTextTemplate(template);
+ rules.getFeishuSettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getFeishuSettingsMap().put(setting2.getFormattedName(), setting2);
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
FeishuHookCallback feishuHookCallback = new FeishuHookCallback(alarmRulesWatcher);
@@ -139,11 +165,13 @@ public class FeishuHookCallbackTest {
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
+ alarmMessage.getHooks().add(setting1.getFormattedName());
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
alarmMessages.add(anotherAlarmMessage);
feishuHookCallback.doAlarm(alarmMessages);
Assertions.assertTrue(IS_SUCCESS.get());
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPChookCallbackTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPChookCallbackTest.java
index 9154ddd6f9..d4732e19da 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPChookCallbackTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/grpc/GRPChookCallbackTest.java
@@ -23,6 +23,7 @@ import com.google.common.collect.Lists;
import java.util.Arrays;
import java.util.List;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
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.analysis.manual.searchtag.Tag;
@@ -40,16 +41,19 @@ public class GRPChookCallbackTest {
@BeforeEach
public void init() throws Exception {
- GRPCAlarmSetting setting = new GRPCAlarmSetting();
- setting.setTargetHost("127.0.0.1");
- setting.setTargetPort(9888);
-
Rules rules = new Rules();
- rules.setGrpchookSetting(setting);
+ GRPCAlarmSetting setting1 = new GRPCAlarmSetting("setting1", AlarmHooksType.gRPC, true);
+ setting1.setTargetHost("127.0.0.1");
+ setting1.setTargetPort(9888);
+ GRPCAlarmSetting setting2 = new GRPCAlarmSetting("setting2", AlarmHooksType.gRPC, false);
+ setting2.setTargetHost("127.0.0.1");
+ setting2.setTargetPort(9888);
+ rules.getGrpcAlarmSettingMap().put(setting1.getFormattedName(), setting1);
+ rules.getGrpcAlarmSettingMap().put(setting2.getFormattedName(), setting2);
alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
grpcCallback = new GRPCCallback(alarmRulesWatcher);
- mockAlarmMessage();
+ mockAlarmMessage(setting1.getFormattedName(), setting2.getFormattedName());
}
@Test
@@ -59,15 +63,17 @@ public class GRPChookCallbackTest {
@Test
public void testGauchoSettingClean() {
- GRPCAlarmSetting grpcAlarmSetting = new GRPCAlarmSetting();
Rules rules = new Rules();
- rules.setGrpchookSetting(grpcAlarmSetting);
+ GRPCAlarmSetting setting1 = new GRPCAlarmSetting("setting1111111", AlarmHooksType.gRPC, true);
+ GRPCAlarmSetting setting2 = new GRPCAlarmSetting("setting2222222", AlarmHooksType.gRPC, true);
+ rules.getGrpcAlarmSettingMap().put(setting1.getFormattedName(), setting1);
+ rules.getGrpcAlarmSettingMap().put(setting2.getFormattedName(), setting2);
alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
grpcCallback = new GRPCCallback(alarmRulesWatcher);
grpcCallback.doAlarm(alarmMessageList);
}
- private void mockAlarmMessage() {
+ private void mockAlarmMessage(String hook1, String hook2) {
AlarmMessage alarmMessage = new AlarmMessage();
alarmMessage.setId0("1");
alarmMessage.setId1("2");
@@ -77,6 +83,17 @@ public class GRPChookCallbackTest {
alarmMessage.setRuleName("mock_rule");
alarmMessage.setStartTime(System.currentTimeMillis());
alarmMessage.setTags(Arrays.asList(new Tag("key", "value")));
- alarmMessageList = Lists.newArrayList(alarmMessage);
+ alarmMessage.getHooks().add(hook1);
+ AlarmMessage alarmMessage2 = new AlarmMessage();
+ alarmMessage2.setId0("21");
+ alarmMessage2.setId1("22");
+ alarmMessage2.setScope(Scope.Service.name());
+ alarmMessage2.setName("mock alarm message2");
+ alarmMessage2.setAlarmMessage("message2");
+ alarmMessage2.setRuleName("mock_rule2");
+ alarmMessage2.setStartTime(System.currentTimeMillis());
+ alarmMessage2.setTags(Arrays.asList(new Tag("key2", "value2")));
+ alarmMessage2.getHooks().add(hook1);
+ alarmMessageList = Lists.newArrayList(alarmMessage, alarmMessage2);
}
}
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutyHookCallbackTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutyHookCallbackTest.java
index 62beade7e1..08b9c7b31d 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutyHookCallbackTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/pagerduty/PagerDutyHookCallbackTest.java
@@ -18,7 +18,9 @@
package org.apache.skywalking.oap.server.core.alarm.provider.pagerduty;
+import java.util.ArrayList;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
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;
@@ -39,36 +41,33 @@ public class PagerDutyHookCallbackTest {
);
Rules rules = new Rules();
- rules.setPagerDutySettings(
- PagerDutySettings.builder()
- .integrationKeys(integrationKeys)
- .textTemplate("Apache SkyWalking Alarm: \n %s.")
- .build()
- );
-
+ PagerDutySettings setting1 = new PagerDutySettings("setting1", AlarmHooksType.pagerduty, true);
+ setting1.setIntegrationKeys(integrationKeys);
+ setting1.setTextTemplate("Apache SkyWalking Alarm: \\n %s.");
+ PagerDutySettings setting2 = new PagerDutySettings("setting2", AlarmHooksType.pagerduty, false);
+ setting2.setIntegrationKeys(integrationKeys);
+ setting2.setTextTemplate("Apache SkyWalking Alarm: \\n %s.");
+ rules.getPagerDutySettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getPagerDutySettingsMap().put(setting2.getFormattedName(), setting2);
PagerDutyHookCallback pagerDutyHookCallback = new PagerDutyHookCallback(
- new AlarmRulesWatcher(rules, null)
+ new AlarmRulesWatcher(rules, null)
);
-
- pagerDutyHookCallback.doAlarm(getMockAlarmMessages());
-
- // please check your pagerduty account to see if the alarm is sent
- }
-
- private List<AlarmMessage> getMockAlarmMessages() {
+ List<AlarmMessage> alarmMessages = new ArrayList<>(2);
AlarmMessage alarmMessage = new AlarmMessage();
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
-
+ alarmMessage.getHooks().add(setting1.getFormattedName());
+ alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
- anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
+ anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
+ alarmMessages.add(anotherAlarmMessage);
- return Arrays.asList(
- alarmMessage,
- anotherAlarmMessage
- );
+ pagerDutyHookCallback.doAlarm(alarmMessages);
+
+ // please check your pagerduty account to see if the alarm is sent
}
}
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallbackTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackHookCallbackTest.java
similarity index 71%
copy from oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallbackTest.java
copy to oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackHookCallbackTest.java
index 3a396e0cb6..33e9ef105a 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallbackTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/slack/SlackHookCallbackTest.java
@@ -16,7 +16,7 @@
*
*/
-package org.apache.skywalking.oap.server.core.alarm.provider.wechat;
+package org.apache.skywalking.oap.server.core.alarm.provider.slack;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
@@ -24,7 +24,12 @@ import com.linecorp.armeria.common.HttpResponse;
import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
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;
@@ -32,12 +37,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class WechatHookCallbackTest {
+public class SlackHookCallbackTest {
private static final AtomicBoolean IS_SUCCESS = new AtomicBoolean();
private static final AtomicInteger COUNT = new AtomicInteger();
@@ -45,12 +45,12 @@ public class WechatHookCallbackTest {
public static final ServerExtension SERVER = new ServerExtension() {
@Override
protected void configure(ServerBuilder sb) {
- sb.service("/wechathook/receiveAlarm", (ctx, req) -> HttpResponse.from(
+ sb.service("/services/x/y/zssss", (ctx, req) -> HttpResponse.from(
req.aggregate().thenApply(r -> {
final String content = r.content().toStringUtf8();
- final JsonObject jsonObject = new Gson().fromJson(content, JsonObject.class);
- final String type = jsonObject.get("msgtype").getAsString();
- if (type.equalsIgnoreCase("text")) {
+ final JsonObject jsonObject = new Gson().fromJson(content, JsonObject.class).get("blocks").getAsJsonArray().get(0).getAsJsonObject();
+ final String type = jsonObject.get("type").getAsString();
+ if (type.equalsIgnoreCase("section")) {
COUNT.incrementAndGet();
if (COUNT.get() == 2) {
IS_SUCCESS.set(true);
@@ -67,24 +67,33 @@ public class WechatHookCallbackTest {
@Test
public void testWechatWebhook() throws Exception {
List<String> remoteEndpoints = new ArrayList<>();
- remoteEndpoints.add("http://127.0.0.1:" + SERVER.httpPort() + "/wechathook/receiveAlarm");
+ remoteEndpoints.add("http://127.0.0.1:" + SERVER.httpPort() + "/services/x/y/zssss");
Rules rules = new Rules();
- String template = "{\"msgtype\":\"text\",\"text\":{\"content\":\"Skywaling alarm: %s\"}}";
- rules.setWecchats(WechatSettings.builder().webhooks(remoteEndpoints).textTemplate(template).build());
+ String template = "{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\":alarm_clock: *Apache Skywalking Alarm* \\n **%s**.\"}}";
+ SlackSettings setting1 = new SlackSettings("setting1", AlarmHooksType.slack, true);
+ setting1.setWebhooks(remoteEndpoints);
+ setting1.setTextTemplate(template);
+ SlackSettings setting2 = new SlackSettings("setting2", AlarmHooksType.slack, false);
+ setting2.setWebhooks(remoteEndpoints);
+ setting2.setTextTemplate(template);
+ rules.getSlackSettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getSlackSettingsMap().put(setting2.getFormattedName(), setting2);
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
- WechatHookCallback wechatHookCallback = new WechatHookCallback(alarmRulesWatcher);
+ SlackhookCallback slackhookCallback = new SlackhookCallback(alarmRulesWatcher);
List<AlarmMessage> alarmMessages = new ArrayList<>(2);
AlarmMessage alarmMessage = new AlarmMessage();
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
+ alarmMessage.getHooks().add(setting1.getFormattedName());
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
alarmMessages.add(anotherAlarmMessage);
- wechatHookCallback.doAlarm(alarmMessages);
+ slackhookCallback.doAlarm(alarmMessages);
Assertions.assertTrue(IS_SUCCESS.get());
}
}
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/WebhookCallbackTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/webhook/WebhookCallbackTest.java
similarity index 80%
rename from oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/WebhookCallbackTest.java
rename to oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/webhook/WebhookCallbackTest.java
index 4e8e61b010..ddba59bf72 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/WebhookCallbackTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/webhook/WebhookCallbackTest.java
@@ -16,7 +16,7 @@
*
*/
-package org.apache.skywalking.oap.server.core.alarm.provider;
+package org.apache.skywalking.oap.server.core.alarm.provider.webhook;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
@@ -25,6 +25,9 @@ import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
+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.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -62,7 +65,12 @@ public class WebhookCallbackTest {
List<String> remoteEndpoints = new ArrayList<>();
remoteEndpoints.add("http://127.0.0.1:" + SERVER.httpPort() + "/webhook/receiveAlarm");
Rules rules = new Rules();
- rules.setWebhooks(remoteEndpoints);
+ WebhookSettings setting1 = new WebhookSettings("setting1", AlarmHooksType.wechat, true);
+ setting1.setUrls(remoteEndpoints);
+ WebhookSettings setting2 = new WebhookSettings("setting2", AlarmHooksType.wechat, false);
+ setting2.setUrls(remoteEndpoints);
+ rules.getWebhookSettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getWebhookSettingsMap().put(setting2.getFormattedName(), setting2);
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
WebhookCallback webhookCallback = new WebhookCallback(alarmRulesWatcher);
List<AlarmMessage> alarmMessages = new ArrayList<>(2);
@@ -70,11 +78,13 @@ public class WebhookCallbackTest {
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
+ alarmMessage.getHooks().add(setting1.getFormattedName());
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
alarmMessages.add(anotherAlarmMessage);
webhookCallback.doAlarm(alarmMessages);
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallbackTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallbackTest.java
index 3a396e0cb6..eb555022e4 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallbackTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/wechat/WechatHookCallbackTest.java
@@ -25,6 +25,7 @@ import com.linecorp.armeria.common.HttpStatus;
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
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;
@@ -70,7 +71,14 @@ public class WechatHookCallbackTest {
remoteEndpoints.add("http://127.0.0.1:" + SERVER.httpPort() + "/wechathook/receiveAlarm");
Rules rules = new Rules();
String template = "{\"msgtype\":\"text\",\"text\":{\"content\":\"Skywaling alarm: %s\"}}";
- rules.setWecchats(WechatSettings.builder().webhooks(remoteEndpoints).textTemplate(template).build());
+ WechatSettings setting1 = new WechatSettings("setting1", AlarmHooksType.wechat, true);
+ setting1.setWebhooks(remoteEndpoints);
+ setting1.setTextTemplate(template);
+ WechatSettings setting2 = new WechatSettings("setting2", AlarmHooksType.wechat, false);
+ setting2.setWebhooks(remoteEndpoints);
+ setting2.setTextTemplate(template);
+ rules.getWechatSettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getWechatSettingsMap().put(setting2.getFormattedName(), setting2);
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
WechatHookCallback wechatHookCallback = new WechatHookCallback(alarmRulesWatcher);
List<AlarmMessage> alarmMessages = new ArrayList<>(2);
@@ -78,11 +86,13 @@ public class WechatHookCallbackTest {
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
+ alarmMessage.getHooks().add(setting1.getFormattedName());
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
alarmMessages.add(anotherAlarmMessage);
wechatHookCallback.doAlarm(alarmMessages);
Assertions.assertTrue(IS_SUCCESS.get());
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkHookCallbackTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkHookCallbackTest.java
index ea41298e3b..0b0921b94d 100644
--- a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkHookCallbackTest.java
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/welink/WeLinkHookCallbackTest.java
@@ -19,6 +19,7 @@
package org.apache.skywalking.oap.server.core.alarm.provider.welink;
import com.google.gson.Gson;
+import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.linecorp.armeria.common.HttpResponse;
import com.linecorp.armeria.common.HttpStatus;
@@ -26,6 +27,7 @@ import com.linecorp.armeria.common.MediaType;
import com.linecorp.armeria.server.ServerBuilder;
import com.linecorp.armeria.testing.junit5.server.ServerExtension;
import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
+import org.apache.skywalking.oap.server.core.alarm.provider.AlarmHooksType;
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;
@@ -51,18 +53,15 @@ public class WeLinkHookCallbackTest {
final String content = r.content().toStringUtf8();
final JsonObject jsonObject = new Gson().fromJson(content, JsonObject.class);
- if (COUNT.get() == 0) {
- String clientId = jsonObject.get("client_id").getAsString();
- if (clientId != null) {
- COUNT.incrementAndGet();
- }
- } else if (COUNT.get() >= 1) {
- String appMsgId = jsonObject.get("app_msg_id").getAsString();
- if (appMsgId != null) {
- COUNT.incrementAndGet();
- }
+ JsonElement clientId = jsonObject.get("client_id");
+ if (clientId != null) {
+ COUNT.incrementAndGet();
}
- if (COUNT.get() == 2) {
+ JsonElement appMsgId = jsonObject.get("app_msg_id");
+ if (appMsgId != null) {
+ COUNT.incrementAndGet();
+ }
+ if (COUNT.get() == 4) {
IS_SUCCESS.set(true);
}
@@ -81,7 +80,14 @@ public class WeLinkHookCallbackTest {
));
Rules rules = new Rules();
String template = "Apache SkyWalking Alarm: \n %s.";
- rules.setWelinks(WeLinkSettings.builder().webhooks(webHooks).textTemplate(template).build());
+ WeLinkSettings setting1 = new WeLinkSettings("setting1", AlarmHooksType.welink, true);
+ setting1.setWebhooks(webHooks);
+ setting1.setTextTemplate(template);
+ WeLinkSettings setting2 = new WeLinkSettings("setting2", AlarmHooksType.welink, false);
+ setting2.setWebhooks(webHooks);
+ setting2.setTextTemplate(template);
+ rules.getWeLinkSettingsMap().put(setting1.getFormattedName(), setting1);
+ rules.getWeLinkSettingsMap().put(setting2.getFormattedName(), setting2);
AlarmRulesWatcher alarmRulesWatcher = new AlarmRulesWatcher(rules, null);
WeLinkHookCallback welinkHookCallback = new WeLinkHookCallback(alarmRulesWatcher);
@@ -90,11 +96,13 @@ public class WeLinkHookCallbackTest {
alarmMessage.setScopeId(DefaultScopeDefine.SERVICE);
alarmMessage.setRuleName("service_resp_time_rule");
alarmMessage.setAlarmMessage("alarmMessage with [DefaultScopeDefine.All]");
+ alarmMessage.getHooks().add(setting1.getFormattedName());
alarmMessages.add(alarmMessage);
AlarmMessage anotherAlarmMessage = new AlarmMessage();
anotherAlarmMessage.setRuleName("service_resp_time_rule_2");
anotherAlarmMessage.setScopeId(DefaultScopeDefine.ENDPOINT);
anotherAlarmMessage.setAlarmMessage("anotherAlarmMessage with [DefaultScopeDefine.Endpoint]");
+ anotherAlarmMessage.getHooks().add(setting2.getFormattedName());
alarmMessages.add(anotherAlarmMessage);
welinkHookCallback.doAlarm(alarmMessages);
Assertions.assertTrue(IS_SUCCESS.get());
diff --git a/oap-server/server-alarm-plugin/src/test/resources/alarm-settings.yml b/oap-server/server-alarm-plugin/src/test/resources/alarm-settings.yml
index cb60cb4465..48f9b60f9a 100755
--- a/oap-server/server-alarm-plugin/src/test/resources/alarm-settings.yml
+++ b/oap-server/server-alarm-plugin/src/test/resources/alarm-settings.yml
@@ -57,86 +57,135 @@ rules:
# Control if this rule is just as a composite rule condition. do not notification alone
only-as-condition: false
message: Successful rate of endpoint {name} is higher than 60%
+ hooks:
+ - "slack.custom1"
+ - "pagerduty.custom1"
composite-rules:
comp1_rule:
expression: endpoint_percent_more_rule && endpoint_percent_rule
message: xxxxx
+ comp2_rule:
+ expression: endpoint_percent_more_rule && endpoint_percent_rule
+ message: xxxxx
+ hooks:
+ - "slack.default"
+ - "slack.custom1"
+ - "pagerduty.custom1"
-webhooks:
- - http://127.0.0.1/notify/
- - http://127.0.0.1/go-wechat/
+hooks:
+ webhook:
+ default:
+ is-default: true
+ urls:
+ - http://127.0.0.1/notify/
+ - http://127.0.0.1/go-wechat/
-gRPCHook:
- target_host: 127.0.0.1
- target_port: 9888
+ gRPC:
+ default:
+ is-default: true
+ target-host: 127.0.0.1
+ target-port: 9888
-slackHooks:
- textTemplate: |-
- {
- "type": "section",
- "text": {
- "type": "mrkdwn",
- "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
- }
- }
- webhooks:
- - https://hooks.slack.com/services/x/y/zssss
+ slack:
+ default:
+ is-default: true
+ text-template: |-
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
+ }
+ }
+ webhooks:
+ - https://hooks.slack.com/services/x/y/zssss
+ custom1:
+ text-template: |-
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
+ }
+ }
+ webhooks:
+ - https://hooks.slack.com/services/x/y/zssss
-wechatHooks:
- textTemplate: |-
- {
- "msgtype": "text",
- "text": {
- "content": "Apache SkyWalking Alarm: \n %s."
- }
- }
- webhooks:
- - https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=dummy_key
+ wechat:
+ default:
+ is-default: true
+ text-template: |-
+ {
+ "msgtype": "text",
+ "text": {
+ "content": "Apache SkyWalking Alarm: \n %s."
+ }
+ }
+ webhooks:
+ - https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=dummy_key
-dingtalkHooks:
- textTemplate: |-
- {
- "msgtype": "text",
- "text": {
- "content": "Apache SkyWalking Alarm: \n %s."
- }
- }
- webhooks:
- - url: https://oapi.dingtalk.com/robot/send?access_token=dummy_token
- secret: dummysecret
- - url: https://oapi.dingtalk.com/robot/send?access_token=dummy_token2
- secret:
+ dingtalk:
+ default:
+ is-default: true
+ text-template: |-
+ {
+ "msgtype": "text",
+ "text": {
+ "content": "Apache SkyWalking Alarm: \n %s."
+ }
+ }
+ webhooks:
+ - url: https://oapi.dingtalk.com/robot/send?access_token=dummy_token
+ 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:
+ feishu:
+ default:
+ is-default: true
+ text-template: |-
+ {
+ "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
+ - url: https://open.feishu.cn/open-apis/bot/v2/hook/dummy_token2
+ secret:
-welinkHooks:
- textTemplate: "Apache SkyWalking Alarm: \n %s."
- webhooks:
- # you may find your own client_id and client_secret in your app, below are dummy, need to change.
- - client_id: "dummy_client_id"
- client_secret: dummy_secret_key
- access_token_url: https://open.welink.huaweicloud.com/api/auth/v2/tickets
- message_url: https://open.welink.huaweicloud.com/api/welinkim/v1/im-service/chat/group-chat
- # if you send to multi group at a time, separate group_ids with commas, e.g. "123xx","456xx"
- group_ids: "dummy_group_id"
- # make a name you like for the robot, it will display in group
- robot_name: robot
+ welink:
+ default:
+ is-default: true
+ text-template: "Apache SkyWalking Alarm: \n %s."
+ webhooks:
+ # you may find your own client_id and client_secret in your app, below are dummy, need to change.
+ - client-id: "dummy_client_id"
+ client-secret: dummy_secret_key
+ access-token-url: https://open.welink.huaweicloud.com/api/auth/v2/tickets
+ message-url: https://open.welink.huaweicloud.com/api/welinkim/v1/im-service/chat/group-chat
+ # if you send to multi group at a time, separate group_ids with commas, e.g. "123xx","456xx"
+ group-ids: "dummy_group_id"
+ # make a name you like for the robot, it will display in group
+ robot-name: robot
-pagerDutyHooks:
- textTemplate: "dummy_text_template"
- integrationKeys:
- - dummy_key
- - dummy_key2
\ No newline at end of file
+ pagerduty:
+ default:
+ is-default: true
+ text-template: "dummy_text_template"
+ integration-keys:
+ - dummy_key
+ - dummy_key2
+ custom1:
+ text-template: "Apache SkyWalking Alarm: \n %s."
+ integration-keys:
+ # # you can find your integration key(s) on the Events API V2 integration page for your PagerDuty service(s).
+ # # (you may need to create an Events API V2 integration for your PagerDuty service if you don't have one yet)
+ # # below are dummy keys that should be replaced with your own integration keys.
+ - dummy_key
+ - dummy_key2
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java
index d4730876a0..b6e3a4d398 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java
@@ -18,11 +18,27 @@
package org.apache.skywalking.oap.server.core.alarm;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* Alarm call back will be called by alarm implementor, after it decided alarm should be sent.
*/
public interface AlarmCallback {
- void doAlarm(List<AlarmMessage> alarmMessage) throws Exception;
+ default Map<String, List<AlarmMessage>> groupMessagesByHook(List<AlarmMessage> alarmMessages) {
+ Map<String, List<AlarmMessage>> result = new HashMap<>();
+ alarmMessages.forEach(message -> {
+ Set<String> hooks = message.getHooks();
+ hooks.forEach(hook -> {
+ List<AlarmMessage> messages = result.computeIfAbsent(hook, v -> new ArrayList<>());
+ messages.add(message);
+ });
+ });
+ return result;
+ }
+
+ void doAlarm(List<AlarmMessage> alarmMessages) throws Exception;
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmMessage.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmMessage.java
index c778c988ca..d3f629878f 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmMessage.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmMessage.java
@@ -18,6 +18,8 @@
package org.apache.skywalking.oap.server.core.alarm;
+import java.util.HashSet;
+import java.util.Set;
import lombok.Getter;
import lombok.Setter;
import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.Tag;
@@ -41,4 +43,5 @@ public class AlarmMessage {
private long startTime;
private transient int period;
private transient boolean onlyAsCondition;
+ private Set<String> hooks = new HashSet<>();
}
diff --git a/oap-server/server-starter/src/main/resources/alarm-settings.yml b/oap-server/server-starter/src/main/resources/alarm-settings.yml
index e145d4e744..718376f08a 100755
--- a/oap-server/server-starter/src/main/resources/alarm-settings.yml
+++ b/oap-server/server-starter/src/main/resources/alarm-settings.yml
@@ -41,81 +41,133 @@ rules:
tags:
level: WARNING
-webhooks:
-# - http://127.0.0.1/notify/
-# - http://127.0.0.1/go-wechat/
-
-gRPCHook:
-# target_host: 127.0.0.1
-# target_port: 9888
-
-slackHooks:
- textTemplate: |-
- {
- "type": "section",
- "text": {
- "type": "mrkdwn",
- "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
- }
- }
- webhooks:
-# - https://hooks.slack.com/services/x/y/zssss
-
-wechatHooks:
- textTemplate: |-
- {
- "msgtype": "text",
- "text": {
- "content": "Apache SkyWalking Alarm: \n %s."
- }
- }
- webhooks:
-# - https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=dummy_key
-
-dingtalkHooks:
- textTemplate: |-
- {
- "msgtype": "text",
- "text": {
- "content": "Apache SkyWalking Alarm: \n %s."
- }
- }
- 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
-
-welinkHooks:
- textTemplate: "Apache SkyWalking Alarm: \n %s."
- webhooks:
-# # you may find your own client_id and client_secret in your app, below are dummy, need to change.
-# - client_id: "dummy_client_id"
-# client_secret: dummy_secret_key
-# access_token_url: https://open.welink.huaweicloud.com/api/auth/v2/tickets
-# message_url: https://open.welink.huaweicloud.com/api/welinkim/v1/im-service/chat/group-chat
-# # if you send to multi group at a time, separate group_ids with commas, e.g. "123xx","456xx"
-# group_ids: "dummy_group_id"
-# # make a name you like for the robot, it will display in group
-# robot_name: robot
+ service_cpm_rule:
+ metrics-name: service_cpm
+ # [Optional] Default, match all services in this metrics
+ threshold: 1
+ op: ">"
+ period: 10
+ count: 1
+ tags:
+ level: WARNING
+ # Binding the specific names of the hooks when the alarm is triggered. The name format is {hookType}.{hookName}
+# hooks:
+# - "slack.custom1"
+# - "pagerduty.custom1"
-pagerDutyHooks:
- textTemplate: "Apache SkyWalking Alarm: \n %s."
- integrationKeys:
-# # you can find your integration key(s) on the Events API V2 integration page for your PagerDuty service(s).
-# # (you may need to create an Events API V2 integration for your PagerDuty service if you don't have one yet)
-# # below are dummy keys that should be replaced with your own integration keys.
-# - dummy_key
-# - dummy_key2
+hooks:
+# webhook:
+# default:
+# # If true, this hook will apply on all rules, unless a rule has its own specific hook. Could have more than one default hooks in the same hook type.
+# is-default: true
+# urls:
+# - http://127.0.0.1/notify/
+# - http://127.0.0.1/go-wechat/
+#
+# gRPC:
+# default:
+# is-default: true
+# target-host: 127.0.0.1
+# target-port: 9888
+#
+# slack:
+# default:
+# is-default: true
+# text-template: |-
+# {
+# "type": "section",
+# "text": {
+# "type": "mrkdwn",
+# "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
+# }
+# }
+# webhooks:
+# - https://hooks.slack.com/services/x/y/zssss
+# custom1:
+# text-template: |-
+# {
+# "type": "section",
+# "text": {
+# "type": "mrkdwn",
+# "text": ":alarm_clock: *Apache Skywalking Alarm* \n **%s**."
+# }
+# }
+# webhooks:
+# - https://hooks.slack.com/services/x/y/custom1
+#
+# pagerduty:
+# default:
+# is-default: true
+# text-template: "Apache SkyWalking Alarm: \n %s."
+# integration-keys:
+# # # you can find your integration key(s) on the Events API V2 integration page for your PagerDuty service(s).
+# # # (you may need to create an Events API V2 integration for your PagerDuty service if you don't have one yet)
+# # # below are dummy keys that should be replaced with your own integration keys.
+# - dummy_key
+# - dummy_key2
+# custom1:
+# text-template: "Apache SkyWalking Alarm: \n %s."
+# integration-keys:
+# # # you can find your integration key(s) on the Events API V2 integration page for your PagerDuty service(s).
+# # # (you may need to create an Events API V2 integration for your PagerDuty service if you don't have one yet)
+# # # below are dummy keys that should be replaced with your own integration keys.
+# - dummy_key
+# - dummy_key2
+#
+# wechat:
+# default:
+# is-default: true
+# text-template: |-
+# {
+# "msgtype": "text",
+# "text": {
+# "content": "Apache SkyWalking Alarm: \n %s."
+# }
+# }
+# webhooks:
+# - https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=dummy_key
+#
+# dingtalk:
+# default:
+# is-default: true
+# text-template: |-
+# {
+# "msgtype": "text",
+# "text": {
+# "content": "Apache SkyWalking Alarm: \n %s."
+# }
+# }
+# webhooks:
+# - url: https://oapi.dingtalk.com/robot/send?access_token=dummy_token
+# secret: dummysecret
+#
+# feishu:
+# default:
+# is-default: true
+# text-template: |-
+# {
+# "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
+#
+# welink:
+# default:
+# is-default: true
+# text-template: "Apache SkyWalking Alarm: \n %s."
+# webhooks:
+# # you may find your own client_id and client_secret in your app, below are dummy, need to change.
+# - client-id: "dummy_client_id"
+# client-secret: dummy_secret_key
+# access-token-url: https://open.welink.huaweicloud.com/api/auth/v2/tickets
+# message-url: https://open.welink.huaweicloud.com/api/welinkim/v1/im-service/chat/group-chat
+# # if you send to multi group at a time, separate group_ids with commas, e.g. "123xx","456xx"
+# group-ids: "dummy_group_id"
+# # make a name you like for the robot, it will display in group
+# robot-name: robot
diff --git a/test/e2e-v2/cases/alarm/alarm-settings.yml b/test/e2e-v2/cases/alarm/alarm-settings.yml
index f765d408de..58843ac9d9 100755
--- a/test/e2e-v2/cases/alarm/alarm-settings.yml
+++ b/test/e2e-v2/cases/alarm/alarm-settings.yml
@@ -27,6 +27,8 @@ rules:
tags:
level: WARNING
receivers: lisi
+ hooks:
+ - webhook.custom
# service sla > 1%
service_sla_rule:
metrics-name: service_sla
@@ -45,5 +47,12 @@ composite-rules:
level: CRITICAL
receivers: zhangsan
-webhooks:
- - http://provider:9090/alarm/receive
+hooks:
+ webhook:
+ default:
+ is-default: true
+ urls:
+ - http://provider:9090/alarm/receive
+ custom:
+ urls:
+ - http://provider:9090/alarm/receive