diff --git a/oap-server/pom.xml b/oap-server/pom.xml
index 2efac8ad9..e77986b66 100644
--- a/oap-server/pom.xml
+++ b/oap-server/pom.xml
@@ -37,6 +37,7 @@
server-library
server-starter
server-query-plugin
+ server-alarm-plugin
diff --git a/oap-server/server-alarm-plugin/pom.xml b/oap-server/server-alarm-plugin/pom.xml
new file mode 100644
index 000000000..7848c6afe
--- /dev/null
+++ b/oap-server/server-alarm-plugin/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+ oap-server
+ org.apache.skywalking
+ 6.0.0-alpha-SNAPSHOT
+
+ 4.0.0
+
+ server-alarm-plugin
+
+
+ org.apache.skywalking
+ server-core
+ 6.0.0-alpha-SNAPSHOT
+ compile
+
+
+
+
+
\ No newline at end of file
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmCore.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmCore.java
new file mode 100644
index 000000000..44375e8b1
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmCore.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import org.joda.time.LocalDateTime;
+import org.joda.time.Minutes;
+
+/**
+ * Alarm core includes metric values in certain time windows based on alarm settings. By using its internal timer
+ * trigger and the alarm rules to decides whether send the alarm to database and webhook(s)
+ *
+ * @author wusheng
+ */
+public class AlarmCore {
+ private Map> runningContext;
+ private LocalDateTime lastExecuteTime;
+
+ AlarmCore(Rules rules) {
+ runningContext = new HashMap<>();
+ rules.getRules().forEach(rule -> {
+ RunningRule runningRule = new RunningRule(rule);
+
+ String indicatorName = rule.getIndicatorName();
+
+ List runningRules = runningContext.get(indicatorName);
+ if (runningRules == null) {
+ runningRules = new ArrayList<>();
+ runningContext.put(indicatorName, runningRules);
+ }
+ runningRules.add(runningRule);
+ });
+ }
+
+ public List findRunningRule(String indicatorName) {
+ return runningContext.get(indicatorName);
+ }
+
+ public void start() {
+ LocalDateTime now = LocalDateTime.now();
+ lastExecuteTime = now;
+ runningContext.values().forEach(ruleList -> ruleList.forEach(runningRule -> runningRule.start(now)));
+ Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() ->
+ runningContext.values().forEach(ruleList -> ruleList.forEach(runningRule -> {
+ LocalDateTime checkTime = LocalDateTime.now();
+ int minutes = Minutes.minutesBetween(checkTime, lastExecuteTime).getMinutes();
+ if (minutes > 0) {
+ runningRule.moveTo(checkTime);
+ /**
+ * At least, run 15 seconds in 1 min, alarm check should run.
+ */
+ if (checkTime.getSecondOfMinute() > 15) {
+ runningRule.check();
+ // Set the last execute time, and make sure the second is `00`, such as: 18:30:00
+ lastExecuteTime = checkTime.minusSeconds(checkTime.getSecondOfMinute());
+ runningRule.check();
+ }
+ }
+ })), 10, 10, TimeUnit.SECONDS);
+ }
+}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmModuleProvider.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmModuleProvider.java
new file mode 100644
index 000000000..b7533bce2
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmModuleProvider.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import java.io.FileNotFoundException;
+import java.io.Reader;
+import org.apache.skywalking.oap.server.core.alarm.AlarmModule;
+import org.apache.skywalking.oap.server.core.alarm.IndicatorNotify;
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
+import org.apache.skywalking.oap.server.library.module.ModuleDefine;
+import org.apache.skywalking.oap.server.library.module.ModuleProvider;
+import org.apache.skywalking.oap.server.library.module.ModuleStartException;
+import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
+import org.apache.skywalking.oap.server.library.util.ResourceUtils;
+
+public class AlarmModuleProvider extends ModuleProvider {
+ @Override public String name() {
+ return "default";
+ }
+
+ @Override public Class extends ModuleDefine> module() {
+ return AlarmModule.class;
+ }
+
+ @Override public ModuleConfig createConfigBeanIfAbsent() {
+ return new AlarmSettings();
+ }
+
+ @Override public void prepare() throws ServiceNotProvidedException, ModuleStartException {
+
+ }
+
+ @Override public void start() throws ServiceNotProvidedException, ModuleStartException {
+ Reader applicationReader;
+ try {
+ applicationReader = ResourceUtils.read("alarm-settings.yml");
+ } catch (FileNotFoundException e) {
+ throw new ModuleStartException("can't load alarm-settings.yml",e);
+ }
+ RulesReader reader = new RulesReader(applicationReader);
+ Rules rules = reader.readRules();
+ this.registerServiceImplementation(IndicatorNotify.class, new NotifyHandler(rules));
+ }
+
+ @Override public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
+
+ }
+
+ @Override public String[] requiredModules() {
+ return new String[0];
+ }
+}
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
new file mode 100644
index 000000000..9de545929
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRule.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author wusheng
+ */
+@Setter(AccessLevel.PUBLIC)
+@Getter(AccessLevel.PUBLIC)
+public class AlarmRule {
+ private String alarmRuleName;
+
+ private String indicatorName;
+ private String threshold;
+ private String op;
+ private int period;
+ private int count;
+ private int silencePeriod;
+}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmSettings.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmSettings.java
new file mode 100644
index 000000000..63a5df311
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmSettings.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
+
+public class AlarmSettings extends ModuleConfig {
+}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/IndicatorValueType.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/IndicatorValueType.java
new file mode 100644
index 000000000..51b7003f0
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/IndicatorValueType.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+public enum IndicatorValueType {
+ LONG, INT, DOUBLE
+}
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
new file mode 100644
index 000000000..9386a9019
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/NotifyHandler.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import java.util.List;
+import org.apache.skywalking.oap.server.core.alarm.AlarmCallback;
+import org.apache.skywalking.oap.server.core.alarm.IndicatorNotify;
+import org.apache.skywalking.oap.server.core.alarm.MetaInAlarm;
+import org.apache.skywalking.oap.server.core.analysis.indicator.Indicator;
+
+public class NotifyHandler implements IndicatorNotify {
+ private final AlarmCore core;
+ private final Rules rules;
+ private List allCallbacks;
+
+ public NotifyHandler(Rules rules) {
+ this.rules = rules;
+ core = new AlarmCore(rules);
+ core.start();
+ }
+
+ @Override public void notify(MetaInAlarm meta, Indicator indicator) {
+ switch (meta.getScope()) {
+ case Service:
+ break;
+ default:
+ return;
+ }
+ List runningRules = core.findRunningRule(meta.getIndicatorName());
+ if (runningRules == null) {
+ return;
+ }
+
+ runningRules.forEach(rule -> rule.in(meta, indicator));
+ }
+
+ @Override
+ public void init(AlarmCallback... callbacks) {
+ for (AlarmCallback callback : callbacks) {
+ allCallbacks.add(callback);
+ }
+ allCallbacks.add(new WebhookCallback(rules.getWebhooks()));
+ }
+
+}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/OP.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/OP.java
new file mode 100644
index 000000000..6618538e9
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/OP.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+public enum OP {
+ GREATER, LESS, EQUAL;
+
+ public static OP get(String op) {
+ switch (op) {
+ case ">":
+ return GREATER;
+ case "<":
+ return LESS;
+ case "==":
+ return EQUAL;
+ default:
+ throw new IllegalArgumentException("unknown op, " + op);
+ }
+ }
+}
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
new file mode 100644
index 000000000..bfbced09b
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Rules.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import java.util.List;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter(AccessLevel.PUBLIC)
+@Getter(AccessLevel.PUBLIC)
+public class Rules {
+ private List rules;
+ private List webhooks;
+}
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
new file mode 100644
index 000000000..08763be95
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RulesReader.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Rule Reader parses the given `alarm-settings.yml` config file, to the target {@link Rules}.
+ *
+ * @author wusheng
+ */
+public class RulesReader {
+ private Map yamlData;
+
+ public RulesReader(InputStream inputStream) {
+ Yaml yaml = new Yaml();
+ yamlData = yaml.loadAs(inputStream, Map.class);
+ }
+
+ public RulesReader(Reader io) {
+ Yaml yaml = new Yaml();
+ yamlData = yaml.loadAs(io, Map.class);
+ }
+
+ public Rules readRules() {
+ Rules rules = new Rules();
+
+ Map rulesData = (Map)yamlData.get("rules");
+ if (rulesData != null) {
+ rules.setRules(new ArrayList<>());
+ rulesData.forEach((k, v) -> {
+ if (((String)k).endsWith("_rule")) {
+ AlarmRule alarmRule = new AlarmRule();
+ alarmRule.setAlarmRuleName((String)k);
+ Map settings = (Map)v;
+ Object indicatorName = settings.get("indicator-name");
+ if (indicatorName == null) {
+ throw new IllegalArgumentException("indicator-name can't be null");
+ }
+ alarmRule.setIndicatorName((String)indicatorName);
+ alarmRule.setThreshold(settings.get("threshold").toString());
+ alarmRule.setOp((String)settings.get("op"));
+ alarmRule.setPeriod((Integer)settings.getOrDefault("period", 1));
+ alarmRule.setCount((Integer)settings.getOrDefault("count", 1));
+ alarmRule.setSilencePeriod((Integer)settings.getOrDefault("silence-period", alarmRule.getPeriod()));
+
+ rules.getRules().add(alarmRule);
+ }
+ });
+ }
+ List webhooks = (List)yamlData.get("webhooks");
+ if (webhooks != null) {
+ rules.setWebhooks(new ArrayList<>());
+ webhooks.forEach(url -> {
+ rules.getWebhooks().add((String)url);
+ });
+ }
+ return rules;
+ }
+}
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
new file mode 100644
index 000000000..03f37d479
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/RunningRule.java
@@ -0,0 +1,327 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import java.util.LinkedList;
+import java.util.concurrent.locks.ReentrantLock;
+import org.apache.skywalking.oap.server.core.alarm.MetaInAlarm;
+import org.apache.skywalking.oap.server.core.analysis.indicator.DoubleValueHolder;
+import org.apache.skywalking.oap.server.core.analysis.indicator.Indicator;
+import org.apache.skywalking.oap.server.core.analysis.indicator.IntValueHolder;
+import org.apache.skywalking.oap.server.core.analysis.indicator.LongValueHolder;
+import org.apache.skywalking.oap.server.core.source.Scope;
+import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
+import org.apache.skywalking.oap.server.core.storage.annotation.StorageEntityAnnotationUtils;
+import org.joda.time.LocalDateTime;
+import org.joda.time.Minutes;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * RunningRule represents each rule in running status.
+ * Based on the {@link AlarmRule} definition,
+ *
+ *
+ * @author wusheng
+ */
+public class RunningRule {
+ private static final Logger logger = LoggerFactory.getLogger(RunningRule.class);
+ private static DateTimeFormatter TIME_BUCKET_FORMATTER = DateTimeFormat.forPattern("yyyyMMddHHmm");
+
+ private String ruleName;
+ private final Threshold threshold;
+ private final OP op;
+ private final int countThreshold;
+ private final int silencePeriod;
+ private int counter;
+ private int silenceCountdown;
+ private Window window;
+ private volatile boolean isStarted = false;
+ private IndicatorValueType valueType;
+ private Scope targetScope;
+
+ public RunningRule(AlarmRule alarmRule) {
+ this.ruleName = alarmRule.getAlarmRuleName();
+
+ // Init the empty window for alarming rule.
+ window = new Window(alarmRule.getPeriod());
+
+ threshold = new Threshold(alarmRule.getAlarmRuleName(), alarmRule.getThreshold());
+ op = OP.get(alarmRule.getOp());
+
+ this.countThreshold = alarmRule.getCount();
+ this.silencePeriod = alarmRule.getSilencePeriod();
+ // -1 means silence countdown is not running.
+ silenceCountdown = -1;
+ }
+
+ /**
+ * Receive indicator result from persistence, after it is saved into storage.
+ * In alarm, only minute dimensionality indicators are expected to process.
+ *
+ * @param indicator
+ */
+ public void in(MetaInAlarm meta, Indicator indicator) {
+ if (!isStarted) {
+ return;
+ }
+
+ if (valueType == null) {
+ if (indicator instanceof LongValueHolder) {
+ valueType = IndicatorValueType.LONG;
+ threshold.setType(IndicatorValueType.LONG);
+ } else if (indicator instanceof IntValueHolder) {
+ valueType = IndicatorValueType.INT;
+ threshold.setType(IndicatorValueType.INT);
+ } else if (indicator instanceof DoubleValueHolder) {
+ valueType = IndicatorValueType.DOUBLE;
+ threshold.setType(IndicatorValueType.DOUBLE);
+ }
+ targetScope = meta.getScope();
+ }
+
+ if (valueType != null) {
+ window.add(indicator);
+ }
+ }
+
+ /**
+ * Start this rule in running mode.
+ * @param current
+ */
+ public void start(LocalDateTime current) {
+ window.start(current);
+ isStarted = true;
+ }
+
+ /**
+ * Move the buffer window to give time.
+ * @param targetTime of moving target
+ */
+ public void moveTo(LocalDateTime targetTime) {
+ window.moveTo(targetTime);
+ }
+
+ /**
+ * Check the conditions, decide to whether trigger alarm.
+ */
+ public void check() {
+ boolean isMatched = window.isMatch();
+
+ /**
+ * When
+ * 1. Metric value threshold triggers alarm by rule
+ * 2. Counter reaches the count threshold;
+ * 3. Isn't in silence stage, judged by SilenceCountdown(!=0).
+ */
+ if (isMatched) {
+ counter++;
+ if (counter >= countThreshold && silenceCountdown < 1) {
+ triggerAlarm();
+ }
+ } else {
+ silenceCountdown--;
+ if (counter > 0) {
+ counter--;
+ }
+ }
+ }
+
+ /**
+ * Trigger alarm callbacks.
+ */
+ private void triggerAlarm() {
+ silenceCountdown = silencePeriod;
+ }
+
+ /**
+ * A indicator window, based on {@link AlarmRule#period}.
+ * This window slides with time, just keeps the recent N(period) buckets.
+ *
+ * @author wusheng
+ */
+ public class Window {
+ private LocalDateTime endTime;
+ private int period;
+
+ private LinkedList values;
+ private ReentrantLock lock = new ReentrantLock();
+
+ public Window(int period) {
+ this.period = period;
+ init();
+ }
+
+ public void start(LocalDateTime current) {
+ this.endTime = current;
+ }
+
+ public void moveTo(LocalDateTime current) {
+ lock.lock();
+ try {
+ int minutes = Minutes.minutesBetween(endTime, current).getMinutes();
+ if (minutes <= 0) {
+ return;
+ }
+ if (minutes > values.size()) {
+ // re-init
+ init();
+ } else {
+ for (int i = 0; i < minutes; i++) {
+ values.removeFirst();
+ values.addLast(null);
+ }
+ }
+ endTime = current;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public void add(Indicator indicator) {
+ long bucket = indicator.getTimeBucket();
+
+ LocalDateTime timebucket = TIME_BUCKET_FORMATTER.parseLocalDateTime(bucket + "");
+
+ int minutes = Minutes.minutesBetween(endTime, timebucket).getMinutes();
+ if (minutes == -1) {
+ this.moveTo(timebucket);
+
+ }
+
+ lock.lock();
+ try {
+ minutes = Minutes.minutesBetween(endTime, timebucket).getMinutes();
+ if (minutes < 0) {
+ // At any moment, should NOT be here
+ // Add this code just because of my obsession :P
+ return;
+ }
+
+ if (minutes >= values.size()) {
+ // too old data
+ // also should happen, but maybe if agent/probe mechanism time is not right.
+ return;
+ }
+
+ int idx = minutes - 1;
+ values.set(idx, indicator);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public boolean isMatch() {
+ int matchCount = 0;
+ for (Indicator indicator : values) {
+ if (indicator == null) {
+ continue;
+ }
+
+ switch (valueType) {
+ case LONG:
+ long lvalue = ((LongValueHolder)indicator).getValue();
+ long lexpected = RunningRule.this.threshold.getLongThreshold();
+ switch (op) {
+ case GREATER:
+ if (lvalue > lexpected)
+ matchCount++;
+ break;
+ case LESS:
+ if (lvalue < lexpected)
+ matchCount++;
+ break;
+ case EQUAL:
+ if (lvalue == lexpected)
+ matchCount++;
+ break;
+ }
+ break;
+ case INT:
+ int ivalue = ((IntValueHolder)indicator).getValue();
+ int iexpected = RunningRule.this.threshold.getIntThreshold();
+ switch (op) {
+ case LESS:
+ if (ivalue < iexpected)
+ matchCount++;
+ break;
+ case GREATER:
+ if (ivalue > iexpected)
+ matchCount++;
+ break;
+ case EQUAL:
+ if (ivalue == iexpected)
+ matchCount++;
+ break;
+ }
+ break;
+ case DOUBLE:
+ double dvalue = ((DoubleValueHolder)indicator).getValue();
+ double dexpected = RunningRule.this.threshold.getDoubleThreadhold();
+ switch (op) {
+ case EQUAL:
+ // NOTICE: double equal is not reliable in Java,
+ // match result is not predictable
+ if (dvalue == dexpected)
+ matchCount++;
+ break;
+ case GREATER:
+ if (dvalue > dexpected)
+ matchCount++;
+ break;
+ case LESS:
+ if (dvalue < dexpected)
+ matchCount++;
+ break;
+ }
+ break;
+ }
+ }
+
+ // Reach the threshold in current bucket.
+ return matchCount >= countThreshold;
+ }
+
+ private void init() {
+ values = new LinkedList();
+ for (int i = 0; i < period; i++) {
+ values.add(null);
+ }
+ }
+
+ private Indicator clone(Indicator indicator) {
+ Class extends StorageBuilder> builder = StorageEntityAnnotationUtils.getBuilder(indicator.getClass());
+ try {
+ StorageBuilder indicatorBuilder = builder.newInstance();
+ return (Indicator)indicatorBuilder.map2Data(indicatorBuilder.data2Map(indicator));
+ } catch (InstantiationException e) {
+ logger.error("clone indicator error, {}", indicator.getClass());
+ return null;
+ } catch (IllegalAccessException e) {
+ logger.error("clone indicator error, {}", indicator.getClass());
+ return null;
+ } catch (Exception e) {
+ logger.error("clone indicator error, {}", indicator.getClass());
+ return null;
+ }
+ }
+ }
+}
diff --git a/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Threshold.java b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Threshold.java
new file mode 100644
index 000000000..c97f0e4a9
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/Threshold.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author wusheng
+ */
+public class Threshold {
+ private static final Logger logger = LoggerFactory.getLogger(Threshold.class);
+
+ private String alarmRuleName;
+ private final String threshold;
+ private int intThreshold;
+ private double doubleThreadhold;
+ private long longThreshold;
+
+ public Threshold(String alarmRuleName, String threshold) {
+ this.alarmRuleName = alarmRuleName;
+ this.threshold = threshold;
+ }
+
+ public int getIntThreshold() {
+ return intThreshold;
+ }
+
+ public double getDoubleThreadhold() {
+ return doubleThreadhold;
+ }
+
+ public long getLongThreshold() {
+ return longThreshold;
+ }
+
+ public void setType(IndicatorValueType type) {
+ try {
+ switch (type) {
+ case INT:
+ intThreshold = Integer.parseInt(threshold);
+ break;
+ case LONG:
+ longThreshold = Long.parseLong(threshold);
+ break;
+ case DOUBLE:
+ doubleThreadhold = Double.parseDouble(threshold);
+ break;
+ }
+ } catch (NumberFormatException e) {
+ logger.warn("Alarm rule {} threshold doesn't match the indicator type, expected type: {}", alarmRuleName, type);
+ }
+ }
+}
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/WebhookCallback.java
new file mode 100644
index 000000000..4ec9a40e2
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/java/org/apache/skywalking/oap/server/core/alarm/provider/WebhookCallback.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import java.util.List;
+import org.apache.skywalking.oap.server.core.alarm.AlarmCallback;
+import org.apache.skywalking.oap.server.core.alarm.AlarmMessage;
+
+/**
+ * Use SkyWalking alarm webhook API call a remote endpoints.
+ */
+public class WebhookCallback implements AlarmCallback {
+ private List remoteEndpoints;
+
+ public WebhookCallback(List remoteEndpoints) {
+ this.remoteEndpoints = remoteEndpoints;
+ }
+
+ @Override public void doAlarm(AlarmMessage alarmMessage) {
+
+ }
+}
diff --git a/oap-server/server-alarm-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/oap-server/server-alarm-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
new file mode 100644
index 000000000..b201e1292
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+org.apache.skywalking.oap.server.core.alarm.provider.AlarmModuleProvider
\ No newline at end of file
diff --git a/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRuleInitTest.java b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRuleInitTest.java
new file mode 100644
index 000000000..ae65478e1
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/test/java/org/apache/skywalking/oap/server/core/alarm/provider/AlarmRuleInitTest.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm.provider;
+
+import java.util.List;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AlarmRuleInitTest {
+ @Test
+ public void testInit() {
+ RulesReader reader = new RulesReader(this.getClass().getClassLoader()
+ .getResourceAsStream("alarm-settings.yml"));
+ Rules rules = reader.readRules();
+
+ List ruleList = rules.getRules();
+ Assert.assertEquals(2, ruleList.size());
+ Assert.assertEquals("85", ruleList.get(1).getThreshold());
+ Assert.assertEquals("endpoint_percent_rule", ruleList.get(0).getAlarmRuleName());
+
+ List rulesWebhooks = rules.getWebhooks();
+ Assert.assertEquals(2, rulesWebhooks.size());
+ Assert.assertEquals("http://127.0.0.1/go-wechat/", rulesWebhooks.get(1));
+ }
+}
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
new file mode 100644
index 000000000..5ed53d1e5
--- /dev/null
+++ b/oap-server/server-alarm-plugin/src/test/resources/alarm-settings.yml
@@ -0,0 +1,40 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+rules:
+ # Rule unique name, must be ended with `_rule`.
+ endpoint_percent_rule:
+ # Indicator value need to be long, double or int
+ indicator-name: endpoint_percent
+ threshold: 75
+ op: <
+ # The length of time to evaluate the metric
+ period: 10
+ # How many times after the metric match the condition, will trigger alarm
+ count: 3
+ # How many times of checks, the alarm keeps silence after alarm triggered, default as same as period.
+ silence-period: 10
+ service_percent_rule:
+ indicator-name: service_percent
+ threshold: 85
+ op: <
+ period: 10
+ count: 4
+
+webhooks:
+ - http://127.0.0.1/notify/
+ - http://127.0.0.1/go-wechat/
+
diff --git a/oap-server/server-core/pom.xml b/oap-server/server-core/pom.xml
index 5ffad8da7..32f1a6074 100644
--- a/oap-server/server-core/pom.xml
+++ b/oap-server/server-core/pom.xml
@@ -31,6 +31,10 @@
jar
+
+ org.yaml
+ snakeyaml
+
org.apache.skywalking
library-module
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
index 9605e2b89..d01de7d4a 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
@@ -19,7 +19,6 @@
package org.apache.skywalking.oap.server.core;
import java.io.IOException;
-import org.apache.skywalking.oap.server.core.alarm.IndicatorAlarmListener;
import org.apache.skywalking.oap.server.core.analysis.indicator.annotation.IndicatorTypeListener;
import org.apache.skywalking.oap.server.core.annotation.AnnotationScan;
import org.apache.skywalking.oap.server.core.cache.*;
@@ -109,7 +108,6 @@ public class CoreModuleProvider extends ModuleProvider {
annotationScan.registerListener(streamAnnotationListener);
annotationScan.registerListener(new IndicatorTypeListener(getManager()));
annotationScan.registerListener(new InventoryTypeListener(getManager()));
- annotationScan.registerListener(IndicatorAlarmListener.INSTANCE);
this.remoteClientManager = new RemoteClientManager(getManager());
this.registerServiceImplementation(RemoteClientManager.class, remoteClientManager);
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorAlarmDataType.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java
similarity index 79%
rename from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorAlarmDataType.java
rename to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java
index 96c3ee753..80a619319 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorAlarmDataType.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmCallback.java
@@ -19,11 +19,11 @@
package org.apache.skywalking.oap.server.core.alarm;
/**
- * Indicator Alarm data type represents the indicator result data time, based on this, the core drives the {@link
- * IndicatorNotify} to notify the alarm implementor.
+ * Alarm call back will be called by alarm implementor,
+ * after it decided alarm should be sent.
*
* @author wusheng
*/
-public enum IndicatorAlarmDataType {
- LONG, INT, DOUBLE
+public interface AlarmCallback {
+ void doAlarm(AlarmMessage alarmMessage);
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmEntrance.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmEntrance.java
new file mode 100644
index 000000000..69c83df9d
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmEntrance.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm;
+
+import java.util.concurrent.locks.ReentrantLock;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.indicator.Indicator;
+import org.apache.skywalking.oap.server.core.cache.ServiceInventoryCache;
+import org.apache.skywalking.oap.server.core.register.ServiceInventory;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+
+/**
+ * @author wusheng
+ */
+public class AlarmEntrance {
+ private ModuleManager moduleManager;
+ private ServiceInventoryCache serviceInventoryCache;
+ private IndicatorNotify indicatorNotify;
+ private ReentrantLock initLock;
+
+ public AlarmEntrance(ModuleManager moduleManager) {
+ this.moduleManager = moduleManager;
+ this.initLock = new ReentrantLock();
+ }
+
+ public void forward(Indicator indicator) {
+ if (!moduleManager.has(AlarmModule.NAME)) {
+ return;
+ }
+
+ init();
+
+ AlarmMeta alarmMeta = ((AlarmSupported)indicator).getAlarmMeta();
+
+ MetaInAlarm metaInAlarm = null;
+ switch (alarmMeta.getScope()) {
+ case Service:
+ int serviceId = alarmMeta.getIds().getID(0);
+ ServiceInventory serviceInventory = serviceInventoryCache.get(serviceId);
+ ServiceMetaInAlarm serviceMetaInAlarm = new ServiceMetaInAlarm();
+ serviceMetaInAlarm.setIndicatorName(alarmMeta.getIndicatorName());
+ serviceMetaInAlarm.setId(serviceId);
+ serviceMetaInAlarm.setName(serviceInventory.getName());
+ metaInAlarm = serviceMetaInAlarm;
+ break;
+ default:
+ return;
+ }
+
+ indicatorNotify.notify(metaInAlarm, indicator);
+ }
+
+ private void init() {
+ if (serviceInventoryCache == null) {
+ initLock.lock();
+ try {
+ if (serviceInventoryCache == null) {
+ serviceInventoryCache = moduleManager.find(CoreModule.NAME).getService(ServiceInventoryCache.class);
+ indicatorNotify = moduleManager.find(AlarmModule.NAME).getService(IndicatorNotify.class);
+ indicatorNotify.init(new AlarmStandardPersistence());
+ }
+ } finally {
+ initLock.unlock();
+ }
+ }
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/NotifyTarget.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmMessage.java
similarity index 84%
rename from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/NotifyTarget.java
rename to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmMessage.java
index 4919d50c9..f7cf35511 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/NotifyTarget.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmMessage.java
@@ -18,13 +18,16 @@
package org.apache.skywalking.oap.server.core.alarm;
+import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
/**
+ * Alarm message represents the details of each alarm.
+ *
* @author wusheng
*/
-public class NotifyTarget {
- @Setter @Getter private String indicatorName;
- @Setter @Getter private IndicatorAlarmDataType dataType;
+@Setter(AccessLevel.PUBLIC)
+@Getter(AccessLevel.PUBLIC)
+public class AlarmMessage {
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmStandardPersistence.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmStandardPersistence.java
new file mode 100644
index 000000000..4a695ee4c
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/AlarmStandardPersistence.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm;
+
+/**
+ * Save the alarm info into storage for UI query.
+ */
+public class AlarmStandardPersistence implements AlarmCallback {
+ @Override public void doAlarm(AlarmMessage alarmMessage) {
+ //TODO Peng-yongsheng
+ /**
+ * This is just a callback entrance.
+ */
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorAlarmListener.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorAlarmListener.java
deleted file mode 100644
index 3c496e1f5..000000000
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorAlarmListener.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.oap.server.core.alarm;
-
-import java.lang.annotation.Annotation;
-import java.util.HashMap;
-import org.apache.skywalking.oap.server.core.analysis.indicator.DoubleValueHolder;
-import org.apache.skywalking.oap.server.core.analysis.indicator.IntValueHolder;
-import org.apache.skywalking.oap.server.core.analysis.indicator.LongValueHolder;
-import org.apache.skywalking.oap.server.core.analysis.indicator.annotation.IndicatorType;
-import org.apache.skywalking.oap.server.core.annotation.AnnotationListener;
-import org.apache.skywalking.oap.server.core.storage.annotation.StorageEntity;
-
-/**
- * Indicator Alarm listener does the pre-analysis of each indicator implementation, when alarm happens, it drives
- * notification based on indicator value data type.
- *
- * @author wusheng
- */
-public class IndicatorAlarmListener implements AnnotationListener {
- public static final IndicatorAlarmListener INSTANCE = new IndicatorAlarmListener();
-
- private final HashMap notifyTarget;
-
- IndicatorAlarmListener() {
- notifyTarget = new HashMap<>();
- }
-
- @Override public Class extends Annotation> annotation() {
- return IndicatorType.class;
- }
-
- @Override public void notify(Class aClass) {
- StorageEntity storageEntityAnnotation = (StorageEntity)aClass.getAnnotation(StorageEntity.class);
- if (storageEntityAnnotation == null) {
- return;
- }
- String indicatorName = storageEntityAnnotation.name();
-
- NotifyTarget target = new NotifyTarget();
- target.setIndicatorName(indicatorName);
- if (DoubleValueHolder.class.isAssignableFrom(aClass)) {
- target.setDataType(IndicatorAlarmDataType.DOUBLE);
- } else if (LongValueHolder.class.isAssignableFrom(aClass)) {
- target.setDataType(IndicatorAlarmDataType.LONG);
- } else if (IntValueHolder.class.isAssignableFrom(aClass)) {
- target.setDataType(IndicatorAlarmDataType.INT);
- } else {
- // If don't declare as any value holder, this is not an alarm candidate value.
- return;
- }
-
- notifyTarget.put(aClass, target);
- }
-
- public NotifyTarget getTarget(Class indicatorClass) {
- return notifyTarget.get(indicatorClass);
- }
-}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorNotify.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorNotify.java
index a281f0c17..d146ab2bb 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorNotify.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/IndicatorNotify.java
@@ -18,6 +18,7 @@
package org.apache.skywalking.oap.server.core.alarm;
+import org.apache.skywalking.oap.server.core.analysis.indicator.Indicator;
import org.apache.skywalking.oap.server.library.module.Service;
/**
@@ -31,9 +32,7 @@ import org.apache.skywalking.oap.server.library.module.Service;
* @author wusheng
*/
public interface IndicatorNotify extends Service {
- void notify(String indicatorName, double value);
+ void notify(MetaInAlarm indicatorName, Indicator indicator);
- void notify(String indicatorName, int value);
-
- void notify(String indicatorName, long value);
+ void init(AlarmCallback... callbacks);
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/MetaInAlarm.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/MetaInAlarm.java
new file mode 100644
index 000000000..e45368c75
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/MetaInAlarm.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm;
+
+import org.apache.skywalking.oap.server.core.source.Scope;
+
+public interface MetaInAlarm {
+ Scope getScope();
+
+ String getName();
+
+ String getIndicatorName();
+
+ /**
+ * In most scopes, there is only id0, as primary id. Such as Service, Endpoint.
+ * But in relation, the ID includes two, actually.
+ * Such as ServiceRelation,
+ * id0 represents the source service id
+ *
+ * @return the primary id.
+ */
+ int getId0();
+
+ /**
+ * Only exist in multiple IDs case,
+ * Such as ServiceRelation,
+ * id1 represents the dest service id
+ *
+ * @return
+ */
+ int getId1();
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/ServiceMetaInAlarm.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/ServiceMetaInAlarm.java
new file mode 100644
index 000000000..4040fe4c4
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/alarm/ServiceMetaInAlarm.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.alarm;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.source.Scope;
+
+@Getter(AccessLevel.PUBLIC)
+@Setter(AccessLevel.PUBLIC)
+public class ServiceMetaInAlarm implements MetaInAlarm {
+ private String indicatorName;
+
+ private int id;
+ private String name;
+ private String[] tags;
+ private String[] properties;
+
+ @Override public Scope getScope() {
+ return Scope.Service;
+ }
+
+ @Override public int getId0() {
+ return id;
+ }
+
+ @Override public int getId1() {
+ return 0;
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/AlarmNotifyWorker.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/AlarmNotifyWorker.java
index 9400b7b47..2b63572b9 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/AlarmNotifyWorker.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/AlarmNotifyWorker.java
@@ -18,8 +18,11 @@
package org.apache.skywalking.oap.server.core.analysis.worker;
+import org.apache.skywalking.oap.server.core.alarm.AlarmEntrance;
+import org.apache.skywalking.oap.server.core.alarm.AlarmSupported;
import org.apache.skywalking.oap.server.core.analysis.indicator.Indicator;
import org.apache.skywalking.oap.server.core.worker.AbstractWorker;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
/**
* Alarm notify worker, do a simple route to alarm core after the aggregation persistence.
@@ -27,11 +30,18 @@ import org.apache.skywalking.oap.server.core.worker.AbstractWorker;
* @author wusheng
*/
public class AlarmNotifyWorker extends AbstractWorker {
- public AlarmNotifyWorker(int workerId) {
+ private ModuleManager moduleManager;
+ private AlarmEntrance entrance;
+
+ public AlarmNotifyWorker(int workerId, ModuleManager moduleManager) {
super(workerId);
+ this.moduleManager = moduleManager;
+ this.entrance = new AlarmEntrance(moduleManager);
}
@Override public void in(Indicator indicator) {
-
+ if (indicator instanceof AlarmSupported) {
+ entrance.forward(indicator);
+ }
}
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/IndicatorProcess.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/IndicatorProcess.java
index 62c335fae..12cfce276 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/IndicatorProcess.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/worker/IndicatorProcess.java
@@ -50,7 +50,7 @@ public enum IndicatorProcess {
throw new UnexpectedException("");
}
- AlarmNotifyWorker alarmNotifyWorker = new AlarmNotifyWorker(WorkerIdGenerator.INSTANCES.generate());
+ AlarmNotifyWorker alarmNotifyWorker = new AlarmNotifyWorker(WorkerIdGenerator.INSTANCES.generate(), moduleManager);
WorkerInstances.INSTANCES.put(alarmNotifyWorker.getWorkerId(), alarmNotifyWorker);
IndicatorPersistentWorker persistentWorker = new IndicatorPersistentWorker(WorkerIdGenerator.INSTANCES.generate(), modelName,
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/alarm/IndicatorAlarmListenerTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/alarm/IndicatorAlarmListenerTest.java
deleted file mode 100644
index f1ce098ae..000000000
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/alarm/IndicatorAlarmListenerTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.oap.server.core.alarm;
-
-import java.util.Map;
-import org.apache.skywalking.oap.server.core.analysis.indicator.LongValueHolder;
-import org.apache.skywalking.oap.server.core.analysis.indicator.annotation.IndicatorType;
-import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
-import org.apache.skywalking.oap.server.core.storage.StorageData;
-import org.apache.skywalking.oap.server.core.storage.annotation.StorageEntity;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class IndicatorAlarmListenerTest {
- @Test
- public void testIndicatorPreAnalysis() {
- IndicatorAlarmListener listener = new IndicatorAlarmListener();
- listener.notify(ATestClass.class);
- listener.notify(UnCompleteIndicator.class);
- listener.notify(MockIndicator.class);
-
- Assert.assertNull(listener.getTarget(ATestClass.class));
- Assert.assertNull(listener.getTarget(UnCompleteIndicator.class));
- Assert.assertNotNull(listener.getTarget(MockIndicator.class));
- }
-
- public class ATestClass {
-
- }
-
- @IndicatorType
- public class UnCompleteIndicator {
-
- }
-
- @IndicatorType
- @StorageEntity(name = "mock_indicator", builder = MockBuilder.class)
- public class MockIndicator implements LongValueHolder {
-
- @Override public long getValue() {
- return 0;
- }
- }
-
- public class MockBuilder implements StorageBuilder {
-
- @Override public StorageData map2Data(Map dbMap) {
- return null;
- }
-
- @Override public Map data2Map(StorageData storageData) {
- return null;
- }
- }
-}
diff --git a/oap-server/server-starter/pom.xml b/oap-server/server-starter/pom.xml
index 9d0ddd0d4..6e9a95c06 100644
--- a/oap-server/server-starter/pom.xml
+++ b/oap-server/server-starter/pom.xml
@@ -31,10 +31,6 @@
jar
-
- org.yaml
- snakeyaml
-
org.apache.skywalking
server-core
@@ -101,6 +97,13 @@
${project.version}
+
+
+
+ org.apache.skywalking
+ server-alarm-plugin
+ ${project.version}
+
skywalking-oap