Skip to content

Commit

Permalink
[feature] Support custom refresh intervals for each group of metrics (#…
Browse files Browse the repository at this point in the history
…2718)

Co-authored-by: tomsun28 <[email protected]>
Co-authored-by: shown <[email protected]>
Co-authored-by: aias00 <[email protected]>
Co-authored-by: crossoverJie <[email protected]>
  • Loading branch information
5 people authored Nov 9, 2024
1 parent dca3e35 commit caf13c0
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@

package org.apache.hertzbeat.collector.dispatch.timer;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.collector.dispatch.entrance.internal.CollectResponseEventListener;
import org.apache.hertzbeat.common.entity.job.Job;
import org.apache.hertzbeat.common.entity.job.Metrics;
import org.apache.hertzbeat.common.entity.message.CollectRep;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* job timer dispatcher
*/
Expand Down Expand Up @@ -83,7 +84,11 @@ public void addJob(Job addJob, CollectResponseEventListener eventListener) {
Timeout timeout = wheelTimer.newTimeout(timerJob, addJob.getInterval(), TimeUnit.SECONDS);
currentCyclicTaskMap.put(addJob.getId(), timeout);
} else {
Timeout timeout = wheelTimer.newTimeout(timerJob, 0, TimeUnit.SECONDS);
for (Metrics metric : addJob.getMetrics()) {
metric.setInterval(0L);
}
addJob.setIntervals(new LinkedList<>(List.of(0L)));
Timeout timeout = wheelTimer.newTimeout(timerJob, addJob.getInterval(), TimeUnit.SECONDS);
currentTempTaskMap.put(addJob.getId(), timeout);
eventListeners.put(addJob.getId(), eventListener);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ private void initJobMetrics(Job job) {
metricsTmp.add(metric);
}
job.setMetrics(metricsTmp);
job.initIntervals();
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.common.entity.message.CollectRep;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.springframework.util.CollectionUtils;

/**
* Collect task details
Expand Down Expand Up @@ -94,9 +95,13 @@ public class Job {
*/
private long timestamp;
/**
* Task collection time interval (unit: second) eg: 30,60,600
* Default task collection time interval (unit: second) eg: 30,60,600
*/
private long interval = 600L;
private long defaultInterval = 600L;
/**
* Refresh time list for one cycle of the job
*/
private LinkedList<Long> intervals;
/**
* Whether it is a recurring periodic task true is yes, false is no
*/
Expand Down Expand Up @@ -151,17 +156,19 @@ public class Job {
*/
public synchronized void constructPriorMetrics() {
Map<Byte, List<Metrics>> map = metrics.stream()
.peek(metric -> {
// Determine whether to configure aliasFields If not, configure the default
if ((metric.getAliasFields() == null || metric.getAliasFields().isEmpty()) && metric.getFields() != null) {
metric.setAliasFields(metric.getFields().stream().map(Metrics.Field::getField).collect(Collectors.toList()));
}
// Set the default metrics execution priority, if not filled, the default last priority
if (metric.getPriority() == null) {
metric.setPriority(Byte.MAX_VALUE);
}
})
.collect(Collectors.groupingBy(Metrics::getPriority));
.filter(metrics -> (System.currentTimeMillis() >= metrics.getCollectTime() + metrics.getInterval() * 1000))
.peek(metric -> {
metric.setCollectTime(System.currentTimeMillis());
// Determine whether to configure aliasFields If not, configure the default
if ((metric.getAliasFields() == null || metric.getAliasFields().isEmpty()) && metric.getFields() != null) {
metric.setAliasFields(metric.getFields().stream().map(Metrics.Field::getField).collect(Collectors.toList()));
}
// Set the default metrics execution priority, if not filled, the default last priority
if (metric.getPriority() == null) {
metric.setPriority(Byte.MAX_VALUE);
}
})
.collect(Collectors.groupingBy(Metrics::getPriority));
// Construct a linked list of task execution order of the metrics
priorMetrics = new LinkedList<>();
map.values().forEach(metric -> {
Expand Down Expand Up @@ -247,4 +254,81 @@ public Job clone() {
// deep clone
return JsonUtil.fromJson(JsonUtil.toJson(this), getClass());
}

public void initIntervals() {
List<Long> metricsIntervals = new LinkedList<>();
for (Metrics metrics: getMetrics()) {
metrics.setCollectTime(System.currentTimeMillis());
if (metrics.getInterval() <= 0) {
metrics.setInterval(defaultInterval);
}
if (!metricsIntervals.contains(metrics.getInterval())) {
metricsIntervals.add(metrics.getInterval());
}
}
generateMetricsIntervals(metricsIntervals);
}

/**
* The greatest common divisor
*/
public static long gcd(long a, long b) {
while (b != 0) {
long temp = b;
b = a % b;
a = temp;
}
return a;
}

/**
* The least common multiple
*/
public static long lcm(List<Long> array) {
if (array != null) {
long result = array.get(0);
for (int i = 1; i < array.size(); i++) {
result = (result * array.get(i)) / gcd(result, array.get(i));
}
return result;
}
return 0;
}

/**
*
* @param metricsIntervals A unique list composed of intervals for all metrics
* Generate a list of refresh intervals for metric collection
*/
public void generateMetricsIntervals(List<Long> metricsIntervals) {
// 1. To find the least common multiple (LCM) of all metric refresh intervals
long lcm = lcm(metricsIntervals);
List<Long> refreshTimes = new LinkedList<>();
// 2. Calculate all possible refresh intervals in one round
for (long interval : metricsIntervals) {
for (long t = interval; t <= lcm; t += interval) {
if (!refreshTimes.contains(t)) {
refreshTimes.add(t);
}
}
}
// 3. Sort from smallest to largest
Collections.sort(refreshTimes);
// 4. Calculate the refresh interval list for Job's cycle
LinkedList<Long> intervals = new LinkedList<>();
intervals.add(refreshTimes.get(0));
for (int i = 1; i < refreshTimes.size(); i++) {
intervals.add(refreshTimes.get(i) - refreshTimes.get(i - 1));
}
setIntervals(intervals);
}

public long getInterval() {
if (!CollectionUtils.isEmpty(getIntervals())) {
long interval = getIntervals().remove();
getIntervals().add(interval);
return interval;
}
return getDefaultInterval();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ public class Metrics {
* the subsequent metrics tasks will only be scheduled after the availability is collected successfully.
*/
private Byte priority;
/**
* The latest collect time
*/
private long collectTime;
/**
* Customize interval of metrics
* If not set, the collection interval set in the front-end page will be used by default
*/
private long interval;
/**
* Is it visible true or false
* if false, web ui will not see this metrics.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public void collectorGoOnline(String identity, CollectorInfo collectorInfo) {
appDefine.setApp(CommonConstants.PROMETHEUS_APP_PREFIX + monitor.getName());
}
appDefine.setMonitorId(monitor.getId());
appDefine.setInterval(monitor.getIntervals());
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
List<Param> params = paramDao.findParamsByMonitorId(monitor.getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public void run(String... args) throws Exception {
}
appDefine.setId(monitor.getJobId());
appDefine.setMonitorId(monitor.getId());
appDefine.setInterval(monitor.getIntervals());
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
List<Param> params = paramDao.findParamsByMonitorId(monitor.getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public void addMonitor(Monitor monitor, List<Param> params, String collector, Gr
appDefine.setApp(CommonConstants.PROMETHEUS_APP_PREFIX + monitor.getName());
}
appDefine.setMonitorId(monitorId);
appDefine.setInterval(monitor.getIntervals());
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
List<Configmap> configmaps = params.stream().map(param -> {
Expand Down Expand Up @@ -272,7 +272,7 @@ public void addNewMonitorOptionalMetrics(List<String> metrics, Monitor monitor,
List<Metrics> realMetrics = metricsDefine.stream().filter(m -> metrics.contains(m.getName())).collect(Collectors.toList());
appDefine.setMetrics(realMetrics);
appDefine.setMonitorId(monitorId);
appDefine.setInterval(monitor.getIntervals());
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
List<Configmap> configmaps = params.stream().map(param -> {
Expand Down Expand Up @@ -543,7 +543,7 @@ public void modifyMonitor(Monitor monitor, List<Param> params, String collector,
}
appDefine.setId(preMonitor.getJobId());
appDefine.setMonitorId(monitorId);
appDefine.setInterval(monitor.getIntervals());
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
if (params != null) {
Expand Down Expand Up @@ -759,7 +759,7 @@ public void enableManageMonitors(HashSet<Long> ids) {
appDefine.setApp(CommonConstants.PROMETHEUS_APP_PREFIX + monitor.getName());
}
appDefine.setMonitorId(monitor.getId());
appDefine.setInterval(monitor.getIntervals());
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
List<Param> params = paramDao.findParamsByMonitorId(monitor.getId());
Expand Down Expand Up @@ -865,7 +865,7 @@ public void updateAppCollectJob(Job job) {
}
appDefine.setId(monitor.getJobId());
appDefine.setMonitorId(monitor.getId());
appDefine.setInterval(monitor.getIntervals());
appDefine.setDefaultInterval(monitor.getIntervals());
appDefine.setCyclic(true);
appDefine.setTimestamp(System.currentTimeMillis());
List<Param> params = paramDao.findParamsByMonitorId(monitor.getId());
Expand Down
22 changes: 11 additions & 11 deletions home/blog/2023-02-10-new-committer.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,16 @@ From the first `PR` to the present, I have participated in the `hertzbeat` open

**contribute:**

* 1. Realize the monitoring of docker containers.
* 2. Complete the domestic database DM monitoring
* 3. Write a single test for the corresponding business.
* 4. English translation of some annotations.
1. Realize the monitoring of docker containers.
2. Complete the domestic database DM monitoring
3. Write a single test for the corresponding business.
4. English translation of some annotations.

**reward:**

* 1. The technical ability has been further improved.
* 2. Broaden your horizons.
* 3. Learned a lot from the bosses.
1. The technical ability has been further improved.
2. Broaden your horizons.
3. Learned a lot from the bosses.

### 🌻 Thanks to the community partners

Expand All @@ -99,10 +99,10 @@ Thanks to the friends who have helped me or inspired me for free (in no particul

First of all, I am also a newcomer to Novice Village, but I can share some of my experience with you, hoping to help you.

* 1. Don't be too impatient, and calm down to understand the general implementation logic of each module.
* 2. Use different functions and debug to see the underlying implementation principle of each function.
* 3. Slowly try to read the source code and understand it.
* 4. If you encounter a bug, you can directly report it to issues, or you can try to solve it yourself.
1. Don't be too impatient, and calm down to understand the general implementation logic of each module.
2. Use different functions and debug to see the underlying implementation principle of each function.
3. Slowly try to read the source code and understand it.
4. If you encounter a bug, you can directly report it to issues, or you can try to solve it yourself.

## What is Hertz Beat?

Expand Down
6 changes: 6 additions & 0 deletions home/docs/advanced/extend-point.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ sidebar_label: Custom Monitoring

**HertzBeat Dashboard** -> **Monitoring Templates** -> **New Template** -> **Config Monitoring Template Yml** -> **Save and Apply** -> **Add A Monitoring with The New Monitoring Type**

### Custom Monitoring Metrics Refresh Interval

HertzBeat now supports setting different refresh intervals for various groups of monitoring metrics. This can be configured in the monitoring template under the `metrics` section by setting the `interval` field, with the unit being seconds. If not set, the default refresh interval specified during the creation of the monitoring will be used.

-------

Configuration usages of the monitoring templates yml are detailed below.
Expand Down Expand Up @@ -111,6 +115,8 @@ metrics:
# metrics scheduling priority(0->127)->(high->low), metrics with the same priority will be scheduled in parallel
# priority 0's metrics is availability metrics, it will be scheduled first, only availability metrics collect success will the scheduling continue
priority: 0
# refresh interval for this metrics group
interval: 600
# collect metrics content
fields:
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-if is metrics label
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@

**产出:**

- 1. 特性代码能以PR的形式合入HertzBeat仓库。
- 2. 完成 HertzBeat官方模板市场
- 3. 更新相关帮助文档
1. 特性代码能以PR的形式合入HertzBeat仓库。
2. 完成 HertzBeat官方模板市场
3. 更新相关帮助文档

**联系导师:** 赵青然 [[email protected]](mailto:[email protected])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ sidebar_label: 自定义监控

![HertzBeat](/img/docs/advanced/extend-point-1.png)

### 自定义监控指标刷新时间

现在,HertzBeat支持为每组监控指标设置不同的刷新时间。您可以在监控模板的 `metrics` 部分通过设置 `interval` 字段来实现,单位为秒。若不进行设置,则使用创建监控时设置的默认刷新时间。

-------

### 监控模版YML
Expand Down Expand Up @@ -146,6 +150,9 @@ metrics:
# 指标采集调度优先级(0->127)->(优先级高->低) 优先级低的指标会等优先级高的指标采集完成后才会被调度, 相同优先级的指标会并行调度采集
# 优先级为0的指标为可用性指标,即它会被首先调度,采集成功才会继续调度其它指标,采集失败则中断调度
priority: 0
# refresh interval for this metrics group
# 该指标组刷新时间
interval: 10
# collect metrics content
# 具体监控指标列表
fields:
Expand Down

0 comments on commit caf13c0

Please sign in to comment.