Compare commits

..
365 Commits
Author SHA1 Message Date
tomsun28 c33aa86ba2 [webapp] update ui
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-07-06 15:26:03 +08:00
tomsun28 b6bca5a10d [improve] make jackson serialize field all visibility
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-07-06 15:08:21 +08:00
Calvin c6f1f07155 [doc] japanese jvm (#3545) 2025-07-05 12:35:45 +08:00
Calvinandtomsun28 0ebd3499b7 [doc] japanese kafka (#3548)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-07-05 12:04:24 +08:00
淞筱 c88d4a7b0e [doc] update download page (#3549) 2025-07-05 11:56:39 +08:00
tomsun28 8bebae9db6 [doc] add hertzbeat maturity and fix doc (#3544) 2025-07-04 19:55:27 +08:00
b6b1a48a5c [doc] recommend newer mysql connector jar (#3541)
Signed-off-by: PJ Fanning <pjfanning@users.noreply.github.com>
Co-authored-by: 淞筱 <2030509072@qq.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-07-03 23:35:53 +08:00
63ed50ef45 [doc] Fix some issues in the documentation (#3526)
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: 淞筱 <2030509072@qq.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-07-03 23:04:31 +08:00
PJ Fanning e63715d1b0 enable GitHub Dependabot to create PRs for security alerts but not for every dependency update (#3543) 2025-07-03 21:27:48 +08:00
Calvin edf3eac6d6 [doc] japanese jetty (#3539) 2025-07-03 11:03:54 +08:00
Calvin 743f285c8d [doc] japanese ipmi (#3537) 2025-07-02 22:55:09 +08:00
Logicandaias00 458433464c [doc]update download page text (#3532)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-07-02 17:45:28 +08:00
淞筱 64740a4f85 [doc] update outdated links (#3535) 2025-07-02 17:15:19 +08:00
淞筱andaias00 b5a2bce261 download version deal (#3531)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-07-01 13:11:31 +08:00
Calvin 5e351c854b [doc] japanese iotdb (#3530) 2025-07-01 12:29:54 +08:00
0875bea046 fix: fix something (#3524)
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: 淞筱 <2030509072@qq.com>
2025-06-30 10:56:55 +08:00
Calvin 9ad5f77816 [doc] japanese influxdb promql (#3527) 2025-06-30 09:46:56 +08:00
aias00andCalvin 998f9059bc [feat]parallel ci (#3523)
Co-authored-by: Calvin <zhengqiwei@apache.org>
2025-06-30 00:04:10 +08:00
a1439c3ec2 [fix] fix i18n error and append two metrics about disk infos (#3514)
Signed-off-by: aias00 <liuhongyu@apache.org>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Calvin <zhengqiwei@apache.org>
2025-06-29 20:20:05 +08:00
742b6f6755 [doc] Add new commiter blog (#3522)
Co-authored-by: yinyijun <yingey2011>
Co-authored-by: 淞筱 <2030509072@qq.com>
2025-06-29 15:15:50 +08:00
5fdb34598c [doc] japanese hikvision (#3499)
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: 淞筱 <2030509072@qq.com>
2025-06-29 12:16:17 +08:00
Calvin 4f982d1ab0 [doc] japanese influxdb (#3521) 2025-06-29 11:50:42 +08:00
4a28056d9f [fix] Update the correct replacement of outdated functions and placeholders (#3516)
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-28 22:31:18 +08:00
Calvinandaias00 3f2fa71e22 [doc] japanese iceberg (#3519)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-28 22:25:22 +08:00
Jastandaias00 08c81bf62f [Improve] Improve kafka e2e (#3520)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-28 22:23:07 +08:00
e16d6cb4ba [feature] Support for Periodic Threshold preview (#3505)
Co-authored-by: Sherlock Yin <sherlock.yin1994@gmail.com>
Co-authored-by: Calvin <zhengqiwei@apache.org>
2025-06-28 20:38:38 +08:00
Calvin a54d14e803 [doc] japanese hugeGraph (#3518) 2025-06-28 07:24:44 +08:00
Calvinandaias00 01ae281769 [doc] japanese hive (#3506)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-28 00:10:22 +08:00
Calvin 9cb10ff14d [doc] japanese huawei switch (#3515) 2025-06-27 20:55:27 +08:00
Calvin 62f40d3ad1 [doc] japanese hpe switch (#3511) 2025-06-26 00:07:54 +08:00
tomsun28 57601ef989 [release] release new version 1.7.2 (#3510)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-06-25 22:01:18 +08:00
puruidong 0a05edbec5 [bugfix]Fixed an error in the format of the flying book notification (#3508)
Signed-off-by: puruidong <pruidong@gmail.com>
2025-06-25 19:18:21 +08:00
Yang Chenandtomsun28 fcef24fdbf [bugfix] Correctly parse binary comparison expressions (#3504)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-25 11:01:12 +08:00
e45c31abfb [bugfix] Fix incorrect expression parsing in alert setting component (#3497)
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-24 22:56:16 +08:00
198c190ca7 fixed:a minor issue change (#3428)
Signed-off-by: 淞筱 <2030509072@qq.com>
Co-authored-by: kangli <likang@apache.org>
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: liutianyou <tianyou.liu@qq.com>
Co-authored-by: 淞筱 <2030509072@qq.com>
2025-06-24 22:50:22 +08:00
铁甲小宝anda-little-fool 392a59f9a9 add:a small jdbc modified. (#3500)
Co-authored-by: a-little-fool <2030509072@qq.com>
2025-06-24 22:07:18 +08:00
aias00 c01b7f7bce [feat] update_mvnd_version (#3498) 2025-06-23 21:18:04 +08:00
Calvin 0323b044b8 [doc] japanese hertzbeat token (#3493) 2025-06-23 08:54:47 +08:00
256302fdcf [fix] Fix antlr4 parsing of or and unless logical and set binary operators (#3488)
Co-authored-by: wordofwordof <black.jack.kaiqi@gmail.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-22 19:46:34 +08:00
Calvin 3f3330af41 [doc] japanese hertzbeat (#3492) 2025-06-22 19:13:18 +08:00
Calvin 33342baa3f [doc] japanese hdfs namenode (#3490) 2025-06-22 06:43:10 +08:00
Logic 563cbd7943 [ci]: add mvnd support and update backend build (#3491) 2025-06-21 20:07:10 +08:00
Duansgandaias00 ddb1601290 [fix] antlr4 vectors and parse semantic fixes and optimizations (#3482)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-21 07:55:54 +08:00
Calvin 8e9d3c09f3 [doc] japanese hdfs datanode (#3487) 2025-06-21 00:07:53 +08:00
Calvin ade04d2cf2 [doc] japanese hbase region server (#3479) 2025-06-20 09:03:09 +08:00
Calvinandaias00 53555c88c7 [doc] japanese hbase master (#3477)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-19 19:14:43 +08:00
Logic 03bf31269d [docs](webhook): update Chinese documentation for alert integration (#3478) 2025-06-19 19:05:21 +08:00
Calvin 5c329a8a66 [doc] japanese hadoop (#3476) 2025-06-18 23:34:44 +08:00
dda9250243 [feature] Add statusCode metrics data. (#3446)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Logic <zqr10159@dromara.org>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: kangli <likang@apache.org>
Co-authored-by: liutianyou <tianyou.liu@qq.com>
2025-06-17 22:32:31 +08:00
Calvin 65a97aed8f [doc] japanese h3c switch (#3471) 2025-06-17 08:07:17 +08:00
Calvin 56528f4fc0 [doc] japanese greptime (#3469) 2025-06-15 22:12:43 +08:00
Duansgandliutianyou f218ba018a [fix] Fix Monitors paging display. (#3467)
Co-authored-by: liutianyou <tianyou.liu@qq.com>
2025-06-15 11:44:23 +08:00
d6ce0c153a [improvement] change column definitions for commonAnnotations and alertFingerprints to TEXT type (#3463)
Co-authored-by: Jast <shenghang@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: liutianyou <tianyou.liu@qq.com>
2025-06-14 21:52:27 +08:00
Calvin a1b23cacdc [doc] japanese greenplum (#3468) 2025-06-14 17:40:04 +08:00
ed6214d0c1 [doc] Alert notification template (#3466)
Co-authored-by: yinyijun <yingey2011>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-14 13:04:32 +08:00
Duansgandtomsun28 9a3fc5911d [fix] fix jacoco can not generate test reports. (#3455)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-14 00:21:07 +08:00
d5d01459e7 [Fix] fix custom monitoring bulletin NullPointerException (#3448)
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: kangli <likang@apache.org>
Co-authored-by: liutianyou <tianyou.liu@qq.com>
2025-06-13 08:48:51 +08:00
liutianyouandtomsun28 d077c72211 [doc] add doc for integrate volcengine alerts (#3460)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-13 00:32:15 +08:00
Yang Chen 11e3e4cc22 [improvement] disable default OpenTelemetry exporters to prevent connection errors (#3461) 2025-06-12 23:40:28 +08:00
Calvin c24c6ab7aa [doc] japanese freebsd (#3456) 2025-06-12 08:50:13 +08:00
Calvinandaias00 a183176e83 [doc] japanese flink on yarn (#3452)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-11 08:56:10 +08:00
tomsun28 a2e8739fec [doc] add publish version 1.7.1 blog (#3449) 2025-06-11 06:57:02 +08:00
liutianyouandCalvin ebb6e3d4ff [feature] support volcengine alert source (#3451)
Co-authored-by: Calvin <zhengqiwei@apache.org>
2025-06-11 00:48:07 +08:00
tomsun28 fc3f26368d [security] update hertzbeat security model (#3450) 2025-06-11 00:22:26 +08:00
Calvin 7967cfabf0 [doc] japanese flink (#3447) 2025-06-10 07:31:31 +08:00
199466cd59 [feat] add support for OpenRouter AI provider (#3439)
Signed-off-by: Yang Chen <1597081640@qq.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Jast <shenghang@apache.org>
2025-06-09 23:35:08 +08:00
8065b63057 [docs] Add one-click installation for Rainbond Cloud (#3440)
Signed-off-by: songyg <songyg@goodrain.com>
Co-authored-by: songyg <songyg@goodrain.com>
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-09 23:32:14 +08:00
Calvinandaias00 88655fcf19 [doc] japanese euleros (#3442)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-06-09 12:03:31 +08:00
Duansgandtomsun28 99b5460dd1 [feature] Support Huawei Cloud Cloud Eye alert source (#3443)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-09 00:22:31 +08:00
d681420c11 [feature] add support for darwin (#3431)
Co-authored-by: kangli <likang@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-09 00:04:02 +08:00
Yang Chen 8618145e44 [feat] add support for ollama and update docs (#3441) 2025-06-07 18:48:41 +08:00
Duansgandkangli dd0045c6a4 [bugfix] Fix the issue where Prometheus RealTime Threshold is not eff… (#3434)
Co-authored-by: kangli <likang@apache.org>
2025-06-06 13:00:55 +08:00
Yang Chen 84e0a604e7 [improvement] disable default OpenTelemetry exporters to prevent connection errors (#3437) 2025-06-06 11:29:51 +08:00
Calvinandtomsun28 ce253f7069 [doc] japanese emqx (#3433)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-06 00:52:26 +08:00
Jast 767b70f70b [Improve] add mvnw (#3430) 2025-06-06 00:49:50 +08:00
Duansgandtomsun28 4aad08ca17 [feature]Support Alibaba Cloud 'Simple Log Service(SLS)' alert source (#3422)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-04 21:05:57 +08:00
c176bb2988 [doc] japanese elasticsearch (#3423)
Co-authored-by: kangli <likang@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-04 09:31:22 +08:00
3cb4fc71f9 [doc] japanese dynamic_tp (#3419)
Co-authored-by: kangli <likang@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-04 09:23:57 +08:00
c3f32132ca [feat] support sql("...") and promql("...") expressions including SQL condition parsing (#3410)
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-06-04 09:07:18 +08:00
e1affb169f [feature]Make GreptimeDB as a grafana data source (#3403)
Signed-off-by: Logic <zqr10159@126.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-06-03 23:37:31 +08:00
shown db27159947 [infra]: Update issue tmpl (#3421)
Signed-off-by: shown <yuluo08290126@gmail.com>
2025-06-02 18:52:51 +08:00
63c187488f [doc] japanese doris_fe (#3416)
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-31 09:14:37 +08:00
f3f66ada0d [doc] Update anonymous user auth configuration of the grafana dashboard document (#3407)
Co-authored-by: Calvin <zhengqiwei@apache.org>
Co-authored-by: Logic <zqr10159@dromara.org>
Co-authored-by: kangli <likang@apache.org>
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-05-31 09:12:33 +08:00
tomsun28 d5c934dc01 [doc] update home doc (#3418) 2025-05-30 21:26:14 +08:00
Jast 518eebb6b1 [Doc] Update 1.7.1 (#3411) 2025-05-29 16:12:24 +08:00
Calvin 210454f969 [doc] japanese doris_be (#3409) 2025-05-29 08:03:06 +08:00
Calvin a8db5e31a0 [doc] japanese docker (#3408) 2025-05-28 07:16:33 +08:00
Calvin c01653aff3 [doc] japanese dns sd (#3405) 2025-05-27 21:27:58 +08:00
Calvin 480bd0e449 [doc] japanese dns (#3404) 2025-05-27 08:47:33 +08:00
97faca6753 [docs] update alert threshold doc (#3399)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: liutianyou <tianyou.liu@qq.com>
2025-05-26 16:12:50 +08:00
Calvinandtomsun28 e271bd7417 [doc] japanese deepseek & dm (#3400)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-26 08:53:40 +08:00
7de4fd1cbf [improve] http sd collector adds authentication (#3388)
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: Calvin <zhengqiwei@apache.org>
2025-05-26 08:42:21 +08:00
Calvin c2a7d0db35 [doc] japanese Debian (#3398) 2025-05-25 15:42:54 +08:00
Calvin 93b2630bf3 [doc] japanese dahua (#3396) 2025-05-25 13:09:06 +08:00
Calvinandliutianyou 23749e7fac [doc] japanese coreos (#3393)
Co-authored-by: liutianyou <tianyou.liu@qq.com>
2025-05-24 09:35:46 +08:00
kangli d5eae40754 [doc]add new committer blog (#3395) 2025-05-24 08:23:17 +08:00
Calvin 7ef79de1de [doc] japanese consul sd (#3392) 2025-05-23 13:07:11 +08:00
tomsun28 8496771c8b [doc] new contributor and committer, update doc (#3391)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-05-23 12:15:09 +08:00
Calvin f31c835181 [doc] japanese clickhouse (#3390) 2025-05-23 08:42:33 +08:00
Logicandtomsun28 552554b96d [fix](warehouse): improve GreptimeDB data storage and querying (#3387)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-22 23:31:06 +08:00
zhangyaxiandtomsun28 4adcfd2a4e [test] Add unit tests for HttpSdCollectImpl (#3386)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-22 23:29:23 +08:00
Calvin e630beecb4 [doc] japanese cisco switch (#3389) 2025-05-22 22:46:53 +08:00
Duansgandtomsun28 6c2b38e180 [doc] modify supplement related documentation (#3383)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-21 23:17:50 +08:00
84986dd1bf [feature] support auto nacos service discovery (#3324)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Signed-off-by: zhangyaxi <yaxi.zhang950408@outlook.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-05-21 22:01:09 +08:00
af868e083a [Task] Batch import metrics data in victoria-metrics (#3337)
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-05-20 23:56:56 +08:00
be3e2f3558 [doc] modify chinese words (#3380)
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-20 21:42:37 +08:00
d32818e8ef [feat] Support Zookeeper Service Discovery (#3377)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-20 21:30:48 +08:00
10b283522c [improve] add path validation for pluginservice (#3375)
Signed-off-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: liutianyou <tianyou.liu@qq.com>
2025-05-20 12:32:24 +08:00
31ab2da41e [doc] Add blog (#3379)
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-20 00:16:06 +08:00
LL-LINandtomsun28 a9436049e3 [doc] fix incorrect time template syntax usercase in doc (#3378)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-20 00:12:20 +08:00
Calvinandtomsun28 41c010511c [doc] japanese centos (#3376)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-20 00:08:39 +08:00
aias00andCalvin b5281c1274 update maven dep (#3359)
Co-authored-by: Calvin <naruse_shinji@163.com>
2025-05-20 00:06:59 +08:00
62cf3d1b2b [improve] improve jndi validation (#3358)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
2025-05-18 17:45:09 +08:00
dc8ae844c1 [improve] improve url validation for serverChan (#3364)
Signed-off-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-18 16:48:31 +08:00
91a7593b87 [improve] improve url validation for SlackAlertNotifyHandlerImpl (#3363)
Signed-off-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-18 16:17:31 +08:00
4442a52adf [improve] improve url validation for TelegramBotAlertNotifyHandlerImpl (#3362)
Signed-off-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-18 14:09:09 +08:00
60e3437e82 [improve] improve url validation for WeComRobotAlertNotifyHandlerImpl (#3361)
Signed-off-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-18 13:31:39 +08:00
21d6ec2f1b [bugfix] Incorrect SD sub-monitor status (#3340)
Signed-off-by: Sherlock Yin <sherlock.yin1994@gmail.com>
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-05-18 01:00:37 +08:00
tomsun28 3ed50f39cb [doc] new ppmc liutianyou and update qq num (#3357)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-05-17 11:08:39 +08:00
Logic dfba21f224 [doc](start): update greptime-init documentation (#3355) 2025-05-16 20:41:08 +08:00
Sherlock Yinandtomsun28 9fb3f39eb1 [doc] update OS monitor (#3353)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-16 07:46:41 +08:00
Calvin 2430448089 [doc] japanese api (#3352) 2025-05-16 00:41:36 +08:00
Yang Chen 993de3d504 [bugfix] Fix incorrect webhook URLs for Uptime Kuma, Zabbix, and Tencent Cloud (#3351) 2025-05-15 20:03:19 +08:00
Jast 955ecd2128 [release] update release version 1.7.1 (#3347) 2025-05-15 15:20:52 +08:00
LL-LIN 96e5402c09 [bugfix] Fix frontend error when all monitor metrics are selected in new bulletin form (#3345) 2025-05-15 14:07:34 +08:00
Jast 0a6e8147e8 [build] Update .gitignore and add Maven wrapper properties (#3346) 2025-05-15 11:31:47 +08:00
7779056983 [feature] Support DNS Service Discovery (#3328)
Signed-off-by: Sherlock Yin <sherlock.yin1994@gmail.com>
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: yinyijun <yingey2011>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-15 08:25:50 +08:00
Calvinandtomsun28 ca3348adf2 [doc] japanese almalinux (#3343)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-15 00:07:06 +08:00
dc822f50e8 [feat] Enhance Label Management for Monitors (#3327)
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-14 23:31:15 +08:00
896adb76a2 [feature] Support Consul Service Discovery (#3326)
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Calvin <naruse_shinji@163.com>
2025-05-14 23:21:00 +08:00
Calvin 2a49fa5774 [doc] japanese airflow (#3339) 2025-05-14 21:54:54 +08:00
aias00 2259d51cae [feat] add deep wiki badge (#3334) 2025-05-13 14:38:31 +08:00
Calvin e9e49cfbc5 [doc] japanese activemq (#3333) 2025-05-13 08:13:14 +08:00
kangliandtomsun28 3eba906491 [feature] Support Eureka Service Discovery (#3323)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-12 20:35:13 +08:00
6645c5d4b2 [Improve] Add i18 for ai bot (#3330)
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-12 20:06:16 +08:00
Calvin 88fb007ef0 [doc] japanese readme (#3329) 2025-05-12 16:03:10 +08:00
LogicandJast 4892ef101f [feature]: integrate OpenTelemetry for GreptimeDB logs and traces- Rename hertzbeat-log to hertzbeat-otel (#3319)
Co-authored-by: Jast <shenghang@apache.org>
2025-05-09 15:03:49 +08:00
tomsun28andshown d0b7e38537 [bugfix] fix the calculator expr exist not work (#3314)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-05-09 13:15:46 +08:00
096153b3a4 [license] update the license file, to add the plc4j-driver-s7 license (#3318)
Co-authored-by: cuijianzhong <shangyuancjz@126.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-05-07 22:00:05 +08:00
zhangyaxi b313db36c6 [feature] Support Zabbix alert source (#3317)
Signed-off-by: zhangyaxi <yaxi.zhang950408@outlook.com>
2025-05-07 08:54:23 +08:00
tomsun28andCopilot 47298033dc [refactor] set default encoding charset utf8 (#3315)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-05 23:30:30 +08:00
tomsun28 f05e91247a [refactor] refactor auto discovery http sd (#3300)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-05-04 00:07:06 +08:00
zhangyaxiandtomsun28 1592c93d25 [feature] Support Uptime Kuma alert source (#3312)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-05-01 14:31:52 +08:00
Yang Chenandtomsun28 46d609a95e [docs] add help documentation for alert integration (#3308)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-30 16:05:59 +08:00
Yang Chen f17fb02441 [docs] Correct Markdown formatting and update lint config to enable local checking (#3310) 2025-04-30 11:08:38 +08:00
e6cc71ed56 [Improve] Add unit test for PeriodicAlertCalculator (#3304)
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: yinyijun <yingey2011>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-28 17:46:14 +08:00
Cyanty e2a9160e59 [refactor] Remove the possible security in action and ignore the 500 code for link check (#3303) 2025-04-28 11:30:14 +08:00
7ebeee2c1f [docs] Add Chinese and English versions of the Hertzbeat upgrade guide (#3294)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-27 00:26:40 +08:00
Cyantyandtomsun28 ccfc8dc8ce [improve] Optimize the way of Dead Link Check (#3302)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-26 23:04:49 +08:00
Yang Chenandaias00 ca9db17241 [bugfix] enables support for VictoriaMetrics in cluster mode within HertzBeat (#3297)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-26 22:29:47 +08:00
Cyanty 7a40bdee12 [Doc] Add English doc for springboot auto practice usecase (#3298) 2025-04-26 20:40:16 +08:00
tomsun28 5db20d33f4 [bugfix] fix collector direct oom (#3295) 2025-04-24 20:22:50 +08:00
Cyanty 896869c611 [Doc] Add springboot auto practice usecase (#3293)
Signed-off-by: Cyanty <153884653+Cyanty@users.noreply.github.com>
2025-04-24 12:51:04 +08:00
tomsun28 32ce88b2c0 [webapp] try reduce memory growth and fix crash (#3292)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-04-23 19:47:24 +08:00
2288d8e900 [e2e] add e2e test for k8s monitor (#3280)
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Jast <shenghang@apache.org>
2025-04-22 23:57:01 +08:00
tomsun28andJast dbb81d44ff [doc] update doc, usecase blog and help doc (#3286)
Co-authored-by: Jast <shenghang@apache.org>
2025-04-22 22:33:47 +08:00
227666dd46 [Task] Set local database as default file server provider (#3282)
Co-authored-by: yinyijun <yingey2011>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-22 22:32:04 +08:00
liutianyouandtomsun28 b14bc6569f [bugfix] page title show "Not page name" when filter monitor list by type (#3289)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-22 22:23:54 +08:00
Jastandtomsun28 7c7102da17 [feature] support ai bot (#3285)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-22 22:19:17 +08:00
Jay丿167andaias00 489eac8e11 [improve] Add E2E tests for Redis collector (#3283)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-22 20:33:46 +08:00
900655680a [improve] Add jdbc common collect e2e code (#3273) (#3273)
Signed-off-by: Cyanty <153884653+Cyanty@users.noreply.github.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: Jast <shenghang@apache.org>
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-04-22 10:19:22 +08:00
tomsun28 e87ed449f2 [doc] update contributors wall (#3281)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-04-22 01:17:41 +08:00
tomsun28 ddf4759b34 [refactor] refact tag to label code (#3278) 2025-04-21 22:16:47 +08:00
Yang ChenandLogic a8ce48b50d [bugfix] support no-whitespace alert expressions in instance filtering (#3276)
Co-authored-by: Logic <zqr10159@dromara.org>
2025-04-21 15:46:16 +08:00
liutianyou a0f3890137 [feature] new alert supports reminding through system notifications (#3275) 2025-04-21 14:47:11 +08:00
liutianyou b02837b362 [bugfix] fix the prometheus metric response data parsing is abnormal (#3274) 2025-04-20 19:47:13 +08:00
9f9cdcf1a9 [Improve] optimize prompt (#3270)
Co-authored-by: Logic <zqr10159@dromara.org>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-20 09:57:06 +08:00
tomsun28 326497939d [webapp] update header logo style (#3272) 2025-04-20 09:49:59 +08:00
Jast d881aff90d [feature] add Maven Wrapper scripts (#3271) 2025-04-19 17:30:57 +08:00
78b0a428ff [feature] support collector alarm and refactor alarm (#2693)
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-19 13:07:41 +08:00
Yang Chenandtomsun28 ba173acc09 [bugfix] correct instance filtering regex in RealTimeAlertCalculator (#3269)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-19 10:10:11 +08:00
9d842a241b [bugfix] Wrong webhook alert template (#3265)
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: Logic <zqr10159@dromara.org>
2025-04-18 23:48:58 +08:00
Cyanty c480d63833 [PR] [bugfix] Set the prometheus monitoring time and correct historical da… (#3264) 2025-04-18 20:56:50 +08:00
tomsun28 ce479c6ba9 [doc] add new contributor in wall (#3259)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-04-18 10:04:45 +08:00
f683cab857 [bugfix] Resolve incorrect display of detailed information in Prometheus task history monitoring charts under VictoriaMetrics. (#3248)
Co-authored-by: Jast <shenghang@apache.org>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-18 09:52:42 +08:00
9c38bd5309 [refactor] Alert datasource calculate (#3253)
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: yinyijun <yingey2011>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-18 09:31:47 +08:00
淞筱 e7cd23a85d [bugfix] fix a remote command execution. (#3250) 2025-04-17 23:14:29 +08:00
Jast 81ad7d51b6 [Feature] Add log mcp for java (#3254) 2025-04-17 16:19:15 +08:00
leo 9fa5b17fe4 [bugfix] fix UriComponentsBuilder in PromqlQueryExecutor (#3244) 2025-04-14 20:37:18 +08:00
tomsun28 9700161fdd [doc] add new contributors to wall (#3243)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-04-14 16:40:24 +08:00
f578df1deb [feat] enable label-based filtering and selection for monitoring thresholds (#3223)
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-14 14:26:52 +08:00
eb58bb76f2 [feature] switch to prometheus online parser & add query datasource (#3215)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Signed-off-by: leo <1552443053@qq.com>
Co-authored-by: Ceilzcx <1758619238@qq.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-14 14:08:11 +08:00
Cyantyandaias00 066d74629a [improve] Adjust Grafana configuration priority hierarchy and optimize API request exception handling (#3241)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-14 09:53:44 +08:00
tomsun28 9619638cff [doc] add new release 1.7.0 blog (#3237) 2025-04-14 09:45:53 +08:00
Yang Chenandtomsun28 b91f849594 [bugfix] Added jobContentCache.remove(jobId) to cancelAsyncCollectJob (#3240)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-13 20:28:52 +08:00
Logic e1806f856f [doc]update Grafana dashboard setup instructions (#3238) 2025-04-13 19:40:33 +08:00
淞筱 95654e49c5 [doc] add code-style-check zh-ch. (#3236)
Signed-off-by: 淞筱 <105542329+a-little-fool@users.noreply.github.com>
2025-04-12 13:41:40 +08:00
9ceb6e6400 [bugfix] Fix the issue where pendingTimeouts may be incorrect in the HashedWheelTimer. (#3174)
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-12 00:20:10 +08:00
淞筱andtomsun28 64cc15fabb [doc] code style check (#3232)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-12 00:14:21 +08:00
27da850ca4 [doc] add alerting silence doc. (#3229)
Co-authored-by: Jast <shenghang@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-12 00:03:24 +08:00
1ad52321ea [Doc] Add Blog (#3224)
Co-authored-by: Administrator <admin@admin.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-11 23:50:40 +08:00
Cyanty ff037a6a3a [Doc] Modify the YML configuration parameters for Spring Boot 2.0/3.0 monitoring (#3231) 2025-04-10 20:21:11 +08:00
Logic 433f09a4e3 [feature]A preliminary logging module implementation (#3218) 2025-04-10 15:21:48 +08:00
Jast 706baffd5e [Doc] Fix dead link (#3227) 2025-04-09 23:43:19 +08:00
Logic 0b6fb353f1 [feature]add support for Dahua and Uniview devices (#3214) 2025-04-07 23:05:29 +08:00
0385892674 [feature] add pushgateway to push module (#3204)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Signed-off-by: leo <1552443053@qq.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-05 17:28:11 +08:00
Logic 04e2321175 [test](hertzbeat-collector): add unit test for XML response parsing (#3212) 2025-04-05 09:18:52 +08:00
8373f0a247 [test] add test for controller AlertInhibitController (#3183)
Co-authored-by: yunfan24 <yunfan24@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-03 21:31:06 +08:00
Logic 5ad03687b2 [feature] Implementation of Hikvision camera monitoring and http monitoring xml parsing function (#3211) 2025-04-03 20:07:18 +08:00
tomsun28andaias00 7127159063 [doc] archive version docs (#3207)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-03 14:30:49 +08:00
Nick Guoandtomsun28 51715797ef [improve] optimize DnsCollectTest with status code. (#3209)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-03 14:01:10 +08:00
liutianyouandtomsun28 47a1b13781 [doc] add doc for alarm grouping and alarm inhibit (#3206)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-03 13:33:15 +08:00
d5fc492b98 [feature] support plc s7 protocol for siemens (#3194)
Co-authored-by: cuijianzhong <shangyuancjz@126.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-02 23:09:32 +08:00
bbc30cd3db [improve] i18n Portuguese (#3193)
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-02 22:46:33 +08:00
6e50d1f3a7 [improve] support the use of time expressions in HTTP payloads (#3192)
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-04-02 22:32:18 +08:00
b18412254e [improve] optimize kafka collection logic and expand test coverage (#3189)
Co-authored-by: yunfan24 <yunfan24@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-02 22:26:37 +08:00
Yang Chenandaias00 fc0ef7773c [bugfix] fix bulletin indicator selection status error (#3201)
Co-authored-by: aias00 <liuhongyu@apache.org>
2025-04-02 15:48:33 +08:00
aias00 adf71441f8 update download info (#3203) 2025-04-02 15:44:42 +08:00
tomsun28 e36842420f [improve] update monitor list ui (#3200)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-03-31 19:27:22 +08:00
tomsun28andaias00 a2c1123b09 [doc] update new hertzbeat ppmc (#3191)
Co-authored-by: aias00 <rokkki@163.com>
2025-03-31 14:52:37 +08:00
tomsun28 b4151a4e73 [improve] update monitor detail ui (#3199)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-03-31 14:33:29 +08:00
jujin 1c1683d9c6 [doc] add blog bout How Does Metrics Collection Work (#3195) 2025-03-30 14:08:15 +08:00
46d4fc2dd9 [bugfix] Modify inconsistent icons (#3190)
Co-authored-by: yinyijun <yingey2011>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-29 10:38:07 +08:00
Sarthak Aroraandtomsun28 ffa2487587 [docs] add collector user guide (#3187)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-29 09:13:06 +08:00
30c7b22c4c [doc] add help documentation for Alarms Center (#3181)
Co-authored-by: yunfan24 <yunfan24@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
2025-03-29 00:06:40 +08:00
彭镜肇andtomsun28 7a3e23ec59 [improve] update import for package import (#3180)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-28 00:09:45 +08:00
Jast da6556641a [Doc] Modify the error records in the document (#3178) 2025-03-27 23:45:02 +08:00
Rickandrick b008f16b67 fix: Ai is a typo (#3176)
Co-authored-by: rick <LinuxSuRen@users.noreply.github.com>
2025-03-26 12:59:17 +08:00
tomsun28andaias00 b77222765c [improve] update notice copyright years (#3171)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
2025-03-25 10:16:26 +08:00
tomsun28 aeb4188f83 [improve] update git archive export ignore (#3172)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-03-25 09:39:49 +08:00
Yang Chen 311cb131fd [bugfix] fix bind Labels are not updated when the Alarm Severity switches (#3170) 2025-03-24 22:12:06 +08:00
tomsun28andaias00 21558e9b4f [bugfix] fix postgre mount error, use mariadb instead of mysql in compose (#3168)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
2025-03-24 15:12:56 +08:00
LL-LINandaias00 8d1f306433 [feature] implement labels-based monitors filtering in bulletin creation flow (#3161)
Co-authored-by: aias00 <rokkki@163.com>
2025-03-24 10:46:52 +08:00
tomsun28 e98af9527e [release] update release version 1.7.0 version and docs (#3165)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-03-23 10:39:00 +08:00
811a07553b [doc] Add alert integration japanese i18 (#3164)
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-22 14:16:28 +08:00
9fd58ced4a [feature] add twilio sms client support (#3159)
Co-authored-by: yunfan24 <yunfan24@outlook.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-22 14:12:32 +08:00
LL-LINandtomsun28 a331c045ae [bugfix] retain sorting state after monitor list auto-refresh (#3156)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-22 11:48:34 +08:00
yunfan24andaias00 63d3d18428 [bugfix] Fix http header being incorrectly encoded. (#3108)
Co-authored-by: aias00 <rokkki@163.com>
2025-03-22 11:44:16 +08:00
Yang Chen cec8d8b396 [bugfix]: fix incomplete class documentation in AppServiceImpl (#3162) 2025-03-21 17:34:43 +08:00
9d68d16a78 [feature] Support TencentCloud alert source (#3149)
Co-authored-by: yunfan24 <yunfan24@outlook.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-17 20:55:56 +08:00
Kerwin BryantandLogic 290474a715 Abstract Redundant Input Components into ConfigurableFieldComponent for Unified Management (#3152)
Co-authored-by: Logic <zqr10159@dromara.org>
2025-03-17 18:50:00 +08:00
Yang Chenandyunfan24 0dbc7347b4 [feature] Supports sending messages to a specific Telegram group topic.(#3079) (#3143)
Co-authored-by: yunfan24 <yunfan24@outlook.com>
2025-03-17 14:56:02 +08:00
tomsun28 e2a2d5eaec [bugfix] fix nightly docker build github action (#3153) 2025-03-17 10:00:41 +08:00
tomsun28 356cca295d [webapp] fix less style file over max build error (#3151)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-03-16 21:58:45 +08:00
yunfan24 5e09c6d9ae [improve] Merge SMS configuration class. (#3148) 2025-03-16 21:27:07 +08:00
tomsun28andZhang Yuxuan 54caa84fc1 [bugfix] fix collect dispatch error (#3150)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Zhang Yuxuan <1373529784@qq.com>
2025-03-15 21:49:58 +08:00
d2a332f533 [bugfix] Fixed #3112, disappear left menu tree item when restart service (#3116)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: yunfan24 <yunfan24@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
2025-03-15 20:47:53 +08:00
tomsun28andLogic dc2efdf1c2 [improve] support bind metrics label and others into alert (#3146)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Logic <zqr10159@dromara.org>
2025-03-15 19:40:48 +08:00
4defb733bf [feature] support SSH proxy jump connections (#3138)
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: Logic <zqr10159@dromara.org>
2025-03-14 20:51:58 +08:00
f8e85ec4f1 [feature] Support skywalking alert source (#3144)
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: yinyijun <yingey2011>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-14 10:41:35 +08:00
jujinandyunfan24 3468739504 [feature] Add AWS sms client (#3134)
Co-authored-by: yunfan24 <yunfan24@outlook.com>
2025-03-14 01:01:29 +08:00
Kerwin Bryantandtomsun28 5a92161cd9 [webapp] Fix the issue of the empty dropdown menu on the Kanban board page. (#3142)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-12 23:58:48 +08:00
Kerwin Bryant 4ce6ffd4ee [improve] Configuring gitpod with java (#3141) 2025-03-12 23:52:36 +08:00
yunfan24andtomsun28 9f34d201ae [doc] Add new committer blog (#3140)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-11 00:24:44 +08:00
liutianyou 4b8ccf2fea [improve] improve plugin upload (#3139) 2025-03-11 00:18:57 +08:00
tomsun28 adf27d2544 [bugfix] fix overflow arrow buffer index (#3137) 2025-03-10 15:25:22 +08:00
tomsun28 033b9b0706 [improve] fix potential memory leakage and content length issues. (#3128)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-03-10 00:45:12 +08:00
01be0c7a1d [improve] Optimize the progress display of monitoring imports (#3120)
Signed-off-by: Sherlock Yin <sherlock.yin1994@gmail.com>
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: yinyijun <yingey2011>
2025-03-10 00:25:31 +08:00
0fdd76c0de [feature] add smslocal sms notification (#3135)
Signed-off-by: 淞筱 <105542329+a-little-fool@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: yunfan24 <yunfan24@outlook.com>
2025-03-09 21:51:53 +08:00
tomsun28 1a38fcf776 [doc] welcome new committer and contributor (#3132)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-03-07 17:50:13 +08:00
yyahang 268e111024 [bugfix] Fix swagger opening exception that Failed to load API definition. (#3127) (#3129) 2025-03-07 01:03:41 +08:00
tomsun28and淞筱 484dc5f70f [webapp] fix monitor define param wrong placeholder tip (#3118)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: 淞筱 <105542329+a-little-fool@users.noreply.github.com>
2025-03-05 21:09:25 +08:00
tomsun28andaias00 b7bd9eb305 [improve] support reuse jdbc connection switch (#3101)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
2025-03-05 21:07:06 +08:00
yunfan24and淞筱 a5f874e682 [doc] Add alibaba SMS and unisms documentation. (#3114)
Co-authored-by: 淞筱 <105542329+a-little-fool@users.noreply.github.com>
2025-03-05 10:08:21 +08:00
Jastandtomsun28 fcf52b383a [doc] Add GSOC doc (#3122)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-04 21:50:36 +08:00
Jast e93c3a9054 [doc]fix link (#3123) 2025-03-04 00:53:11 +08:00
不关银渐层的事哦andtomsun28 84f222b516 [bugfix] fix #3090 garbled characters (#3113)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-03-03 16:09:12 +08:00
jujin 53bb58da5f [bugfix] Fix exception thrown when searching for CollectRep.Field in the list (#3109) 2025-02-28 23:17:46 +08:00
tomsun28 3688974610 [bugfix] fix alert sse illegal state exception (#3106) 2025-02-25 15:27:53 +08:00
af35043663 [feature] adding-ptBR-translation (#3098)
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-02-25 09:37:21 +08:00
Jastandshown 84c28229b2 [Feature] Add deepseek Api Monitor (#3096)
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-02-24 15:39:53 +08:00
tomsun28 1a3e614209 [webapp] fix web oom crash when backend api can not access (#3100) 2025-02-23 21:22:37 +08:00
Jast 3df0e56da9 [Improve] Message notification prompt optimization (#3095) 2025-02-23 21:19:10 +08:00
Jast b5b4771e1a [Doc]Improve openai doc (#3097) 2025-02-22 10:30:25 +08:00
b8c5ae4d40 [bugfix] kafka client detect error (#3088)
Co-authored-by: Jast <shenghang@apache.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-02-21 22:05:12 +08:00
淞筱 207f2d958c [doc] correct home's new_committer_process (#3094) 2025-02-21 20:59:51 +08:00
Nick Guo 398a40bba4 [improve] optimize kafka collect test (#3093) 2025-02-21 17:47:46 +08:00
yunfan24andtomsun28 bb14681621 [feature] supports alibabacloud sms. (#3084)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-02-21 13:55:30 +08:00
yunfan24 d3a080fbaf [improve] Improve and unify the search. (#3085) 2025-02-20 14:58:56 +08:00
tomsun28 ce6f9feac6 [webapp] update and fix alert ui when theme dark (#3082) 2025-02-16 23:25:04 +08:00
yunfan24 7d18118bbd [feature] SMS notification supports unisms. (#3077) 2025-02-15 22:40:03 +08:00
yunfan24andaias00 d5d2b6bc71 [doc] Update the SMS configuration document. (#3073)
Co-authored-by: aias00 <rokkki@163.com>
2025-02-13 20:32:48 +08:00
Logicandtomsun28 e11a4da2ac [improve](web-app): update monitor chart configuration and springboot GreptimeDB version (#3071)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-02-13 10:19:49 +08:00
58360442ca [Bugfix] fix when the monitor is modified, the status is erroneously changed (#3067)
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-02-13 00:14:37 +08:00
yunfan24andaias00 4d76c0abf4 [improve] Refactor SMS sending and replace Tencent Cloud SDK with HTTP API. (#3063)
Co-authored-by: aias00 <rokkki@163.com>
2025-02-11 19:40:36 +08:00
Jastandtomsun28 f761e18739 [Feature]Add Chinese check (#3066)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-02-11 10:36:55 +08:00
yunfan24 6ac073a54e [improve] Complete the missing labels in the i18n file. (#3065) 2025-02-11 10:16:36 +08:00
65a8d19c5d [feature] Support SSH Tunnel (#3060)
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: aias00 <rokkki@163.com>
2025-02-10 10:20:03 +08:00
tomsun28 060b4d875d [webapp] update ui theme (#3064)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-02-10 10:09:31 +08:00
kangliandLogic 6c88c1ba03 [API DOC] Change Swagger description (#3061)
Co-authored-by: Logic <zqr10159@dromara.org>
2025-02-08 19:29:12 +08:00
tomsun28 8c58a35476 [bugfix] fix singleton not support remove, search id error, audio fetch 401 (#3062)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-02-08 18:36:42 +08:00
2ab05a5669 [feature] Add Japanese i18n (#3013)
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-02-08 09:19:13 +08:00
f3bc7f55c5 [feature] Add Sftp config for monitor (#3038)
Co-authored-by: yinyijun <yingey2011>
Co-authored-by: yunfan24 <yunfan24@outlook.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
2025-02-07 23:57:06 +08:00
7effbc1f0d [Feature]Add zookeeper e2e code (#3030)
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-02-07 23:22:10 +08:00
Logicandtomsun28 05e42182d9 [bugfix]style(alert-center): enhance 3D transformation and z-index layers (#3059)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Signed-off-by: Logic <zqr10159@dromara.org>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-02-07 20:28:15 +08:00
yunfan24andtomsun28 5e69f4dfd0 [bugfix] Fix the issue where the monitoring status is not updated. (#3056)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-02-07 16:12:47 +08:00
tomsun28 aeb0083394 [improve] update theme ui color (#3057)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-02-07 15:47:19 +08:00
Logic 02f635bdd3 [improve](alert-center) enhance alert card animations and interactions (#3055) 2025-02-07 10:18:52 +08:00
7dbcaaeda8 [alert] support multi query expr threshold (#3054)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Signed-off-by: Logic <zqr10159@126.com>
Co-authored-by: Logic <zqr10159@dromara.org>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-06 21:33:56 +08:00
Logicandgithub-actions[bot] 4ddf0a9f3f [alert] support sse for alert center, no need to manually refresh the page, add slide-in animation (#3051)
Signed-off-by: Logic <zqr10159@126.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-02-06 16:13:01 +08:00
yunfan24andtomsun28 f1b1e3f7d6 [improve] Search ignores case sensitivity. (#3042)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-02-05 15:56:31 +08:00
yunfan24 921b8e5713 [update] upgrade actions upload-artifact to v4 (#3046) 2025-02-05 11:30:42 +08:00
yunfan24andtomsun28 4009525f81 [improve] Replaced hardcoded text with internationalized string. (#3035)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-30 22:01:32 +08:00
yunfan24 e0c7b4e111 [bugfix] Fixed the bug in the threshold rules search box. (#3034) 2025-01-30 21:43:51 +08:00
yunfan24andaias00 5e01482caa [feature] Add pagination and name-based search functionality in notification module (#2948)
Co-authored-by: aias00 <rokkki@163.com>
2025-01-27 14:12:55 +08:00
yunfan24 028e2fbcbe [bugfix] fix and enable some unit tests. (#3031) 2025-01-27 12:58:14 +08:00
tomsun28 d00cc6dcf4 [feature] periodic alert threshold (#3024) 2025-01-26 18:37:57 +08:00
4b7fdd6985 OnlineParserTest doesn't test anything (#3010)
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: leo <1552443053@qq.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-26 16:13:21 +08:00
tomsun28andJast e45ec431aa [doc] update new contributor wall (#3025)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Jast <shenghang@apache.org>
2025-01-26 15:50:05 +08:00
Jastandtomsun28 8fa52fbca1 [Feature] Add API e2e code (#3029)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-26 11:23:52 +08:00
Jastandtomsun28 132fd00ab1 [Improve] update english doc (#3028)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-26 11:12:43 +08:00
12ba2faa19 [MINOR UPDATE] Use Encode to string when possible (Base64) (#3016)
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-24 18:44:14 +08:00
PJ Fanningandaias00 2f3abfbad4 [issue-2998] remove invalid check in isValidLabelValue (#3015)
Co-authored-by: aias00 <rokkki@163.com>
2025-01-24 18:38:43 +08:00
myangle1120andaias00 95739d9114 [bugfix] Modify mask issue (#3018)
Co-authored-by: aias00 <rokkki@163.com>
2025-01-24 09:27:43 +08:00
Logicandtomsun28 428ae1f7d5 [bugfix]Fix page not found (#3014)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-23 19:49:02 +08:00
PJ Fanningandaias00 6509b8bfc6 [MINOR UPDATE] always specify the char encoding in getBytes (#3011)
Co-authored-by: aias00 <rokkki@163.com>
2025-01-23 18:40:59 +08:00
yunfan24andtomsun28 783bd8de89 [improve] Freeze the 'Operate' column on the right side of the list. (#3009)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-23 15:52:10 +08:00
Logicandtomsun28 d1115b44d1 [feature](alert) implement drag-and-drop functionality for alert templates (#3005)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-22 23:43:50 +08:00
NikhilMurugesanandaias00 68e37d613a [bugfix] fix some unit tests that failed to run (#3007)
Co-authored-by: aias00 <rokkki@163.com>
2025-01-22 23:41:08 +08:00
jonasHanhan 7db0df11ba [feature] Add alerter_zh_TW.properties configuration to adapt to mult… (#3004) 2025-01-21 16:30:48 +08:00
wanhaoandLogic e244bdc5a7 [feature] Complete multiple languages (#3002)
Co-authored-by: Logic <zqr10159@dromara.org>
2025-01-21 09:13:21 +08:00
tomsun28andLogic 0b7aa487f0 [webapp] bugfix edit monitor http query params error (#3001)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Logic <zqr10159@dromara.org>
2025-01-20 13:09:27 +08:00
PJ FanningandLogic 59d8764dfb [MINOR UPDATE] refactor base64 code to simplify the conversions (#2999)
Co-authored-by: Logic <zqr10159@dromara.org>
2025-01-20 10:13:52 +08:00
yunfan24 8a38a34965 [feature] Support monitoring for StarRocks FE and StarRocks BE. (#2997) 2025-01-20 10:03:18 +08:00
tomsun28 fd7e1b0e05 [bugfix] fix wrong http user-agent content (#2996) 2025-01-20 01:16:50 +08:00
PJ Fanning 5441838888 [MINOR UPDATE] fix more instances of unclosed Http Responses (#2995) 2025-01-19 22:45:28 +08:00
PJ FanningandLogic 56b1dcb502 [MINOR UPDATE] close http response in PrometheusAutoCollectImpl (#2994)
Signed-off-by: PJ Fanning <pjfanning@users.noreply.github.com>
Co-authored-by: Logic <zqr10159@dromara.org>
2025-01-19 17:56:16 +08:00
PJ Fanningandtomsun28 efbaf7feac [MINOR UPDATE] close HttpResponse in HttpCollectImpl (#2993)
Signed-off-by: PJ Fanning <pjfanning@users.noreply.github.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-19 17:48:21 +08:00
Logic 7003b8a150 [Improve]Add Copy token button (#2992) 2025-01-19 14:54:01 +08:00
wanhaoandaias00 aed524a88b [feature] Added multilingual defaults for forms (#2991)
Co-authored-by: aias00 <rokkki@163.com>
2025-01-18 20:54:57 +08:00
aias00 9b20ab8434 [type:fix] remove matomo ip (#2990) 2025-01-17 23:15:44 +08:00
5c39b98eaa [feature] Add privateKey passphrase config for linux monitor (#2982)
Co-authored-by: yinyijun <yinyijun6@mgtv.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: aias00 <rokkki@163.com>
2025-01-17 22:05:14 +08:00
aias00 43ac859939 [type:improve] fix dependencies vulnerabilites (#2989) 2025-01-17 20:31:57 +08:00
helei1030andtomsun28 b5c2eca819 [docs]added spark Chinese documents and changed the original spar… (#2987)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-17 10:41:19 +08:00
PJ Fanning cd57f51892 [MINOR UPDATE] improve xml parsing code (#2988)
Signed-off-by: PJ Fanning <pjfanning@users.noreply.github.com>
2025-01-17 09:17:57 +08:00
tomsun28 a33966de9f [improve] update i18n json stru and update search ui (#2986) 2025-01-16 20:46:32 +08:00
4ff9452926 [bugfix] fix hbase dashboard display anomalies and turn on HTTPS (#2980)
Co-authored-by: zhuoyuchen <>
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: Jast <shenghang@apache.org>
2025-01-15 18:20:21 +08:00
Jast 67da9bdbba [Feature] Support copy monitoring (#2981) 2025-01-15 17:03:53 +08:00
tomsun28 8bb4493b43 [bugfix] fix alert integration extern source bug (#2979) 2025-01-14 18:22:21 +08:00
ghyandshown 92edd53f8c [webapp] key-value-input component hover effect fixed (#2972)
Signed-off-by: ghy <ghyghoo8@qq.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-01-13 15:44:14 +08:00
d70ad75dcc [bugfix] Fix NullPointerException (#2849)
Signed-off-by: Ayu <127600988+ayu-v0@users.noreply.github.com>
Signed-off-by: Zhang Yuxuan <1373529784@qq.com>
Co-authored-by: Ayu <14359932+lin-Ayu0v0@user.noreply.gitee.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: Zhang Yuxuan <1373529784@qq.com>
2025-01-12 22:52:37 +08:00
tomsun28andLogic 2e76c12fe1 [feature] alert integration extern source (#2978)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: Logic <zqr10159@dromara.org>
2025-01-12 16:13:52 +08:00
Nick Guoandtomsun28 7e158eb778 [Improve] Add more test cases for Kafka junit tests (#2976)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-11 17:05:04 +08:00
Logicandtomsun28 db23c94882 [bugfix](warehouse) add metrics data update logic in memory storage (#2973)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-10 20:10:01 +08:00
yunfan24andaias00 e905f36de2 [bugfix] Fix the search functionality issue. (#2970)
Co-authored-by: aias00 <rokkki@163.com>
2025-01-10 19:36:22 +08:00
aias00andshown 037957dbe6 [feature] replace googletagmanager to matomo (#2877)
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-01-09 16:28:17 +08:00
liutianyouandtomsun28 01d18f7935 [Improve] add no popup option after next login (#2969)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-08 23:47:47 +08:00
88e350de1c [BUG] "Advanced Settings" is all white in dark mode (#2965)
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-08 23:43:27 +08:00
Nick Guoandtomsun28 07d22a8712 [Improve] Standardize Kafka metric naming (#2961)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-08 23:38:29 +08:00
tomsun28 7847fd78b7 [bufix] fix collector job scheduler error (#2966)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-01-08 21:44:42 +08:00
tomsun28 f7676ac8ca [improve] update alarm inhibit rule and alarm ui (#2957) 2025-01-08 10:04:07 +08:00
Jastandtomsun28 dd1cc700d9 [Imporve] Improve Huaweicloud (#2954)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-07 23:05:05 +08:00
Nick Guo d8dabe251a [Doc]Add English version of documentation for Kafka Consumer Detail (#2953) 2025-01-07 10:12:47 +08:00
Nick GuoandLogic f2e647d777 【Improve】adjust log level from INFO to WARN. (#2952)
Co-authored-by: Logic <zqr10159@dromara.org>
2025-01-06 13:50:09 +08:00
tomsun28 7bac0245a2 [improve] fix some alarm relate bug, update alarm center ui (#2951)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
2025-01-06 11:25:52 +08:00
Jast d6e5399121 [Improve]Modify Chinese comments (#2950) 2025-01-06 00:36:29 +08:00
doveLinandaias00 00076fc704 [Feature] Support customized JMX monitoring through the Factory Pattern. (#2932)
Co-authored-by: aias00 <rokkki@163.com>
2025-01-05 17:59:42 +08:00
yunfan24andtomsun28 4a3d61bd9e [doc] Add Supported MySQL Versions. (#2949)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-05 16:53:50 +08:00
Logic af59b487e4 [bugfix](db): optimize column update. (#2947) 2025-01-05 16:48:56 +08:00
4cd3c3c97f [alarm] refactor new alarm (#2902)
Signed-off-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: a-little-fool <2030509072@qq.com>
Co-authored-by: Logic <zqr10159@dromara.org>
2025-01-04 22:18:27 +08:00
69a21ffaa1 [refactor] refactoring methods replaceCryPlaceholder and replaceSmilingPlace (#2832)
Co-authored-by: Zhang Yuxuan <1373529784@qq.com>
Co-authored-by: aias00 <rokkki@163.com>
Co-authored-by: Calvin <naruse_shinji@163.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-04 19:54:05 +08:00
Jast 8ab71e672f [Improve]Improve e2e code (#2945) 2025-01-04 15:58:22 +08:00
7625a0b508 [home] updated navbar css #2928 (#2934)
Signed-off-by: Vedant7789 <147625492+Vedant7789@users.noreply.github.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: aias00 <rokkki@163.com>
2025-01-03 17:43:51 +08:00
dc963833e8 [improve] Refactor and Split the Message Notification Component. (#2924)
Co-authored-by: shown <yuluo08290126@gmail.com>
Co-authored-by: aias00 <rokkki@163.com>
2025-01-03 17:15:56 +08:00
Craaaaazy77andshown 87d4379efb [bugfix] Modify the doris_be.md document into an English version (#2936)
Signed-off-by: Craaaaazy77 <417989286@qq.com>
Co-authored-by: shown <yuluo08290126@gmail.com>
2025-01-03 14:40:42 +08:00
Simon Sigréandtomsun28 bffd7c1d4f [bugfix] Corrected case 'DashBoard' is a lower case 'B' (#2935)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-02 20:27:24 +08:00
yunfan24 ba21ef5cdb [improve] Improve the synchronization of the mute status. (#2927) 2025-01-02 18:59:44 +08:00
Simon Sigréandtomsun28 3bf237a4eb [feature] Adding CPU Temperature Check Into Default Ubuntu Checks (#2930)
Signed-off-by: Simon Sigré <simon.sigre@gmail.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-02 00:57:05 +08:00
ponfeeandtomsun28 19e7f128a3 [improve] optimize website navbar css(#2928) (#2929)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-01 14:49:57 +08:00
Jastandtomsun28 5c409d7512 [Improve] Optimize the e2e code structure (#2926)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-01 14:14:26 +08:00
6bf20ba21a [bugfix] Fixed the 'java.lang.UnsupportedOperationException' exception caused by getCurrentMetricsData (#2923)
Co-authored-by: bcxc <lixiaobaivvv@gmail.com>
Co-authored-by: tomsun28 <tomsun28@outlook.com>
2025-01-01 14:00:32 +08:00
Simon Sigré 8c9b1f3f92 [doc] Update app-windows_script.yml (#2922)
Signed-off-by: Simon Sigré <simon.sigre@gmail.com>
2025-01-01 00:28:34 +08:00
yunfan24 b3eb0083df [bugfix] Bug fix for alarm voice. (#2920) 2024-12-30 23:41:48 +08:00
LogicandJast e51accb3e6 [improve](warehouse): replace empty json object key with empty string (#2919)
Co-authored-by: Jast <shenghang@apache.org>
2024-12-30 20:08:33 +08:00
Logic a9e219811a [bugfix]: fix setColumns method in CollectRep class (#2918) 2024-12-30 19:58:00 +08:00
1626 changed files with 121319 additions and 27583 deletions
+369 -27
View File
@@ -267,7 +267,9 @@
"contributions": [
"code",
"bug",
"design"
"design",
"test",
"blog"
]
},
{
@@ -361,7 +363,9 @@
"contributions": [
"bug",
"code",
"doc"
"doc",
"test",
"design"
]
},
{
@@ -683,7 +687,8 @@
"contributions": [
"code",
"test",
"doc"
"doc",
"design"
]
},
{
@@ -797,7 +802,11 @@
"profile": "https://github.com/zqr10159",
"contributions": [
"doc",
"code"
"code",
"blog",
"bug",
"test",
"design"
]
},
{
@@ -889,7 +898,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/50475131?v=4",
"profile": "https://github.com/l646505418",
"contributions": [
"code"
"code",
"bug"
]
},
{
@@ -898,7 +908,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/78642589?v=4",
"profile": "http://www.carpewang.com",
"contributions": [
"code"
"code",
"bug"
]
},
{
@@ -1263,7 +1274,11 @@
"avatar_url": "https://avatars.githubusercontent.com/u/105542329?v=4",
"profile": "https://github.com/a-little-fool",
"contributions": [
"code"
"code",
"doc",
"blog",
"bug",
"design"
]
},
{
@@ -1326,7 +1341,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/67301054?v=4",
"profile": "http://www.jimmyqiao.top",
"contributions": [
"code"
"code",
"bug"
]
},
{
@@ -1419,7 +1435,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/28394742?v=4",
"profile": "https://github.com/Clownsw",
"contributions": [
"code"
"code",
"bug"
]
},
{
@@ -1430,7 +1447,9 @@
"contributions": [
"doc",
"code",
"design"
"design",
"bug",
"test"
]
},
{
@@ -1469,7 +1488,8 @@
"contributions": [
"code",
"design",
"doc"
"doc",
"bug"
]
},
{
@@ -1541,7 +1561,9 @@
"avatar_url": "https://avatars.githubusercontent.com/u/42080876?v=4",
"profile": "https://github.com/yqxxgh",
"contributions": [
"doc"
"doc",
"code",
"bug"
]
},
{
@@ -1586,7 +1608,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/55646681?v=4",
"profile": "https://github.com/starmilkxin",
"contributions": [
"code"
"code",
"bug"
]
},
{
@@ -1605,7 +1628,11 @@
"profile": "https://github.com/LiuTianyou",
"contributions": [
"code",
"doc"
"doc",
"bug",
"test",
"blog",
"design"
]
},
{
@@ -1651,9 +1678,11 @@
"avatar_url": "https://avatars.githubusercontent.com/u/71874373?v=4",
"profile": "https://github.com/gjjjj0101",
"contributions": [
"test",
"code",
"doc",
"design",
"test"
"bug"
]
},
{
@@ -1662,7 +1691,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/37864182?v=4",
"profile": "https://jangto.tistory.com/",
"contributions": [
"code"
"code",
"doc"
]
},
{
@@ -1672,7 +1702,10 @@
"profile": "https://crossoverjie.top/",
"contributions": [
"code",
"doc"
"doc",
"blog",
"test",
"design"
]
},
{
@@ -1708,7 +1741,9 @@
"avatar_url": "https://avatars.githubusercontent.com/u/8465969?v=4",
"profile": "https://github.com/xuziyang",
"contributions": [
"code"
"code",
"doc",
"bug"
]
},
{
@@ -1762,7 +1797,13 @@
"avatar_url": "https://avatars.githubusercontent.com/u/29418975?v=4",
"profile": "http://www.hadoop.wiki/",
"contributions": [
"code"
"code",
"ideas",
"doc",
"blog",
"bug",
"test",
"design"
]
},
{
@@ -1771,7 +1812,11 @@
"avatar_url": "https://avatars.githubusercontent.com/u/61108539?v=4",
"profile": "https://github.com/zuobiao-zhou",
"contributions": [
"code"
"code",
"doc",
"bug",
"blog",
"test"
]
},
{
@@ -1807,7 +1852,11 @@
"avatar_url": "https://avatars.githubusercontent.com/u/25810623?v=4",
"profile": "https://github.com/Aias00",
"contributions": [
"code"
"code",
"doc",
"bug",
"ideas",
"test"
]
},
{
@@ -1825,7 +1874,10 @@
"avatar_url": "https://avatars.githubusercontent.com/u/77964041?v=4",
"profile": "https://blog.csdn.net/qq_52397471",
"contributions": [
"code"
"code",
"bug",
"test",
"blog"
]
},
{
@@ -1834,7 +1886,9 @@
"avatar_url": "https://avatars.githubusercontent.com/u/118667222?v=4",
"profile": "https://github.com/Yanshuming1",
"contributions": [
"code"
"code",
"doc",
"bug"
]
},
{
@@ -1934,8 +1988,10 @@
"avatar_url": "https://avatars.githubusercontent.com/u/3371163?v=4",
"profile": "https://github.com/kerwin612",
"contributions": [
"design",
"code",
"design"
"doc",
"bug"
]
},
{
@@ -1962,7 +2018,9 @@
"avatar_url": "https://avatars.githubusercontent.com/u/69385076?v=4",
"profile": "https://github.com/pwallk",
"contributions": [
"code"
"code",
"doc",
"bug"
]
},
{
@@ -2007,7 +2065,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/83876361?v=4",
"profile": "https://github.com/keaifafafa",
"contributions": [
"code"
"code",
"bug"
]
},
{
@@ -2142,7 +2201,9 @@
"avatar_url": "https://avatars.githubusercontent.com/u/59016860?v=4",
"profile": "https://github.com/Rancho-7",
"contributions": [
"doc"
"doc",
"code",
"bug"
]
},
{
@@ -2159,9 +2220,290 @@
"name": "yunfan24",
"avatar_url": "https://avatars.githubusercontent.com/u/91836599?v=4",
"profile": "https://zzrl.cc/",
"contributions": [
"code",
"doc",
"bug",
"test",
"blog"
]
},
{
"login": "lctking",
"name": "nullwli",
"avatar_url": "https://avatars.githubusercontent.com/u/168249998?v=4",
"profile": "https://github.com/lctking",
"contributions": [
"code"
]
},
{
"login": "simonsigre",
"name": "Simon Sigré",
"avatar_url": "https://avatars.githubusercontent.com/u/14932913?v=4",
"profile": "https://simonsigre.com/",
"contributions": [
"doc",
"code"
]
},
{
"login": "ponfee",
"name": "ponfee",
"avatar_url": "https://avatars.githubusercontent.com/u/46117331?v=4",
"profile": "http://www.ponfee.cn/",
"contributions": [
"code"
]
},
{
"login": "Vedant7789",
"name": "Vedant7789",
"avatar_url": "https://avatars.githubusercontent.com/u/147625492?v=4",
"profile": "https://github.com/Vedant7789",
"contributions": [
"code"
]
},
{
"login": "Craaaaazy77",
"name": "Craaaaazy77",
"avatar_url": "https://avatars.githubusercontent.com/u/23025522?v=4",
"profile": "https://github.com/Craaaaazy77",
"contributions": [
"doc"
]
},
{
"login": "Suvrat1629",
"name": "Suvrat1629",
"avatar_url": "https://avatars.githubusercontent.com/u/140749446?v=4",
"profile": "https://github.com/Suvrat1629",
"contributions": [
"code"
]
},
{
"login": "ghyghoo8",
"name": "ghy",
"avatar_url": "https://avatars.githubusercontent.com/u/363129?v=4",
"profile": "http://ghyghoo8.github.io/",
"contributions": [
"code"
]
},
{
"login": "helei1030",
"name": "helei1030",
"avatar_url": "https://avatars.githubusercontent.com/u/11839080?v=4",
"profile": "https://github.com/helei1030",
"contributions": [
"doc"
]
},
{
"login": "pjfanning",
"name": "PJ Fanning",
"avatar_url": "https://avatars.githubusercontent.com/u/11783444?v=4",
"profile": "https://medium.com/@pjfanning",
"contributions": [
"code",
"bug",
"test"
]
},
{
"login": "MonsterChenzhuo",
"name": "monster",
"avatar_url": "https://avatars.githubusercontent.com/u/60029759?v=4",
"profile": "https://github.com/MonsterChenzhuo",
"contributions": [
"code"
]
},
{
"login": "MasamiYui",
"name": "Sherlock Yin",
"avatar_url": "https://avatars.githubusercontent.com/u/22274133?v=4",
"profile": "https://github.com/MasamiYui",
"contributions": [
"code",
"doc",
"bug"
]
},
{
"login": "wanhao23",
"name": "wanhao",
"avatar_url": "https://avatars.githubusercontent.com/u/29560961?v=4",
"profile": "https://github.com/wanhao23",
"contributions": [
"code",
"doc"
]
},
{
"login": "jonasHanhan",
"name": "jonasHanhan",
"avatar_url": "https://avatars.githubusercontent.com/u/130035609?v=4",
"profile": "https://github.com/jonasHanhan",
"contributions": [
"code"
]
},
{
"login": "NikhilMurugesan",
"name": "NikhilMurugesan",
"avatar_url": "https://avatars.githubusercontent.com/u/49281792?v=4",
"profile": "https://github.com/NikhilMurugesan",
"contributions": [
"code"
]
},
{
"login": "myangle1120",
"name": "myangle1120",
"avatar_url": "https://avatars.githubusercontent.com/u/19237013?v=4",
"profile": "https://github.com/myangle1120",
"contributions": [
"code"
]
},
{
"login": "yasminvo",
"name": "yasminvo",
"avatar_url": "https://avatars.githubusercontent.com/u/107528848?v=4",
"profile": "https://github.com/yasminvo",
"contributions": [
"code"
]
},
{
"login": "notbugggg",
"name": "不关银渐层的事哦",
"avatar_url": "https://avatars.githubusercontent.com/u/147966331?v=4",
"profile": "https://github.com/notbugggg",
"contributions": [
"code",
"bug"
]
},
{
"login": "yyahang",
"name": "yyahang",
"avatar_url": "https://avatars.githubusercontent.com/u/90464876?v=4",
"profile": "https://github.com/yyahang",
"contributions": [
"code"
]
},
{
"login": "JuJinPark",
"name": "jujin",
"avatar_url": "https://avatars.githubusercontent.com/u/44892459?v=4",
"profile": "https://github.com/JuJinPark",
"contributions": [
"code",
"doc",
"ideas",
"blog"
]
},
{
"login": "LL-LIN",
"name": "LL-LIN",
"avatar_url": "https://avatars.githubusercontent.com/u/43002118?v=4",
"profile": "https://github.com/LL-LIN",
"contributions": [
"code",
"bug"
]
},
{
"login": "bigcyy",
"name": "Yang Chen",
"avatar_url": "https://avatars.githubusercontent.com/u/73413979?v=4",
"profile": "https://bigcyy.github.io/",
"contributions": [
"code",
"doc",
"bug"
]
},
{
"login": "sarthakeash",
"name": "Sarthak Arora",
"avatar_url": "https://avatars.githubusercontent.com/u/74091160?v=4",
"profile": "https://github.com/sarthakeash",
"contributions": [
"code",
"doc"
]
},
{
"login": "PengJingzhao",
"name": "彭镜肇",
"avatar_url": "https://avatars.githubusercontent.com/u/97368949?v=4",
"profile": "https://github.com/PengJingzhao",
"contributions": [
"code"
]
},
{
"login": "gagaradio",
"name": "Walter Jia",
"avatar_url": "https://avatars.githubusercontent.com/u/18532370?v=4",
"profile": "https://github.com/gagaradio",
"contributions": [
"code"
]
},
{
"login": "boyucjz",
"name": "boyucjz",
"avatar_url": "https://avatars.githubusercontent.com/u/18730041?v=4",
"profile": "https://github.com/boyucjz",
"contributions": [
"code"
]
},
{
"login": "Cyanty",
"name": "Cyanty",
"avatar_url": "https://avatars.githubusercontent.com/u/153884653?v=4",
"profile": "https://github.com/Cyanty",
"contributions": [
"code",
"doc"
]
},
{
"login": "KevinLLF",
"name": "Jay丿167",
"avatar_url": "https://avatars.githubusercontent.com/u/85452733?v=4",
"profile": "https://github.com/KevinLLF",
"contributions": [
"code"
]
},
{
"login": "Duansg",
"name": "Duansg",
"avatar_url": "https://avatars.githubusercontent.com/u/112607719?v=4",
"profile": "https://github.com/Duansg",
"contributions": [
"doc"
]
},
{
"login": "xiaomizhou2",
"name": "zhangyaxi",
"avatar_url": "https://avatars.githubusercontent.com/u/47807926?v=4",
"profile": "https://github.com/xiaomizhou2",
"contributions": [
"code",
"test"
]
}
],
"contributorsPerLine": 7,
+3
View File
@@ -52,6 +52,9 @@ github:
required_pull_request_reviews:
dismiss_stale_reviews: true
required_approving_review_count: 1
# enable GitHub Dependabot to create PRs for security alerts but not for every dependency update
dependabot_alerts: true
dependabot_updates: false
notifications:
commits: notifications@hertzbeat.apache.org
issues: notifications@hertzbeat.apache.org
+2
View File
@@ -17,7 +17,9 @@
/home export-ignore
/hip export-ignore
/template-marketplace export-ignore
/.github export-ignore
/.idea export-ignore
/.devcontainer export-ignore
.gitattributes export-ignore
.gitignore export-ignore
+2 -1
View File
@@ -53,4 +53,5 @@ body:
validations:
required: false
- type: markdown
value: "Please read the [Contribution Guideline](https://hertzbeat.apache.org/docs/community/contribution) before submitting the PR"
attributes:
value: "Please read the [Contribution Guideline](https://hertzbeat.apache.org/docs/community/contribution) before submitting the PR"
+2 -2
View File
@@ -46,7 +46,7 @@ jobs:
- uses: ./script/ci/github-actions/setup-deps
- name: Build with Maven
run: mvn clean -B package -Prelease -Dmaven.test.skip=false --file pom.xml
run: mvnd clean -B package -Prelease -Dmaven.test.skip=false --file pom.xml
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4.0.1
@@ -73,7 +73,7 @@ jobs:
# upload application logs
- name: Upload logs & API test reports
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: always()
with:
name: hz-logs-${{ github.run_id }}
+2
View File
@@ -31,6 +31,8 @@ name: "CodeQL"
on:
schedule:
- cron: '21 13 * * 4'
push:
branches: [ action* ]
jobs:
analyze:
+4 -6
View File
@@ -19,7 +19,7 @@ name: DOC CI
on:
push:
branches: [ master, dev ]
branches: [ master, dev, action* ]
paths:
- 'home/**'
pull_request:
@@ -49,11 +49,9 @@ jobs:
- name: Dead Link Check
run: |
sudo npm install -g markdown-link-check@3.8.7
for file in $(find ./home -name "*.md"); do
if ! grep -Fxq "$file" ./script/ci/exclude_files.txt; then
markdown-link-check -c ./script/ci/link_check.json -q "$file"
fi
done
find ./home -name "*.md" > all_md_files.txt
grep -vFf ./script/ci/exclude_files.txt all_md_files.txt > to_check.txt
xargs -P 8 -a to_check.txt -I{} markdown-link-check -c ./script/ci/link_check.json -q "{}"
- name: NPM INSTALL
working-directory: home
+4 -3
View File
@@ -17,7 +17,8 @@
name: 'HertzBeat Doc Pdf Builder'
on:
page_build
push:
branches: [ page_build* ]
jobs:
build:
@@ -39,7 +40,7 @@ jobs:
run: npx docusaurus-prince-pdf -u https://hertzbeat.apache.org/docs --output docs-en.pdf
- name: Upload results
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: docs-cn-pdf
path: docs-cn.pdf
@@ -47,7 +48,7 @@ jobs:
retention-days: 1
- name: Upload results
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: docs-en-pdf
path: docs-en.pdf
+1 -1
View File
@@ -22,7 +22,7 @@ name: Frontend CI
on:
push:
branches: [ master, dev ]
branches: [ master, dev, action* ]
paths:
- 'web-app/**'
pull_request:
+1 -1
View File
@@ -22,7 +22,7 @@ name: License Checker
on:
push:
branches: [ master, dev ]
branches: [ master, dev, action* ]
pull_request:
branches: [ master, dev ]
+53
View File
@@ -0,0 +1,53 @@
# 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.
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Monitor E2E Test
on:
schedule:
# trigger at 01:00 everyday
- cron: '0 1 * * *'
push:
branches: [ action* ]
jobs:
check-license-header:
name: Monitor E2E Test
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: ./script/ci/github-actions/setup-deps
- name: Build with Maven
run: mvn clean -B package -Prelease -Dmaven.test.skip=true --file pom.xml
- name: Build Image
uses: docker/build-push-action@v3
with:
context: ./dist
file: ./script/docker/server/Dockerfile
push: false
tags: apache/hertzbeat:test
- name: Run K8s Monitor E2E Test
run: |
sudo curl -L https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
sudo chmod u+x /usr/local/bin/docker-compose
cd e2e/k8s
sudo docker-compose version
sudo docker-compose up --exit-code-from testing --remove-orphans
+1 -1
View File
@@ -42,7 +42,7 @@ jobs:
run: |
mvn clean install
mvn clean package -Prelease -DskipTests
cd collector
cd hertzbeat-collector
mvn clean package -Pcluster -DskipTests
- uses: docker/setup-qemu-action@v3
+5 -3
View File
@@ -6,13 +6,13 @@ Thumbs.db
build/
out/
micronaut-cli.yml
.mvn/
mvnw
mvnw.bat
*.log
package-lock.json
*.zip
jdk/
data/
!/e2e/**/data/
### STS ###
.apt_generated
@@ -54,3 +54,5 @@ node_modules
application-dev.yml
application-mysql.yml
application-pg.yml
/package.json
/yarn.lock
+7
View File
@@ -0,0 +1,7 @@
FROM gitpod/workspace-full
USER gitpod
RUN bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && \
sdk install java 17.0.3-ms && \
sdk default java 17.0.3-ms"
+3 -2
View File
@@ -1,3 +1,6 @@
image:
file: .gitpod.Dockerfile
tasks:
- name: Run backend
@@ -15,8 +18,6 @@ tasks:
- name: Setup backend
init: |
sdk install java 17.0.11.fx-zulu < /dev/null
sdk default java 17.0.11.fx-zulu < /dev/null
mvn clean install -DskipTests
command: |
gp sync-done setup-backend
+5 -4
View File
@@ -15,6 +15,7 @@
// limitations under the License.
//
{
"globs": ["home/**/*.md"],
"config": {
"default": true,
"MD001": true,
@@ -39,9 +40,9 @@
"MD047": true,
"MD052": true
},
"ignore": [
"node_modules/",
"target/",
"dist/"
"ignores": [
"**/node_modules/**",
"**/target/**",
"**/dist/**"
]
}
+17
View File
@@ -0,0 +1,17 @@
# 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.
wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
+1 -1
View File
@@ -1,5 +1,5 @@
Apache HertzBeat (incubating)
Copyright 2024 The Apache Software Foundation
Copyright 2024-2025 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
+75 -34
View File
@@ -4,21 +4,23 @@
</a>
</p>
<h4 align="center">
<a href="README.md">English Document</a> | <a href="README_CN.md">中文文档</a>
</h4>
<p align="center">
<b>Readme</b>:
<b><a href="README.md">English</a></b> | <a href="README_CN.md">中文</a> | <a href="README_JP.md">日本語</a>
</p>
> A real-time monitoring system with agentless, performance cluster, prometheus-compatible, custom monitoring and status page building capabilities.
[![Discord](https://img.shields.io/badge/Chat-Discord-7289DA?logo=discord)](https://discord.gg/Fb6M73htGr)
[![Reddit](https://img.shields.io/badge/Reddit-Community-7289DA?logo=reddit)](https://www.reddit.com/r/hertzbeat/)
[![Twitter](https://img.shields.io/twitter/follow/hertzbeat1024?logo=twitter)](https://twitter.com/hertzbeat1024)
[![Twitter](https://img.shields.io/twitter/follow/hertzbeat1024?logo=twitter)](https://x.com/hertzbeat1024)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8139/badge)](https://www.bestpractices.dev/projects/8139)
[![codecov](https://codecov.io/gh/apache/HertzBeat/branch/master/graph/badge.svg)](https://app.codecov.io/gh/apache/hertzbeat)
[![Docker Pulls](https://img.shields.io/docker/pulls/apache/hertzbeat?style=%20for-the-badge&logo=docker&label=DockerHub%20Download)](https://hub.docker.com/r/apache/hertzbeat)
[![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/hertzbeat)](https://artifacthub.io/packages/search?repo=hertzbeat)
[![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UCri75zfWX0GHqJFPENEbLow?logo=youtube&label=YouTube%20Channel)](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/apache/hertzbeat)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/apache/hertzbeat)
**Home: [hertzbeat.apache.org](https://hertzbeat.apache.org)**
**Email: <a href="mailto:dev-subscribe@hertzbeat.apache.org">Mail to `dev-subscribe@hertzbeat.apache.org`</a> to subscribe mailing lists**
@@ -222,7 +224,7 @@ Thanks to these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="http://mroldx.xyz/"><img src="https://avatars.githubusercontent.com/u/34847828?v=4?s=100" width="100px;" alt="mroldx"/><br /><sub><b>mroldx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mroldx" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/woshiniusange"><img src="https://avatars.githubusercontent.com/u/91513022?v=4?s=100" width="100px;" alt="woshiniusange"/><br /><sub><b>woshiniusange</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=woshiniusange" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://vampireachao.github.io/"><img src="https://avatars.githubusercontent.com/u/52746628?v=4?s=100" width="100px;" alt="VampireAchao"/><br /><sub><b>VampireAchao</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=VampireAchao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ceilzcx"><img src="https://avatars.githubusercontent.com/u/48920254?v=4?s=100" width="100px;" alt="zcx"/><br /><sub><b>zcx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Ceilzcx" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACeilzcx" title="Bug reports">🐛</a> <a href="#design-Ceilzcx" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ceilzcx"><img src="https://avatars.githubusercontent.com/u/48920254?v=4?s=100" width="100px;" alt="zcx"/><br /><sub><b>zcx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Ceilzcx" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACeilzcx" title="Bug reports">🐛</a> <a href="#design-Ceilzcx" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=Ceilzcx" title="Tests">⚠️</a> <a href="#blog-Ceilzcx" title="Blogposts">📝</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CharlieXCL"><img src="https://avatars.githubusercontent.com/u/91540487?v=4?s=100" width="100px;" alt="CharlieXCL"/><br /><sub><b>CharlieXCL</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=CharlieXCL" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Privauto"><img src="https://avatars.githubusercontent.com/u/36581456?v=4?s=100" width="100px;" alt="Privauto"/><br /><sub><b>Privauto</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Privauto" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Privauto" title="Documentation">📖</a></td>
</tr>
@@ -236,7 +238,7 @@ Thanks to these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://www.zhihu.com/people/kevinbauer"><img src="https://avatars.githubusercontent.com/u/28581579?v=4?s=100" width="100px;" alt="Kevin Huang"/><br /><sub><b>Kevin Huang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=kevinhuangwl" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TJxiaobao"><img src="https://avatars.githubusercontent.com/u/85919258?v=4?s=100" width="100px;" alt="铁甲小宝"/><br /><sub><b>铁甲小宝</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3ATJxiaobao" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TJxiaobao"><img src="https://avatars.githubusercontent.com/u/85919258?v=4?s=100" width="100px;" alt="铁甲小宝"/><br /><sub><b>铁甲小宝</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3ATJxiaobao" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Tests">⚠️</a> <a href="#design-TJxiaobao" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jack-123-power"><img src="https://avatars.githubusercontent.com/u/84333501?v=4?s=100" width="100px;" alt="Captain Jack"/><br /><sub><b>Captain Jack</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Jack-123-power" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/haibo-duan"><img src="https://avatars.githubusercontent.com/u/7974845?v=4?s=100" width="100px;" alt="haibo.duan"/><br /><sub><b>haibo.duan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=haibo-duan" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=haibo-duan" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/assassinfym"><img src="https://avatars.githubusercontent.com/u/15188754?v=4?s=100" width="100px;" alt="assassin"/><br /><sub><b>assassin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3Aassassinfym" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=assassinfym" title="Code">💻</a></td>
@@ -278,7 +280,7 @@ Thanks to these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://wjl110.xyz/"><img src="https://avatars.githubusercontent.com/u/53851034?v=4?s=100" width="100px;" alt="wjl110"/><br /><sub><b>wjl110</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wjl110" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ngyhd"><img src="https://avatars.githubusercontent.com/u/29095207?v=4?s=100" width="100px;" alt="Sean"/><br /><sub><b>Sean</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ngyhd" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Daydreamer-ia"><img src="https://avatars.githubusercontent.com/u/83362909?v=4?s=100" width="100px;" alt="chenyiqin"/><br /><sub><b>chenyiqin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Daydreamer-ia" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Daydreamer-ia" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hudongdong129"><img src="https://avatars.githubusercontent.com/u/34374227?v=4?s=100" width="100px;" alt="hudongdong129"/><br /><sub><b>hudongdong129</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hudongdong129"><img src="https://avatars.githubusercontent.com/u/34374227?v=4?s=100" width="100px;" alt="hudongdong129"/><br /><sub><b>hudongdong129</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Documentation">📖</a> <a href="#design-hudongdong129" title="Design">🎨</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TherChenYang"><img src="https://avatars.githubusercontent.com/u/124348939?v=4?s=100" width="100px;" alt="TherChenYang"/><br /><sub><b>TherChenYang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=TherChenYang" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=TherChenYang" title="Tests">⚠️</a></td>
@@ -294,7 +296,7 @@ Thanks to these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/baiban114"><img src="https://avatars.githubusercontent.com/u/59152619?v=4?s=100" width="100px;" alt="TableRow"/><br /><sub><b>TableRow</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=baiban114" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=baiban114" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ByteIDance"><img src="https://avatars.githubusercontent.com/u/100207562?v=4?s=100" width="100px;" alt="ByteIDance"/><br /><sub><b>ByteIDance</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ByteIDance" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mangel2002"><img src="https://avatars.githubusercontent.com/u/9348020?v=4?s=100" width="100px;" alt="Jangfe"/><br /><sub><b>Jangfe</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mangel2002" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zqr10159"><img src="https://avatars.githubusercontent.com/u/30048352?v=4?s=100" width="100px;" alt="zqr10159"/><br /><sub><b>zqr10159</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zqr10159"><img src="https://avatars.githubusercontent.com/u/30048352?v=4?s=100" width="100px;" alt="zqr10159"/><br /><sub><b>zqr10159</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Code">💻</a> <a href="#blog-zqr10159" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Azqr10159" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Tests">⚠️</a> <a href="#design-zqr10159" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vinci-897"><img src="https://avatars.githubusercontent.com/u/55838224?v=4?s=100" width="100px;" alt="vinci"/><br /><sub><b>vinci</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=vinci-897" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=vinci-897" title="Documentation">📖</a> <a href="#design-vinci-897" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/js110"><img src="https://avatars.githubusercontent.com/u/51191863?v=4?s=100" width="100px;" alt="js110"/><br /><sub><b>js110</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=js110" title="Code">💻</a></td>
</tr>
@@ -308,8 +310,8 @@ Thanks to these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZangJuxy"><img src="https://avatars.githubusercontent.com/u/71380295?v=4?s=100" width="100px;" alt="ZangJuxy"/><br /><sub><b>ZangJuxy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZangJuxy" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/l646505418"><img src="https://avatars.githubusercontent.com/u/50475131?v=4?s=100" width="100px;" alt="l646505418"/><br /><sub><b>l646505418</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=l646505418" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.carpewang.com"><img src="https://avatars.githubusercontent.com/u/78642589?v=4?s=100" width="100px;" alt="Carpe-Wang"/><br /><sub><b>Carpe-Wang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Carpe-Wang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/l646505418"><img src="https://avatars.githubusercontent.com/u/50475131?v=4?s=100" width="100px;" alt="l646505418"/><br /><sub><b>l646505418</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=l646505418" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Al646505418" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.carpewang.com"><img src="https://avatars.githubusercontent.com/u/78642589?v=4?s=100" width="100px;" alt="Carpe-Wang"/><br /><sub><b>Carpe-Wang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Carpe-Wang" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACarpe-Wang" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/moshu023"><img src="https://avatars.githubusercontent.com/u/48593205?v=4?s=100" width="100px;" alt="莫枢"/><br /><sub><b>莫枢</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=moshu023" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/huangcanda"><img src="https://avatars.githubusercontent.com/u/4470566?v=4?s=100" width="100px;" alt="huangcanda"/><br /><sub><b>huangcanda</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=huangcanda" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.zrkizzy.com"><img src="https://avatars.githubusercontent.com/u/85340613?v=4?s=100" width="100px;" alt="世纪末的架构师"/><br /><sub><b>世纪末的架构师</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Architect-Java" title="Code">💻</a></td>
@@ -359,7 +361,7 @@ Thanks to these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lisongning"><img src="https://avatars.githubusercontent.com/u/93140178?v=4?s=100" width="100px;" alt="lisongning"/><br /><sub><b>lisongning</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lisongning" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/YutingNie"><img src="https://avatars.githubusercontent.com/u/104416402?v=4?s=100" width="100px;" alt="YutingNie"/><br /><sub><b>YutingNie</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=YutingNie" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=YutingNie" title="Documentation">📖</a> <a href="#design-YutingNie" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mikezzb"><img src="https://avatars.githubusercontent.com/u/23418428?v=4?s=100" width="100px;" alt="Mike Zhou"/><br /><sub><b>Mike Zhou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mikezzb" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=mikezzb" title="Documentation">📖</a> <a href="#design-mikezzb" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/a-little-fool"><img src="https://avatars.githubusercontent.com/u/105542329?v=4?s=100" width="100px;" alt="小笨蛋"/><br /><sub><b>小笨蛋</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=a-little-fool" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/a-little-fool"><img src="https://avatars.githubusercontent.com/u/105542329?v=4?s=100" width="100px;" alt="小笨蛋"/><br /><sub><b>小笨蛋</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=a-little-fool" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=a-little-fool" title="Documentation">📖</a> <a href="#blog-a-little-fool" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Aa-little-fool" title="Bug reports">🐛</a> <a href="#design-a-little-fool" title="Design">🎨</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/littlezhongzer"><img src="https://avatars.githubusercontent.com/u/33685289?v=4?s=100" width="100px;" alt="littlezhongzer"/><br /><sub><b>littlezhongzer</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=littlezhongzer" title="Code">💻</a></td>
@@ -368,7 +370,7 @@ Thanks to these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/XimfengYao"><img src="https://avatars.githubusercontent.com/u/17541537?v=4?s=100" width="100px;" alt="姚贤丰"/><br /><sub><b>姚贤丰</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=XimfengYao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LINGLUOJUN"><img src="https://avatars.githubusercontent.com/u/16778977?v=4?s=100" width="100px;" alt="lingluojun"/><br /><sub><b>lingluojun</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LINGLUOJUN" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.luelueking.com"><img src="https://avatars.githubusercontent.com/u/93204032?v=4?s=100" width="100px;" alt="1ue"/><br /><sub><b>1ue</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=luelueking" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.jimmyqiao.top"><img src="https://avatars.githubusercontent.com/u/67301054?v=4?s=100" width="100px;" alt="qyaaaa"/><br /><sub><b>qyaaaa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=qyaaaa" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.jimmyqiao.top"><img src="https://avatars.githubusercontent.com/u/67301054?v=4?s=100" width="100px;" alt="qyaaaa"/><br /><sub><b>qyaaaa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=qyaaaa" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Aqyaaaa" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://novohit.top"><img src="https://avatars.githubusercontent.com/u/101090395?v=4?s=100" width="100px;" alt="novohit"/><br /><sub><b>novohit</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=novohit" title="Code">💻</a></td>
@@ -382,14 +384,14 @@ Thanks to these wonderful people, welcome to join us:
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/1036664317"><img src="https://avatars.githubusercontent.com/u/7696697?v=4?s=100" width="100px;" alt="moghn"/><br /><sub><b>moghn</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=1036664317" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xiaoguolong"><img src="https://avatars.githubusercontent.com/u/33684988?v=4?s=100" width="100px;" alt="xiaoguolong"/><br /><sub><b>xiaoguolong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xiaoguolong" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Clownsw"><img src="https://avatars.githubusercontent.com/u/28394742?v=4?s=100" width="100px;" alt="Smliexx"/><br /><sub><b>Smliexx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Clownsw" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Calvin979"><img src="https://avatars.githubusercontent.com/u/131688897?v=4?s=100" width="100px;" alt="Naruse"/><br /><sub><b>Naruse</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Code">💻</a> <a href="#design-Calvin979" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Clownsw"><img src="https://avatars.githubusercontent.com/u/28394742?v=4?s=100" width="100px;" alt="Smliexx"/><br /><sub><b>Smliexx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Clownsw" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AClownsw" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Calvin979"><img src="https://avatars.githubusercontent.com/u/131688897?v=4?s=100" width="100px;" alt="Naruse"/><br /><sub><b>Naruse</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Code">💻</a> <a href="#design-Calvin979" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACalvin979" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bbelide2"><img src="https://avatars.githubusercontent.com/u/26840796?v=4?s=100" width="100px;" alt="Bala Sukesh"/><br /><sub><b>Bala Sukesh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bbelide2" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jinyaoMa"><img src="https://avatars.githubusercontent.com/u/25066570?v=4?s=100" width="100px;" alt="Jinyao Ma"/><br /><sub><b>Jinyao Ma</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jinyaoMa" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://linuxsuren.github.io/open-source-best-practice/"><img src="https://avatars.githubusercontent.com/u/1450685?v=4?s=100" width="100px;" alt="Rick"/><br /><sub><b>Rick</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LinuxSuRen" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=LinuxSuRen" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZY945"><img src="https://avatars.githubusercontent.com/u/74083801?v=4?s=100" width="100px;" alt="东风"/><br /><sub><b>东风</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Code">💻</a> <a href="#design-ZY945" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZY945"><img src="https://avatars.githubusercontent.com/u/74083801?v=4?s=100" width="100px;" alt="东风"/><br /><sub><b>东风</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Code">💻</a> <a href="#design-ZY945" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AZY945" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/prolevel1"><img src="https://avatars.githubusercontent.com/u/51995525?v=4?s=100" width="100px;" alt="sonam singh"/><br /><sub><b>sonam singh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=prolevel1" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZhangZixuan1994"><img src="https://avatars.githubusercontent.com/u/20011653?v=4?s=100" width="100px;" alt="ZhangZixuan1994"/><br /><sub><b>ZhangZixuan1994</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZhangZixuan1994" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hurenjie1"><img src="https://avatars.githubusercontent.com/u/40120355?v=4?s=100" width="100px;" alt="SHIG"/><br /><sub><b>SHIG</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hurenjie1" title="Code">💻</a></td>
@@ -399,29 +401,29 @@ Thanks to these wonderful people, welcome to join us:
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/avvCode"><img src="https://avatars.githubusercontent.com/u/113538532?v=4?s=100" width="100px;" alt="avv"/><br /><sub><b>avv</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=avvCode" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yqxxgh"><img src="https://avatars.githubusercontent.com/u/42080876?v=4?s=100" width="100px;" alt="yqxxgh"/><br /><sub><b>yqxxgh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yqxxgh" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yqxxgh"><img src="https://avatars.githubusercontent.com/u/42080876?v=4?s=100" width="100px;" alt="yqxxgh"/><br /><sub><b>yqxxgh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yqxxgh" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=yqxxgh" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayqxxgh" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CharlieShi46"><img src="https://avatars.githubusercontent.com/u/149798885?v=4?s=100" width="100px;" alt="CharlieShi46"/><br /><sub><b>CharlieShi46</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=CharlieShi46" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Nctllnty"><img src="https://avatars.githubusercontent.com/u/33241818?v=4?s=100" width="100px;" alt="Nctllnty"/><br /><sub><b>Nctllnty</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Nctllnty" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Wang-Yonghao"><img src="https://avatars.githubusercontent.com/u/48146606?v=4?s=100" width="100px;" alt="Wang-Yonghao"/><br /><sub><b>Wang-Yonghao</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Wang-Yonghao" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.yuque.com/dudiao/yy"><img src="https://avatars.githubusercontent.com/u/38355949?v=4?s=100" width="100px;" alt="读钓"/><br /><sub><b>读钓</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=dudiao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starmilkxin"><img src="https://avatars.githubusercontent.com/u/55646681?v=4?s=100" width="100px;" alt="Xin"/><br /><sub><b>Xin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=starmilkxin" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starmilkxin"><img src="https://avatars.githubusercontent.com/u/55646681?v=4?s=100" width="100px;" alt="Xin"/><br /><sub><b>Xin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=starmilkxin" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Astarmilkxin" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/handy-git"><img src="https://avatars.githubusercontent.com/u/32837980?v=4?s=100" width="100px;" alt="handy"/><br /><sub><b>handy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=handy-git" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LiuTianyou"><img src="https://avatars.githubusercontent.com/u/30208283?v=4?s=100" width="100px;" alt="LiuTianyou"/><br /><sub><b>LiuTianyou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LiuTianyou"><img src="https://avatars.githubusercontent.com/u/30208283?v=4?s=100" width="100px;" alt="LiuTianyou"/><br /><sub><b>LiuTianyou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ALiuTianyou" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Tests">⚠️</a> <a href="#blog-LiuTianyou" title="Blogposts">📝</a> <a href="#design-LiuTianyou" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/WinterKi1ler"><img src="https://avatars.githubusercontent.com/u/160592092?v=4?s=100" width="100px;" alt="WinterKi1ler"/><br /><sub><b>WinterKi1ler</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=WinterKi1ler" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://sharehoo.cn/"><img src="https://avatars.githubusercontent.com/u/45377370?v=4?s=100" width="100px;" alt="miki"/><br /><sub><b>miki</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=miki-hmt" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://codeflex.substack.com/"><img src="https://avatars.githubusercontent.com/u/85513042?v=4?s=100" width="100px;" alt="Keshav Carpenter"/><br /><sub><b>Keshav Carpenter</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=alpha951" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=alpha951" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/makechoicenow"><img src="https://avatars.githubusercontent.com/u/9911918?v=4?s=100" width="100px;" alt="makechoicenow"/><br /><sub><b>makechoicenow</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=makechoicenow" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gjjjj0101"><img src="https://avatars.githubusercontent.com/u/71874373?v=4?s=100" width="100px;" alt="Gao Jian"/><br /><sub><b>Gao Jian</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Code">💻</a> <a href="#design-gjjjj0101" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gjjjj0101"><img src="https://avatars.githubusercontent.com/u/71874373?v=4?s=100" width="100px;" alt="Gao Jian"/><br /><sub><b>Gao Jian</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Documentation">📖</a> <a href="#design-gjjjj0101" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Agjjjj0101" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://jangto.tistory.com/"><img src="https://avatars.githubusercontent.com/u/37864182?v=4?s=100" width="100px;" alt="Hyeon Sung"/><br /><sub><b>Hyeon Sung</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=dukbong" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://crossoverjie.top/"><img src="https://avatars.githubusercontent.com/u/15684156?v=4?s=100" width="100px;" alt="crossoverJie"/><br /><sub><b>crossoverJie</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://jangto.tistory.com/"><img src="https://avatars.githubusercontent.com/u/37864182?v=4?s=100" width="100px;" alt="Hyeon Sung"/><br /><sub><b>Hyeon Sung</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=dukbong" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=dukbong" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://crossoverjie.top/"><img src="https://avatars.githubusercontent.com/u/15684156?v=4?s=100" width="100px;" alt="crossoverJie"/><br /><sub><b>crossoverJie</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Documentation">📖</a> <a href="#blog-crossoverJie" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Tests">⚠️</a> <a href="#design-crossoverJie" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PeixyJ"><img src="https://avatars.githubusercontent.com/u/45998593?v=4?s=100" width="100px;" alt="PeixyJ"/><br /><sub><b>PeixyJ</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=PeixyJ" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Hi-Mr-Wind"><img src="https://avatars.githubusercontent.com/u/85803831?v=4?s=100" width="100px;" alt="风如歌"/><br /><sub><b>风如歌</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Hi-Mr-Wind" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MananPoojara"><img src="https://avatars.githubusercontent.com/u/104253184?v=4?s=100" width="100px;" alt="Manan Pujara"/><br /><sub><b>Manan Pujara</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MananPoojara" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xuziyang"><img src="https://avatars.githubusercontent.com/u/8465969?v=4?s=100" width="100px;" alt="xuziyang"/><br /><sub><b>xuziyang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xuziyang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xuziyang"><img src="https://avatars.githubusercontent.com/u/8465969?v=4?s=100" width="100px;" alt="xuziyang"/><br /><sub><b>xuziyang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xuziyang" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=xuziyang" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Axuziyang" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lwqzz"><img src="https://avatars.githubusercontent.com/u/62584513?v=4?s=100" width="100px;" alt="lwqzz"/><br /><sub><b>lwqzz</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lwqzz" title="Code">💻</a></td>
</tr>
<tr>
@@ -429,17 +431,17 @@ Thanks to these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tomorrowshipyltm"><img src="https://avatars.githubusercontent.com/u/61336903?v=4?s=100" width="100px;" alt="tomorrowshipyltm"/><br /><sub><b>tomorrowshipyltm</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=tomorrowshipyltm" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/15613060203"><img src="https://avatars.githubusercontent.com/u/41351615?v=4?s=100" width="100px;" alt="栗磊"/><br /><sub><b>栗磊</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=15613060203" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Alanxtl"><img src="https://avatars.githubusercontent.com/u/25652981?v=4?s=100" width="100px;" alt="Alan"/><br /><sub><b>Alan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Alanxtl" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.hadoop.wiki/"><img src="https://avatars.githubusercontent.com/u/29418975?v=4?s=100" width="100px;" alt="Jast"/><br /><sub><b>Jast</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zuobiao-zhou"><img src="https://avatars.githubusercontent.com/u/61108539?v=4?s=100" width="100px;" alt="Zhang Yuxuan"/><br /><sub><b>Zhang Yuxuan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.hadoop.wiki/"><img src="https://avatars.githubusercontent.com/u/29418975?v=4?s=100" width="100px;" alt="Jast"/><br /><sub><b>Jast</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Code">💻</a> <a href="#ideas-zhangshenghang" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Documentation">📖</a> <a href="#blog-zhangshenghang" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Azhangshenghang" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Tests">⚠️</a> <a href="#design-zhangshenghang" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zuobiao-zhou"><img src="https://avatars.githubusercontent.com/u/61108539?v=4?s=100" width="100px;" alt="Zhang Yuxuan"/><br /><sub><b>Zhang Yuxuan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Azuobiao-zhou" title="Bug reports">🐛</a> <a href="#blog-zuobiao-zhou" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Pzz-2021"><img src="https://avatars.githubusercontent.com/u/118056735?v=4?s=100" width="100px;" alt="P.P."/><br /><sub><b>P.P.</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Pzz-2021" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LLP2333"><img src="https://avatars.githubusercontent.com/u/61670545?v=4?s=100" width="100px;" alt="llp2333"/><br /><sub><b>llp2333</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LLP2333" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/HeartLinked"><img src="https://avatars.githubusercontent.com/u/78212101?v=4?s=100" width="100px;" alt="feiyang li"/><br /><sub><b>feiyang li</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=HeartLinked" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Aias00"><img src="https://avatars.githubusercontent.com/u/25810623?v=4?s=100" width="100px;" alt="aias00"/><br /><sub><b>aias00</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Aias00"><img src="https://avatars.githubusercontent.com/u/25810623?v=4?s=100" width="100px;" alt="aias00"/><br /><sub><b>aias00</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AAias00" title="Bug reports">🐛</a> <a href="#ideas-Aias00" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/westboy"><img src="https://avatars.githubusercontent.com/u/6385565?v=4?s=100" width="100px;" alt="Jin"/><br /><sub><b>Jin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=westboy" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://blog.csdn.net/qq_52397471"><img src="https://avatars.githubusercontent.com/u/77964041?v=4?s=100" width="100px;" alt="YuLuo"/><br /><sub><b>YuLuo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yuluo-yx" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Yanshuming1"><img src="https://avatars.githubusercontent.com/u/118667222?v=4?s=100" width="100px;" alt="linDong"/><br /><sub><b>linDong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Yanshuming1" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://blog.csdn.net/qq_52397471"><img src="https://avatars.githubusercontent.com/u/77964041?v=4?s=100" width="100px;" alt="YuLuo"/><br /><sub><b>YuLuo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yuluo-yx" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayuluo-yx" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=yuluo-yx" title="Tests">⚠️</a> <a href="#blog-yuluo-yx" title="Blogposts">📝</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Yanshuming1"><img src="https://avatars.githubusercontent.com/u/118667222?v=4?s=100" width="100px;" alt="linDong"/><br /><sub><b>linDong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Yanshuming1" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Yanshuming1" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AYanshuming1" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lwjxy"><img src="https://avatars.githubusercontent.com/u/52726400?v=4?s=100" width="100px;" alt="lwjxy"/><br /><sub><b>lwjxy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lwjxy" title="Code">💻</a></td>
</tr>
<tr>
@@ -454,17 +456,17 @@ Thanks to these wonderful people, welcome to join us:
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ileonli"><img src="https://avatars.githubusercontent.com/u/45332412?v=4?s=100" width="100px;" alt="Leon Li"/><br /><sub><b>Leon Li</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ileonli" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://fnil.net/"><img src="https://avatars.githubusercontent.com/u/14142?v=4?s=100" width="100px;" alt="dennis zhuang"/><br /><sub><b>dennis zhuang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=killme2008" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kerwin612"><img src="https://avatars.githubusercontent.com/u/3371163?v=4?s=100" width="100px;" alt="Kerwin Bryant"/><br /><sub><b>Kerwin Bryant</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=kerwin612" title="Code">💻</a> <a href="#design-kerwin612" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kerwin612"><img src="https://avatars.githubusercontent.com/u/3371163?v=4?s=100" width="100px;" alt="Kerwin Bryant"/><br /><sub><b>Kerwin Bryant</b></sub></a><br /><a href="#design-kerwin612" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=kerwin612" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=kerwin612" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Akerwin612" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ShineDevelopment"><img src="https://avatars.githubusercontent.com/u/59306780?v=4?s=100" width="100px;" alt="daixianglong"/><br /><sub><b>daixianglong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ShineDevelopment" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mchgood"><img src="https://avatars.githubusercontent.com/u/38482005?v=4?s=100" width="100px;" alt="mchgood"/><br /><sub><b>mchgood</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mchgood" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pwallk"><img src="https://avatars.githubusercontent.com/u/69385076?v=4?s=100" width="100px;" alt="kangli"/><br /><sub><b>kangli</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=pwallk" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pwallk"><img src="https://avatars.githubusercontent.com/u/69385076?v=4?s=100" width="100px;" alt="kangli"/><br /><sub><b>kangli</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=pwallk" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=pwallk" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Apwallk" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cdphantom"><img src="https://avatars.githubusercontent.com/u/12674795?v=4?s=100" width="100px;" alt="cdphantom"/><br /><sub><b>cdphantom</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=cdphantom" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/asd108908382"><img src="https://avatars.githubusercontent.com/u/77717999?v=4?s=100" width="100px;" alt="jiawei.guo"/><br /><sub><b>jiawei.guo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=asd108908382" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/QBH-insist"><img src="https://avatars.githubusercontent.com/u/39401478?v=4?s=100" width="100px;" alt="QBH-insist"/><br /><sub><b>QBH-insist</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=QBH-insist" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jiangsh-ui"><img src="https://avatars.githubusercontent.com/u/86990361?v=4?s=100" width="100px;" alt="jiangsh"/><br /><sub><b>jiangsh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jiangsh-ui" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/keaifafafa"><img src="https://avatars.githubusercontent.com/u/83876361?v=4?s=100" width="100px;" alt="Keaifa"/><br /><sub><b>Keaifa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=keaifafafa" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/keaifafafa"><img src="https://avatars.githubusercontent.com/u/83876361?v=4?s=100" width="100px;" alt="Keaifa"/><br /><sub><b>Keaifa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=keaifafafa" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Akeaifafafa" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/loong95"><img src="https://avatars.githubusercontent.com/u/16333958?v=4?s=100" width="100px;" alt="Loong"/><br /><sub><b>Loong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=loong95" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ceekay47"><img src="https://avatars.githubusercontent.com/u/104664857?v=4?s=100" width="100px;" alt="Chandrakant Vankayalapati"/><br /><sub><b>Chandrakant Vankayalapati</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ceekay47" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MRgenial"><img src="https://avatars.githubusercontent.com/u/49973336?v=4?s=100" width="100px;" alt="b_mountain"/><br /><sub><b>b_mountain</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MRgenial" title="Code">💻</a></td>
@@ -483,9 +485,48 @@ Thanks to these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starryCoder"><img src="https://avatars.githubusercontent.com/u/46510059?v=4?s=100" width="100px;" alt="starryCoder"/><br /><sub><b>starryCoder</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=starryCoder" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hasimmollah"><img src="https://avatars.githubusercontent.com/u/32538599?v=4?s=100" width="100px;" alt="hasimmollah"/><br /><sub><b>hasimmollah</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hasimmollah" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ayu-v0"><img src="https://avatars.githubusercontent.com/u/127600988?v=4?s=100" width="100px;" alt="Ayu"/><br /><sub><b>Ayu</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ayu-v0" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Rancho-7"><img src="https://avatars.githubusercontent.com/u/59016860?v=4?s=100" width="100px;" alt="Nick Guo"/><br /><sub><b>Nick Guo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Rancho-7" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Rancho-7"><img src="https://avatars.githubusercontent.com/u/59016860?v=4?s=100" width="100px;" alt="Nick Guo"/><br /><sub><b>Nick Guo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Rancho-7" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=Rancho-7" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ARancho-7" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/doveLin0818"><img src="https://avatars.githubusercontent.com/u/190927907?v=4?s=100" width="100px;" alt="doveLin"/><br /><sub><b>doveLin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=doveLin0818" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://zzrl.cc/"><img src="https://avatars.githubusercontent.com/u/91836599?v=4?s=100" width="100px;" alt="yunfan24"/><br /><sub><b>yunfan24</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://zzrl.cc/"><img src="https://avatars.githubusercontent.com/u/91836599?v=4?s=100" width="100px;" alt="yunfan24"/><br /><sub><b>yunfan24</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayunfan24" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Tests">⚠️</a> <a href="#blog-yunfan24" title="Blogposts">📝</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lctking"><img src="https://avatars.githubusercontent.com/u/168249998?v=4?s=100" width="100px;" alt="nullwli"/><br /><sub><b>nullwli</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lctking" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://simonsigre.com/"><img src="https://avatars.githubusercontent.com/u/14932913?v=4?s=100" width="100px;" alt="Simon Sigré"/><br /><sub><b>Simon Sigré</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=simonsigre" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=simonsigre" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.ponfee.cn/"><img src="https://avatars.githubusercontent.com/u/46117331?v=4?s=100" width="100px;" alt="ponfee"/><br /><sub><b>ponfee</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ponfee" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Vedant7789"><img src="https://avatars.githubusercontent.com/u/147625492?v=4?s=100" width="100px;" alt="Vedant7789"/><br /><sub><b>Vedant7789</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Vedant7789" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Craaaaazy77"><img src="https://avatars.githubusercontent.com/u/23025522?v=4?s=100" width="100px;" alt="Craaaaazy77"/><br /><sub><b>Craaaaazy77</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Craaaaazy77" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Suvrat1629"><img src="https://avatars.githubusercontent.com/u/140749446?v=4?s=100" width="100px;" alt="Suvrat1629"/><br /><sub><b>Suvrat1629</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Suvrat1629" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://ghyghoo8.github.io/"><img src="https://avatars.githubusercontent.com/u/363129?v=4?s=100" width="100px;" alt="ghy"/><br /><sub><b>ghy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ghyghoo8" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/helei1030"><img src="https://avatars.githubusercontent.com/u/11839080?v=4?s=100" width="100px;" alt="helei1030"/><br /><sub><b>helei1030</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=helei1030" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://medium.com/@pjfanning"><img src="https://avatars.githubusercontent.com/u/11783444?v=4?s=100" width="100px;" alt="PJ Fanning"/><br /><sub><b>PJ Fanning</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=pjfanning" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Apjfanning" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=pjfanning" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MonsterChenzhuo"><img src="https://avatars.githubusercontent.com/u/60029759?v=4?s=100" width="100px;" alt="monster"/><br /><sub><b>monster</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MonsterChenzhuo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MasamiYui"><img src="https://avatars.githubusercontent.com/u/22274133?v=4?s=100" width="100px;" alt="Sherlock Yin"/><br /><sub><b>Sherlock Yin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MasamiYui" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=MasamiYui" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AMasamiYui" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wanhao23"><img src="https://avatars.githubusercontent.com/u/29560961?v=4?s=100" width="100px;" alt="wanhao"/><br /><sub><b>wanhao</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wanhao23" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=wanhao23" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jonasHanhan"><img src="https://avatars.githubusercontent.com/u/130035609?v=4?s=100" width="100px;" alt="jonasHanhan"/><br /><sub><b>jonasHanhan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jonasHanhan" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NikhilMurugesan"><img src="https://avatars.githubusercontent.com/u/49281792?v=4?s=100" width="100px;" alt="NikhilMurugesan"/><br /><sub><b>NikhilMurugesan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=NikhilMurugesan" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/myangle1120"><img src="https://avatars.githubusercontent.com/u/19237013?v=4?s=100" width="100px;" alt="myangle1120"/><br /><sub><b>myangle1120</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=myangle1120" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yasminvo"><img src="https://avatars.githubusercontent.com/u/107528848?v=4?s=100" width="100px;" alt="yasminvo"/><br /><sub><b>yasminvo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yasminvo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notbugggg"><img src="https://avatars.githubusercontent.com/u/147966331?v=4?s=100" width="100px;" alt="不关银渐层的事哦"/><br /><sub><b>不关银渐层的事哦</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=notbugggg" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Anotbugggg" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yyahang"><img src="https://avatars.githubusercontent.com/u/90464876?v=4?s=100" width="100px;" alt="yyahang"/><br /><sub><b>yyahang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yyahang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JuJinPark"><img src="https://avatars.githubusercontent.com/u/44892459?v=4?s=100" width="100px;" alt="jujin"/><br /><sub><b>jujin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=JuJinPark" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=JuJinPark" title="Documentation">📖</a> <a href="#ideas-JuJinPark" title="Ideas, Planning, & Feedback">🤔</a> <a href="#blog-JuJinPark" title="Blogposts">📝</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LL-LIN"><img src="https://avatars.githubusercontent.com/u/43002118?v=4?s=100" width="100px;" alt="LL-LIN"/><br /><sub><b>LL-LIN</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LL-LIN" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ALL-LIN" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://bigcyy.github.io/"><img src="https://avatars.githubusercontent.com/u/73413979?v=4?s=100" width="100px;" alt="Yang Chen"/><br /><sub><b>Yang Chen</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bigcyy" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=bigcyy" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Abigcyy" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sarthakeash"><img src="https://avatars.githubusercontent.com/u/74091160?v=4?s=100" width="100px;" alt="Sarthak Arora"/><br /><sub><b>Sarthak Arora</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=sarthakeash" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=sarthakeash" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PengJingzhao"><img src="https://avatars.githubusercontent.com/u/97368949?v=4?s=100" width="100px;" alt="彭镜肇"/><br /><sub><b>彭镜肇</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=PengJingzhao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gagaradio"><img src="https://avatars.githubusercontent.com/u/18532370?v=4?s=100" width="100px;" alt="Walter Jia"/><br /><sub><b>Walter Jia</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gagaradio" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/boyucjz"><img src="https://avatars.githubusercontent.com/u/18730041?v=4?s=100" width="100px;" alt="boyucjz"/><br /><sub><b>boyucjz</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=boyucjz" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Cyanty"><img src="https://avatars.githubusercontent.com/u/153884653?v=4?s=100" width="100px;" alt="Cyanty"/><br /><sub><b>Cyanty</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Cyanty" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Cyanty" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KevinLLF"><img src="https://avatars.githubusercontent.com/u/85452733?v=4?s=100" width="100px;" alt="Jay丿167"/><br /><sub><b>Jay丿167</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=KevinLLF" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Duansg"><img src="https://avatars.githubusercontent.com/u/112607719?v=4?s=100" width="100px;" alt="Duansg"/><br /><sub><b>Duansg</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Duansg" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xiaomizhou2"><img src="https://avatars.githubusercontent.com/u/47807926?v=4?s=100" width="100px;" alt="zhangyaxi"/><br /><sub><b>zhangyaxi</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xiaomizhou2" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=xiaomizhou2" title="Tests">⚠️</a></td>
</tr>
</tbody>
</table>
@@ -507,13 +548,13 @@ WeChat Group : Add friend `ahertzbeat` and invite to the group.
WeChat Public : Search ID `usthecom`.
[QQ Group](https://jq.qq.com/?_wv=1027&k=Bud9OzdI) : Group num `630061200`
[QQ Group](https://qm.qq.com/q/xxqecSC2cw) : Group num `1035688434`
[Github Discussion](https://github.com/apache/hertzbeat/discussions)
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
[Follow Us Twitter](https://x.com/hertzbeat1024)
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
+79 -39
View File
@@ -4,15 +4,16 @@
</a>
</p>
<h4 align="center">
<a href="README_CN.md">中文文档</a> | <a href="README.md">English Document</a>
</h4>
<p align="center">
<b>Readme</b>:
<a href="README.md">English</a> | <b><a href="README_CN.md">中文</a></b> | <a href="README_JP.md">日本語</a>
</p>
> 实时监控系统,无需 Agent,性能集群,兼容 Prometheus,自定义监控和状态页构建能力。
[![Discord](https://img.shields.io/badge/Chat-Discord-7289DA?logo=discord)](https://discord.gg/Fb6M73htGr)
[![Reddit](https://img.shields.io/badge/Reddit-Community-7289DA?logo=reddit)](https://www.reddit.com/r/hertzbeat/)
[![Twitter](https://img.shields.io/twitter/follow/hertzbeat1024?logo=twitter)](https://twitter.com/hertzbeat1024)
[![Twitter](https://img.shields.io/twitter/follow/hertzbeat1024?logo=twitter)](https://x.com/hertzbeat1024)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8139/badge)](https://www.bestpractices.dev/projects/8139)
[![codecov](https://codecov.io/gh/apache/HertzBeat/branch/master/graph/badge.svg)](https://app.codecov.io/gh/apache/hertzbeat)
[![Docker Pulls](https://img.shields.io/docker/pulls/apache/hertzbeat?style=%20for-the-badge&logo=docker&label=DockerHub%20Download)](https://hub.docker.com/r/apache/hertzbeat)
@@ -32,8 +33,8 @@
### 特点
-**监控+告警+通知** 为一体,支持对应用服务,应用程序,数据库,缓存,操作系统,大数据,中间件,Web 服务器,云原生,网络,自定义等监控阈值告警通知一步到位。
- 易用友好,无需 `Agent`,全 `WEB` 页面操作,鼠标点一点就能监控告警,零上手学习成本。
-`Http, Jmx, Ssh, Snmp, Jdbc, Prometheus` 等协议规范可配置化,只需在浏览器配置监控模 `YML` 就能使用这些协议去自定义采集想要的指标。您相信只需配置下就能立刻适配一款 `K8s``Docker` 等新的监控类型吗?
- 易用友好,无需 `Agent`,全 `WEB` 页面操作,鼠标点一点就能监控告警,无需学习成本。
-`Http, Jmx, Ssh, Snmp, Jdbc, Prometheus` 等协议规范可配置化,只需在浏览器配置监控模 `YML` 就能使用这些协议去自定义采集想要的指标。您相信只需简单配置即可快速适配一款 `K8s``Docker` 等新的监控类型吗?
- 兼容 `Prometheus` 的系统生态并且更多,只需页面操作就可以监控 `Prometheus` 所能监控的。
- 高性能,支持多采集器集群横向扩展,支持多隔离网络监控,云边协同。
- 自由的告警阈值规则,`邮件` `Discord` `Slack` `Telegram` `钉钉` `微信` `飞书` `短信` `Webhook` `Server酱` 等方式消息及时送达。
@@ -58,8 +59,8 @@
## ⛄ 已支持
> 我们将监控采集类型(mysql,jvm,k8s)都定义为 `yml` 监控模,用户可以导入这些模来支持对应类型的监控!
> 欢迎大家一起贡献你使用过程中自定义的通用监控类型监控模
> 我们将监控采集类型(mysql,jvm,k8s)都定义为 `yml` 监控模,用户可以导入这些模来支持对应类型的监控!
> 欢迎大家一起贡献你使用过程中自定义的通用监控类型监控模
- [Website](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-website.yml), [Port Telnet](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-port.yml),
[Http Api](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-api.yml), [Ping Connect](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-ping.yml),
@@ -97,7 +98,7 @@
- [CiscoSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-cisco_switch.yml), [HpeSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-hpe_switch.yml),
[HuaweiSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-huawei_switch.yml), [TpLinkSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-tplink_switch.yml),
[H3cSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-h3c_switch.yml)
- 和更多自定义监控模
- 和更多自定义监控模
- 通知支持 `Discord` `Slack` `Telegram` `邮件` `钉钉` `微信` `飞书` `短信` `Webhook` `Server酱`
## 🐕 快速开始
@@ -221,7 +222,7 @@ Thanks these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="http://mroldx.xyz/"><img src="https://avatars.githubusercontent.com/u/34847828?v=4?s=100" width="100px;" alt="mroldx"/><br /><sub><b>mroldx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mroldx" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/woshiniusange"><img src="https://avatars.githubusercontent.com/u/91513022?v=4?s=100" width="100px;" alt="woshiniusange"/><br /><sub><b>woshiniusange</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=woshiniusange" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://vampireachao.github.io/"><img src="https://avatars.githubusercontent.com/u/52746628?v=4?s=100" width="100px;" alt="VampireAchao"/><br /><sub><b>VampireAchao</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=VampireAchao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ceilzcx"><img src="https://avatars.githubusercontent.com/u/48920254?v=4?s=100" width="100px;" alt="zcx"/><br /><sub><b>zcx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Ceilzcx" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACeilzcx" title="Bug reports">🐛</a> <a href="#design-Ceilzcx" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ceilzcx"><img src="https://avatars.githubusercontent.com/u/48920254?v=4?s=100" width="100px;" alt="zcx"/><br /><sub><b>zcx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Ceilzcx" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACeilzcx" title="Bug reports">🐛</a> <a href="#design-Ceilzcx" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=Ceilzcx" title="Tests">⚠️</a> <a href="#blog-Ceilzcx" title="Blogposts">📝</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CharlieXCL"><img src="https://avatars.githubusercontent.com/u/91540487?v=4?s=100" width="100px;" alt="CharlieXCL"/><br /><sub><b>CharlieXCL</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=CharlieXCL" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Privauto"><img src="https://avatars.githubusercontent.com/u/36581456?v=4?s=100" width="100px;" alt="Privauto"/><br /><sub><b>Privauto</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Privauto" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Privauto" title="Documentation">📖</a></td>
</tr>
@@ -235,7 +236,7 @@ Thanks these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://www.zhihu.com/people/kevinbauer"><img src="https://avatars.githubusercontent.com/u/28581579?v=4?s=100" width="100px;" alt="Kevin Huang"/><br /><sub><b>Kevin Huang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=kevinhuangwl" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TJxiaobao"><img src="https://avatars.githubusercontent.com/u/85919258?v=4?s=100" width="100px;" alt="铁甲小宝"/><br /><sub><b>铁甲小宝</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3ATJxiaobao" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TJxiaobao"><img src="https://avatars.githubusercontent.com/u/85919258?v=4?s=100" width="100px;" alt="铁甲小宝"/><br /><sub><b>铁甲小宝</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3ATJxiaobao" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Tests">⚠️</a> <a href="#design-TJxiaobao" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jack-123-power"><img src="https://avatars.githubusercontent.com/u/84333501?v=4?s=100" width="100px;" alt="Captain Jack"/><br /><sub><b>Captain Jack</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Jack-123-power" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/haibo-duan"><img src="https://avatars.githubusercontent.com/u/7974845?v=4?s=100" width="100px;" alt="haibo.duan"/><br /><sub><b>haibo.duan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=haibo-duan" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=haibo-duan" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/assassinfym"><img src="https://avatars.githubusercontent.com/u/15188754?v=4?s=100" width="100px;" alt="assassin"/><br /><sub><b>assassin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3Aassassinfym" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=assassinfym" title="Code">💻</a></td>
@@ -277,7 +278,7 @@ Thanks these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://wjl110.xyz/"><img src="https://avatars.githubusercontent.com/u/53851034?v=4?s=100" width="100px;" alt="wjl110"/><br /><sub><b>wjl110</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wjl110" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ngyhd"><img src="https://avatars.githubusercontent.com/u/29095207?v=4?s=100" width="100px;" alt="Sean"/><br /><sub><b>Sean</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ngyhd" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Daydreamer-ia"><img src="https://avatars.githubusercontent.com/u/83362909?v=4?s=100" width="100px;" alt="chenyiqin"/><br /><sub><b>chenyiqin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Daydreamer-ia" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Daydreamer-ia" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hudongdong129"><img src="https://avatars.githubusercontent.com/u/34374227?v=4?s=100" width="100px;" alt="hudongdong129"/><br /><sub><b>hudongdong129</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hudongdong129"><img src="https://avatars.githubusercontent.com/u/34374227?v=4?s=100" width="100px;" alt="hudongdong129"/><br /><sub><b>hudongdong129</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Documentation">📖</a> <a href="#design-hudongdong129" title="Design">🎨</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TherChenYang"><img src="https://avatars.githubusercontent.com/u/124348939?v=4?s=100" width="100px;" alt="TherChenYang"/><br /><sub><b>TherChenYang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=TherChenYang" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=TherChenYang" title="Tests">⚠️</a></td>
@@ -293,7 +294,7 @@ Thanks these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/baiban114"><img src="https://avatars.githubusercontent.com/u/59152619?v=4?s=100" width="100px;" alt="TableRow"/><br /><sub><b>TableRow</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=baiban114" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=baiban114" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ByteIDance"><img src="https://avatars.githubusercontent.com/u/100207562?v=4?s=100" width="100px;" alt="ByteIDance"/><br /><sub><b>ByteIDance</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ByteIDance" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mangel2002"><img src="https://avatars.githubusercontent.com/u/9348020?v=4?s=100" width="100px;" alt="Jangfe"/><br /><sub><b>Jangfe</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mangel2002" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zqr10159"><img src="https://avatars.githubusercontent.com/u/30048352?v=4?s=100" width="100px;" alt="zqr10159"/><br /><sub><b>zqr10159</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zqr10159"><img src="https://avatars.githubusercontent.com/u/30048352?v=4?s=100" width="100px;" alt="zqr10159"/><br /><sub><b>zqr10159</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Code">💻</a> <a href="#blog-zqr10159" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Azqr10159" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Tests">⚠️</a> <a href="#design-zqr10159" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vinci-897"><img src="https://avatars.githubusercontent.com/u/55838224?v=4?s=100" width="100px;" alt="vinci"/><br /><sub><b>vinci</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=vinci-897" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=vinci-897" title="Documentation">📖</a> <a href="#design-vinci-897" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/js110"><img src="https://avatars.githubusercontent.com/u/51191863?v=4?s=100" width="100px;" alt="js110"/><br /><sub><b>js110</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=js110" title="Code">💻</a></td>
</tr>
@@ -307,8 +308,8 @@ Thanks these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZangJuxy"><img src="https://avatars.githubusercontent.com/u/71380295?v=4?s=100" width="100px;" alt="ZangJuxy"/><br /><sub><b>ZangJuxy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZangJuxy" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/l646505418"><img src="https://avatars.githubusercontent.com/u/50475131?v=4?s=100" width="100px;" alt="l646505418"/><br /><sub><b>l646505418</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=l646505418" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.carpewang.com"><img src="https://avatars.githubusercontent.com/u/78642589?v=4?s=100" width="100px;" alt="Carpe-Wang"/><br /><sub><b>Carpe-Wang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Carpe-Wang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/l646505418"><img src="https://avatars.githubusercontent.com/u/50475131?v=4?s=100" width="100px;" alt="l646505418"/><br /><sub><b>l646505418</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=l646505418" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Al646505418" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.carpewang.com"><img src="https://avatars.githubusercontent.com/u/78642589?v=4?s=100" width="100px;" alt="Carpe-Wang"/><br /><sub><b>Carpe-Wang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Carpe-Wang" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACarpe-Wang" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/moshu023"><img src="https://avatars.githubusercontent.com/u/48593205?v=4?s=100" width="100px;" alt="莫枢"/><br /><sub><b>莫枢</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=moshu023" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/huangcanda"><img src="https://avatars.githubusercontent.com/u/4470566?v=4?s=100" width="100px;" alt="huangcanda"/><br /><sub><b>huangcanda</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=huangcanda" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.zrkizzy.com"><img src="https://avatars.githubusercontent.com/u/85340613?v=4?s=100" width="100px;" alt="世纪末的架构师"/><br /><sub><b>世纪末的架构师</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Architect-Java" title="Code">💻</a></td>
@@ -358,7 +359,7 @@ Thanks these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lisongning"><img src="https://avatars.githubusercontent.com/u/93140178?v=4?s=100" width="100px;" alt="lisongning"/><br /><sub><b>lisongning</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lisongning" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/YutingNie"><img src="https://avatars.githubusercontent.com/u/104416402?v=4?s=100" width="100px;" alt="YutingNie"/><br /><sub><b>YutingNie</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=YutingNie" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=YutingNie" title="Documentation">📖</a> <a href="#design-YutingNie" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mikezzb"><img src="https://avatars.githubusercontent.com/u/23418428?v=4?s=100" width="100px;" alt="Mike Zhou"/><br /><sub><b>Mike Zhou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mikezzb" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=mikezzb" title="Documentation">📖</a> <a href="#design-mikezzb" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/a-little-fool"><img src="https://avatars.githubusercontent.com/u/105542329?v=4?s=100" width="100px;" alt="小笨蛋"/><br /><sub><b>小笨蛋</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=a-little-fool" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/a-little-fool"><img src="https://avatars.githubusercontent.com/u/105542329?v=4?s=100" width="100px;" alt="小笨蛋"/><br /><sub><b>小笨蛋</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=a-little-fool" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=a-little-fool" title="Documentation">📖</a> <a href="#blog-a-little-fool" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Aa-little-fool" title="Bug reports">🐛</a> <a href="#design-a-little-fool" title="Design">🎨</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/littlezhongzer"><img src="https://avatars.githubusercontent.com/u/33685289?v=4?s=100" width="100px;" alt="littlezhongzer"/><br /><sub><b>littlezhongzer</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=littlezhongzer" title="Code">💻</a></td>
@@ -367,7 +368,7 @@ Thanks these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/XimfengYao"><img src="https://avatars.githubusercontent.com/u/17541537?v=4?s=100" width="100px;" alt="姚贤丰"/><br /><sub><b>姚贤丰</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=XimfengYao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LINGLUOJUN"><img src="https://avatars.githubusercontent.com/u/16778977?v=4?s=100" width="100px;" alt="lingluojun"/><br /><sub><b>lingluojun</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LINGLUOJUN" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.luelueking.com"><img src="https://avatars.githubusercontent.com/u/93204032?v=4?s=100" width="100px;" alt="1ue"/><br /><sub><b>1ue</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=luelueking" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.jimmyqiao.top"><img src="https://avatars.githubusercontent.com/u/67301054?v=4?s=100" width="100px;" alt="qyaaaa"/><br /><sub><b>qyaaaa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=qyaaaa" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.jimmyqiao.top"><img src="https://avatars.githubusercontent.com/u/67301054?v=4?s=100" width="100px;" alt="qyaaaa"/><br /><sub><b>qyaaaa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=qyaaaa" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Aqyaaaa" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://novohit.top"><img src="https://avatars.githubusercontent.com/u/101090395?v=4?s=100" width="100px;" alt="novohit"/><br /><sub><b>novohit</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=novohit" title="Code">💻</a></td>
@@ -381,14 +382,14 @@ Thanks these wonderful people, welcome to join us:
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/1036664317"><img src="https://avatars.githubusercontent.com/u/7696697?v=4?s=100" width="100px;" alt="moghn"/><br /><sub><b>moghn</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=1036664317" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xiaoguolong"><img src="https://avatars.githubusercontent.com/u/33684988?v=4?s=100" width="100px;" alt="xiaoguolong"/><br /><sub><b>xiaoguolong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xiaoguolong" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Clownsw"><img src="https://avatars.githubusercontent.com/u/28394742?v=4?s=100" width="100px;" alt="Smliexx"/><br /><sub><b>Smliexx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Clownsw" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Calvin979"><img src="https://avatars.githubusercontent.com/u/131688897?v=4?s=100" width="100px;" alt="Naruse"/><br /><sub><b>Naruse</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Code">💻</a> <a href="#design-Calvin979" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Clownsw"><img src="https://avatars.githubusercontent.com/u/28394742?v=4?s=100" width="100px;" alt="Smliexx"/><br /><sub><b>Smliexx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Clownsw" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AClownsw" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Calvin979"><img src="https://avatars.githubusercontent.com/u/131688897?v=4?s=100" width="100px;" alt="Naruse"/><br /><sub><b>Naruse</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Code">💻</a> <a href="#design-Calvin979" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACalvin979" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bbelide2"><img src="https://avatars.githubusercontent.com/u/26840796?v=4?s=100" width="100px;" alt="Bala Sukesh"/><br /><sub><b>Bala Sukesh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bbelide2" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jinyaoMa"><img src="https://avatars.githubusercontent.com/u/25066570?v=4?s=100" width="100px;" alt="Jinyao Ma"/><br /><sub><b>Jinyao Ma</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jinyaoMa" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://linuxsuren.github.io/open-source-best-practice/"><img src="https://avatars.githubusercontent.com/u/1450685?v=4?s=100" width="100px;" alt="Rick"/><br /><sub><b>Rick</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LinuxSuRen" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=LinuxSuRen" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZY945"><img src="https://avatars.githubusercontent.com/u/74083801?v=4?s=100" width="100px;" alt="东风"/><br /><sub><b>东风</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Code">💻</a> <a href="#design-ZY945" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZY945"><img src="https://avatars.githubusercontent.com/u/74083801?v=4?s=100" width="100px;" alt="东风"/><br /><sub><b>东风</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Code">💻</a> <a href="#design-ZY945" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AZY945" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/prolevel1"><img src="https://avatars.githubusercontent.com/u/51995525?v=4?s=100" width="100px;" alt="sonam singh"/><br /><sub><b>sonam singh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=prolevel1" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZhangZixuan1994"><img src="https://avatars.githubusercontent.com/u/20011653?v=4?s=100" width="100px;" alt="ZhangZixuan1994"/><br /><sub><b>ZhangZixuan1994</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZhangZixuan1994" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hurenjie1"><img src="https://avatars.githubusercontent.com/u/40120355?v=4?s=100" width="100px;" alt="SHIG"/><br /><sub><b>SHIG</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hurenjie1" title="Code">💻</a></td>
@@ -398,29 +399,29 @@ Thanks these wonderful people, welcome to join us:
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/avvCode"><img src="https://avatars.githubusercontent.com/u/113538532?v=4?s=100" width="100px;" alt="avv"/><br /><sub><b>avv</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=avvCode" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yqxxgh"><img src="https://avatars.githubusercontent.com/u/42080876?v=4?s=100" width="100px;" alt="yqxxgh"/><br /><sub><b>yqxxgh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yqxxgh" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yqxxgh"><img src="https://avatars.githubusercontent.com/u/42080876?v=4?s=100" width="100px;" alt="yqxxgh"/><br /><sub><b>yqxxgh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yqxxgh" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=yqxxgh" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayqxxgh" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CharlieShi46"><img src="https://avatars.githubusercontent.com/u/149798885?v=4?s=100" width="100px;" alt="CharlieShi46"/><br /><sub><b>CharlieShi46</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=CharlieShi46" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Nctllnty"><img src="https://avatars.githubusercontent.com/u/33241818?v=4?s=100" width="100px;" alt="Nctllnty"/><br /><sub><b>Nctllnty</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Nctllnty" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Wang-Yonghao"><img src="https://avatars.githubusercontent.com/u/48146606?v=4?s=100" width="100px;" alt="Wang-Yonghao"/><br /><sub><b>Wang-Yonghao</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Wang-Yonghao" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.yuque.com/dudiao/yy"><img src="https://avatars.githubusercontent.com/u/38355949?v=4?s=100" width="100px;" alt="读钓"/><br /><sub><b>读钓</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=dudiao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starmilkxin"><img src="https://avatars.githubusercontent.com/u/55646681?v=4?s=100" width="100px;" alt="Xin"/><br /><sub><b>Xin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=starmilkxin" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starmilkxin"><img src="https://avatars.githubusercontent.com/u/55646681?v=4?s=100" width="100px;" alt="Xin"/><br /><sub><b>Xin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=starmilkxin" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Astarmilkxin" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/handy-git"><img src="https://avatars.githubusercontent.com/u/32837980?v=4?s=100" width="100px;" alt="handy"/><br /><sub><b>handy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=handy-git" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LiuTianyou"><img src="https://avatars.githubusercontent.com/u/30208283?v=4?s=100" width="100px;" alt="LiuTianyou"/><br /><sub><b>LiuTianyou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LiuTianyou"><img src="https://avatars.githubusercontent.com/u/30208283?v=4?s=100" width="100px;" alt="LiuTianyou"/><br /><sub><b>LiuTianyou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ALiuTianyou" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Tests">⚠️</a> <a href="#blog-LiuTianyou" title="Blogposts">📝</a> <a href="#design-LiuTianyou" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/WinterKi1ler"><img src="https://avatars.githubusercontent.com/u/160592092?v=4?s=100" width="100px;" alt="WinterKi1ler"/><br /><sub><b>WinterKi1ler</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=WinterKi1ler" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://sharehoo.cn/"><img src="https://avatars.githubusercontent.com/u/45377370?v=4?s=100" width="100px;" alt="miki"/><br /><sub><b>miki</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=miki-hmt" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://codeflex.substack.com/"><img src="https://avatars.githubusercontent.com/u/85513042?v=4?s=100" width="100px;" alt="Keshav Carpenter"/><br /><sub><b>Keshav Carpenter</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=alpha951" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=alpha951" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/makechoicenow"><img src="https://avatars.githubusercontent.com/u/9911918?v=4?s=100" width="100px;" alt="makechoicenow"/><br /><sub><b>makechoicenow</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=makechoicenow" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gjjjj0101"><img src="https://avatars.githubusercontent.com/u/71874373?v=4?s=100" width="100px;" alt="Gao Jian"/><br /><sub><b>Gao Jian</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Code">💻</a> <a href="#design-gjjjj0101" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gjjjj0101"><img src="https://avatars.githubusercontent.com/u/71874373?v=4?s=100" width="100px;" alt="Gao Jian"/><br /><sub><b>Gao Jian</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Documentation">📖</a> <a href="#design-gjjjj0101" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Agjjjj0101" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://jangto.tistory.com/"><img src="https://avatars.githubusercontent.com/u/37864182?v=4?s=100" width="100px;" alt="Hyeon Sung"/><br /><sub><b>Hyeon Sung</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=dukbong" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://crossoverjie.top/"><img src="https://avatars.githubusercontent.com/u/15684156?v=4?s=100" width="100px;" alt="crossoverJie"/><br /><sub><b>crossoverJie</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://jangto.tistory.com/"><img src="https://avatars.githubusercontent.com/u/37864182?v=4?s=100" width="100px;" alt="Hyeon Sung"/><br /><sub><b>Hyeon Sung</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=dukbong" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=dukbong" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://crossoverjie.top/"><img src="https://avatars.githubusercontent.com/u/15684156?v=4?s=100" width="100px;" alt="crossoverJie"/><br /><sub><b>crossoverJie</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Documentation">📖</a> <a href="#blog-crossoverJie" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Tests">⚠️</a> <a href="#design-crossoverJie" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PeixyJ"><img src="https://avatars.githubusercontent.com/u/45998593?v=4?s=100" width="100px;" alt="PeixyJ"/><br /><sub><b>PeixyJ</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=PeixyJ" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Hi-Mr-Wind"><img src="https://avatars.githubusercontent.com/u/85803831?v=4?s=100" width="100px;" alt="风如歌"/><br /><sub><b>风如歌</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Hi-Mr-Wind" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MananPoojara"><img src="https://avatars.githubusercontent.com/u/104253184?v=4?s=100" width="100px;" alt="Manan Pujara"/><br /><sub><b>Manan Pujara</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MananPoojara" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xuziyang"><img src="https://avatars.githubusercontent.com/u/8465969?v=4?s=100" width="100px;" alt="xuziyang"/><br /><sub><b>xuziyang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xuziyang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xuziyang"><img src="https://avatars.githubusercontent.com/u/8465969?v=4?s=100" width="100px;" alt="xuziyang"/><br /><sub><b>xuziyang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xuziyang" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=xuziyang" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Axuziyang" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lwqzz"><img src="https://avatars.githubusercontent.com/u/62584513?v=4?s=100" width="100px;" alt="lwqzz"/><br /><sub><b>lwqzz</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lwqzz" title="Code">💻</a></td>
</tr>
<tr>
@@ -428,17 +429,17 @@ Thanks these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tomorrowshipyltm"><img src="https://avatars.githubusercontent.com/u/61336903?v=4?s=100" width="100px;" alt="tomorrowshipyltm"/><br /><sub><b>tomorrowshipyltm</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=tomorrowshipyltm" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/15613060203"><img src="https://avatars.githubusercontent.com/u/41351615?v=4?s=100" width="100px;" alt="栗磊"/><br /><sub><b>栗磊</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=15613060203" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Alanxtl"><img src="https://avatars.githubusercontent.com/u/25652981?v=4?s=100" width="100px;" alt="Alan"/><br /><sub><b>Alan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Alanxtl" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.hadoop.wiki/"><img src="https://avatars.githubusercontent.com/u/29418975?v=4?s=100" width="100px;" alt="Jast"/><br /><sub><b>Jast</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zuobiao-zhou"><img src="https://avatars.githubusercontent.com/u/61108539?v=4?s=100" width="100px;" alt="Zhang Yuxuan"/><br /><sub><b>Zhang Yuxuan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.hadoop.wiki/"><img src="https://avatars.githubusercontent.com/u/29418975?v=4?s=100" width="100px;" alt="Jast"/><br /><sub><b>Jast</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Code">💻</a> <a href="#ideas-zhangshenghang" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Documentation">📖</a> <a href="#blog-zhangshenghang" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Azhangshenghang" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Tests">⚠️</a> <a href="#design-zhangshenghang" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zuobiao-zhou"><img src="https://avatars.githubusercontent.com/u/61108539?v=4?s=100" width="100px;" alt="Zhang Yuxuan"/><br /><sub><b>Zhang Yuxuan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Azuobiao-zhou" title="Bug reports">🐛</a> <a href="#blog-zuobiao-zhou" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Pzz-2021"><img src="https://avatars.githubusercontent.com/u/118056735?v=4?s=100" width="100px;" alt="P.P."/><br /><sub><b>P.P.</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Pzz-2021" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LLP2333"><img src="https://avatars.githubusercontent.com/u/61670545?v=4?s=100" width="100px;" alt="llp2333"/><br /><sub><b>llp2333</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LLP2333" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/HeartLinked"><img src="https://avatars.githubusercontent.com/u/78212101?v=4?s=100" width="100px;" alt="feiyang li"/><br /><sub><b>feiyang li</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=HeartLinked" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Aias00"><img src="https://avatars.githubusercontent.com/u/25810623?v=4?s=100" width="100px;" alt="aias00"/><br /><sub><b>aias00</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Aias00"><img src="https://avatars.githubusercontent.com/u/25810623?v=4?s=100" width="100px;" alt="aias00"/><br /><sub><b>aias00</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AAias00" title="Bug reports">🐛</a> <a href="#ideas-Aias00" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/westboy"><img src="https://avatars.githubusercontent.com/u/6385565?v=4?s=100" width="100px;" alt="Jin"/><br /><sub><b>Jin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=westboy" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://blog.csdn.net/qq_52397471"><img src="https://avatars.githubusercontent.com/u/77964041?v=4?s=100" width="100px;" alt="YuLuo"/><br /><sub><b>YuLuo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yuluo-yx" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Yanshuming1"><img src="https://avatars.githubusercontent.com/u/118667222?v=4?s=100" width="100px;" alt="linDong"/><br /><sub><b>linDong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Yanshuming1" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://blog.csdn.net/qq_52397471"><img src="https://avatars.githubusercontent.com/u/77964041?v=4?s=100" width="100px;" alt="YuLuo"/><br /><sub><b>YuLuo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yuluo-yx" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayuluo-yx" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=yuluo-yx" title="Tests">⚠️</a> <a href="#blog-yuluo-yx" title="Blogposts">📝</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Yanshuming1"><img src="https://avatars.githubusercontent.com/u/118667222?v=4?s=100" width="100px;" alt="linDong"/><br /><sub><b>linDong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Yanshuming1" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Yanshuming1" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AYanshuming1" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lwjxy"><img src="https://avatars.githubusercontent.com/u/52726400?v=4?s=100" width="100px;" alt="lwjxy"/><br /><sub><b>lwjxy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lwjxy" title="Code">💻</a></td>
</tr>
<tr>
@@ -453,17 +454,17 @@ Thanks these wonderful people, welcome to join us:
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ileonli"><img src="https://avatars.githubusercontent.com/u/45332412?v=4?s=100" width="100px;" alt="Leon Li"/><br /><sub><b>Leon Li</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ileonli" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://fnil.net/"><img src="https://avatars.githubusercontent.com/u/14142?v=4?s=100" width="100px;" alt="dennis zhuang"/><br /><sub><b>dennis zhuang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=killme2008" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kerwin612"><img src="https://avatars.githubusercontent.com/u/3371163?v=4?s=100" width="100px;" alt="Kerwin Bryant"/><br /><sub><b>Kerwin Bryant</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=kerwin612" title="Code">💻</a> <a href="#design-kerwin612" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kerwin612"><img src="https://avatars.githubusercontent.com/u/3371163?v=4?s=100" width="100px;" alt="Kerwin Bryant"/><br /><sub><b>Kerwin Bryant</b></sub></a><br /><a href="#design-kerwin612" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=kerwin612" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=kerwin612" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Akerwin612" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ShineDevelopment"><img src="https://avatars.githubusercontent.com/u/59306780?v=4?s=100" width="100px;" alt="daixianglong"/><br /><sub><b>daixianglong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ShineDevelopment" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mchgood"><img src="https://avatars.githubusercontent.com/u/38482005?v=4?s=100" width="100px;" alt="mchgood"/><br /><sub><b>mchgood</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mchgood" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pwallk"><img src="https://avatars.githubusercontent.com/u/69385076?v=4?s=100" width="100px;" alt="kangli"/><br /><sub><b>kangli</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=pwallk" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pwallk"><img src="https://avatars.githubusercontent.com/u/69385076?v=4?s=100" width="100px;" alt="kangli"/><br /><sub><b>kangli</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=pwallk" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=pwallk" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Apwallk" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cdphantom"><img src="https://avatars.githubusercontent.com/u/12674795?v=4?s=100" width="100px;" alt="cdphantom"/><br /><sub><b>cdphantom</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=cdphantom" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/asd108908382"><img src="https://avatars.githubusercontent.com/u/77717999?v=4?s=100" width="100px;" alt="jiawei.guo"/><br /><sub><b>jiawei.guo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=asd108908382" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/QBH-insist"><img src="https://avatars.githubusercontent.com/u/39401478?v=4?s=100" width="100px;" alt="QBH-insist"/><br /><sub><b>QBH-insist</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=QBH-insist" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jiangsh-ui"><img src="https://avatars.githubusercontent.com/u/86990361?v=4?s=100" width="100px;" alt="jiangsh"/><br /><sub><b>jiangsh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jiangsh-ui" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/keaifafafa"><img src="https://avatars.githubusercontent.com/u/83876361?v=4?s=100" width="100px;" alt="Keaifa"/><br /><sub><b>Keaifa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=keaifafafa" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/keaifafafa"><img src="https://avatars.githubusercontent.com/u/83876361?v=4?s=100" width="100px;" alt="Keaifa"/><br /><sub><b>Keaifa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=keaifafafa" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Akeaifafafa" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/loong95"><img src="https://avatars.githubusercontent.com/u/16333958?v=4?s=100" width="100px;" alt="Loong"/><br /><sub><b>Loong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=loong95" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ceekay47"><img src="https://avatars.githubusercontent.com/u/104664857?v=4?s=100" width="100px;" alt="Chandrakant Vankayalapati"/><br /><sub><b>Chandrakant Vankayalapati</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ceekay47" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MRgenial"><img src="https://avatars.githubusercontent.com/u/49973336?v=4?s=100" width="100px;" alt="b_mountain"/><br /><sub><b>b_mountain</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MRgenial" title="Code">💻</a></td>
@@ -482,9 +483,48 @@ Thanks these wonderful people, welcome to join us:
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starryCoder"><img src="https://avatars.githubusercontent.com/u/46510059?v=4?s=100" width="100px;" alt="starryCoder"/><br /><sub><b>starryCoder</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=starryCoder" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hasimmollah"><img src="https://avatars.githubusercontent.com/u/32538599?v=4?s=100" width="100px;" alt="hasimmollah"/><br /><sub><b>hasimmollah</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hasimmollah" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ayu-v0"><img src="https://avatars.githubusercontent.com/u/127600988?v=4?s=100" width="100px;" alt="Ayu"/><br /><sub><b>Ayu</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ayu-v0" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Rancho-7"><img src="https://avatars.githubusercontent.com/u/59016860?v=4?s=100" width="100px;" alt="Nick Guo"/><br /><sub><b>Nick Guo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Rancho-7" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Rancho-7"><img src="https://avatars.githubusercontent.com/u/59016860?v=4?s=100" width="100px;" alt="Nick Guo"/><br /><sub><b>Nick Guo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Rancho-7" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=Rancho-7" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ARancho-7" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/doveLin0818"><img src="https://avatars.githubusercontent.com/u/190927907?v=4?s=100" width="100px;" alt="doveLin"/><br /><sub><b>doveLin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=doveLin0818" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://zzrl.cc/"><img src="https://avatars.githubusercontent.com/u/91836599?v=4?s=100" width="100px;" alt="yunfan24"/><br /><sub><b>yunfan24</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://zzrl.cc/"><img src="https://avatars.githubusercontent.com/u/91836599?v=4?s=100" width="100px;" alt="yunfan24"/><br /><sub><b>yunfan24</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayunfan24" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Tests">⚠️</a> <a href="#blog-yunfan24" title="Blogposts">📝</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lctking"><img src="https://avatars.githubusercontent.com/u/168249998?v=4?s=100" width="100px;" alt="nullwli"/><br /><sub><b>nullwli</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lctking" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://simonsigre.com/"><img src="https://avatars.githubusercontent.com/u/14932913?v=4?s=100" width="100px;" alt="Simon Sigré"/><br /><sub><b>Simon Sigré</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=simonsigre" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=simonsigre" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.ponfee.cn/"><img src="https://avatars.githubusercontent.com/u/46117331?v=4?s=100" width="100px;" alt="ponfee"/><br /><sub><b>ponfee</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ponfee" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Vedant7789"><img src="https://avatars.githubusercontent.com/u/147625492?v=4?s=100" width="100px;" alt="Vedant7789"/><br /><sub><b>Vedant7789</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Vedant7789" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Craaaaazy77"><img src="https://avatars.githubusercontent.com/u/23025522?v=4?s=100" width="100px;" alt="Craaaaazy77"/><br /><sub><b>Craaaaazy77</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Craaaaazy77" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Suvrat1629"><img src="https://avatars.githubusercontent.com/u/140749446?v=4?s=100" width="100px;" alt="Suvrat1629"/><br /><sub><b>Suvrat1629</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Suvrat1629" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://ghyghoo8.github.io/"><img src="https://avatars.githubusercontent.com/u/363129?v=4?s=100" width="100px;" alt="ghy"/><br /><sub><b>ghy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ghyghoo8" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/helei1030"><img src="https://avatars.githubusercontent.com/u/11839080?v=4?s=100" width="100px;" alt="helei1030"/><br /><sub><b>helei1030</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=helei1030" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://medium.com/@pjfanning"><img src="https://avatars.githubusercontent.com/u/11783444?v=4?s=100" width="100px;" alt="PJ Fanning"/><br /><sub><b>PJ Fanning</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=pjfanning" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Apjfanning" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=pjfanning" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MonsterChenzhuo"><img src="https://avatars.githubusercontent.com/u/60029759?v=4?s=100" width="100px;" alt="monster"/><br /><sub><b>monster</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MonsterChenzhuo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MasamiYui"><img src="https://avatars.githubusercontent.com/u/22274133?v=4?s=100" width="100px;" alt="Sherlock Yin"/><br /><sub><b>Sherlock Yin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MasamiYui" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=MasamiYui" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AMasamiYui" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wanhao23"><img src="https://avatars.githubusercontent.com/u/29560961?v=4?s=100" width="100px;" alt="wanhao"/><br /><sub><b>wanhao</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wanhao23" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=wanhao23" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jonasHanhan"><img src="https://avatars.githubusercontent.com/u/130035609?v=4?s=100" width="100px;" alt="jonasHanhan"/><br /><sub><b>jonasHanhan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jonasHanhan" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NikhilMurugesan"><img src="https://avatars.githubusercontent.com/u/49281792?v=4?s=100" width="100px;" alt="NikhilMurugesan"/><br /><sub><b>NikhilMurugesan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=NikhilMurugesan" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/myangle1120"><img src="https://avatars.githubusercontent.com/u/19237013?v=4?s=100" width="100px;" alt="myangle1120"/><br /><sub><b>myangle1120</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=myangle1120" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yasminvo"><img src="https://avatars.githubusercontent.com/u/107528848?v=4?s=100" width="100px;" alt="yasminvo"/><br /><sub><b>yasminvo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yasminvo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notbugggg"><img src="https://avatars.githubusercontent.com/u/147966331?v=4?s=100" width="100px;" alt="不关银渐层的事哦"/><br /><sub><b>不关银渐层的事哦</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=notbugggg" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Anotbugggg" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yyahang"><img src="https://avatars.githubusercontent.com/u/90464876?v=4?s=100" width="100px;" alt="yyahang"/><br /><sub><b>yyahang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yyahang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JuJinPark"><img src="https://avatars.githubusercontent.com/u/44892459?v=4?s=100" width="100px;" alt="jujin"/><br /><sub><b>jujin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=JuJinPark" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=JuJinPark" title="Documentation">📖</a> <a href="#ideas-JuJinPark" title="Ideas, Planning, & Feedback">🤔</a> <a href="#blog-JuJinPark" title="Blogposts">📝</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LL-LIN"><img src="https://avatars.githubusercontent.com/u/43002118?v=4?s=100" width="100px;" alt="LL-LIN"/><br /><sub><b>LL-LIN</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LL-LIN" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ALL-LIN" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://bigcyy.github.io/"><img src="https://avatars.githubusercontent.com/u/73413979?v=4?s=100" width="100px;" alt="Yang Chen"/><br /><sub><b>Yang Chen</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bigcyy" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=bigcyy" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Abigcyy" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sarthakeash"><img src="https://avatars.githubusercontent.com/u/74091160?v=4?s=100" width="100px;" alt="Sarthak Arora"/><br /><sub><b>Sarthak Arora</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=sarthakeash" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=sarthakeash" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PengJingzhao"><img src="https://avatars.githubusercontent.com/u/97368949?v=4?s=100" width="100px;" alt="彭镜肇"/><br /><sub><b>彭镜肇</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=PengJingzhao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gagaradio"><img src="https://avatars.githubusercontent.com/u/18532370?v=4?s=100" width="100px;" alt="Walter Jia"/><br /><sub><b>Walter Jia</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gagaradio" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/boyucjz"><img src="https://avatars.githubusercontent.com/u/18730041?v=4?s=100" width="100px;" alt="boyucjz"/><br /><sub><b>boyucjz</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=boyucjz" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Cyanty"><img src="https://avatars.githubusercontent.com/u/153884653?v=4?s=100" width="100px;" alt="Cyanty"/><br /><sub><b>Cyanty</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Cyanty" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Cyanty" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KevinLLF"><img src="https://avatars.githubusercontent.com/u/85452733?v=4?s=100" width="100px;" alt="Jay丿167"/><br /><sub><b>Jay丿167</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=KevinLLF" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Duansg"><img src="https://avatars.githubusercontent.com/u/112607719?v=4?s=100" width="100px;" alt="Duansg"/><br /><sub><b>Duansg</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Duansg" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xiaomizhou2"><img src="https://avatars.githubusercontent.com/u/47807926?v=4?s=100" width="100px;" alt="zhangyaxi"/><br /><sub><b>zhangyaxi</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xiaomizhou2" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=xiaomizhou2" title="Tests">⚠️</a></td>
</tr>
</tbody>
</table>
@@ -506,13 +546,13 @@ Thanks these wonderful people, welcome to join us:
微信公众号 : 搜索 ID `usthecom`.
[QQ交流群](https://jq.qq.com/?_wv=1027&k=Bud9OzdI) : 群号 `630061200`
[QQ交流群](https://qm.qq.com/q/xxqecSC2cw) : 群号 `1035688434`
[Github Discussion](https://github.com/apache/hertzbeat/discussions)
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
[Follow Us Twitter](https://twitter.com/hertzbeat1024)
[Follow Us Twitter](https://x.com/hertzbeat1024)
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
+578
View File
@@ -0,0 +1,578 @@
<p align="center">
<a href="https://hertzbeat.apache.org">
<img alt="hertzbeat" src="/home/static/img/hertzbeat-brand.svg" width="260">
</a>
</p>
<p align="center">
<b>Readme</b>:
<a href="README.md">English</a> | <a href="README_CN.md">中文</a> | <b><a href="README_JP.md">日本語</a></b>
</p>
> オープンソースのリアルタイム監視システム、エージェントレス、クラスタ対応、Prometheus互換、カスタムおよびステータスページ付き。
[![Discord](https://img.shields.io/badge/Chat-Discord-7289DA?logo=discord)](https://discord.gg/Fb6M73htGr)
[![Reddit](https://img.shields.io/badge/Reddit-Community-7289DA?logo=reddit)](https://www.reddit.com/r/hertzbeat/)
[![Twitter](https://img.shields.io/twitter/follow/hertzbeat1024?logo=twitter)](https://x.com/hertzbeat1024)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8139/badge)](https://www.bestpractices.dev/projects/8139)
[![codecov](https://codecov.io/gh/apache/HertzBeat/branch/master/graph/badge.svg)](https://app.codecov.io/gh/apache/hertzbeat)
[![Docker Pulls](https://img.shields.io/docker/pulls/apache/hertzbeat?style=%20for-the-badge&logo=docker&label=DockerHub%20Download)](https://hub.docker.com/r/apache/hertzbeat)
[![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/hertzbeat)](https://artifacthub.io/packages/search?repo=hertzbeat)
[![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UCri75zfWX0GHqJFPENEbLow?logo=youtube&label=YouTube%20Channel)](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/apache/hertzbeat)
**公式サイト: [hertzbeat.apache.org](https://hertzbeat.apache.org)**
**メール:** メーリングリストに登録するために、<a href="mailto:dev-subscribe@hertzbeat.apache.org">dev-subscribe@hertzbeat.apache.org</a>にメールを送ってください。
## 🎡 <font color="green">紹介</font>
[Apache HertzBeat](https://github.com/apache/hertzbeat) incubating)はオープンソースのリアルタイム監視システム、エージェントレス、クラスタ対応、Prometheus互換、カスタムおよびステータスページ付き。
### 特性
- **モニター・アラーム・通知** を一体化し、Web、データベース、キャッシュ、OS、ミドルウェア、クラウドネイティブ、ネットワークなどをサポート。
- 使いやすさを重視し、マウスのクリックだけで完全なWebベースの操作が可能。
- `Http、Jmx、Ssh、Snmp、jdbc、Prometheus`などのプロトコルを設定可能にし、テンプレート`YML`ファイルをオンラインで設定するだけで、あらゆるメトリクスを収集できるようにします。HertzBeatでオンライン設定するだけで、`K8S``Docker`のような新しい監視タイプに素早く対応できることを想像してみてください。
- `Prometheus`のエコシステム互換、Prometheusが監視できるものを、全てオンライン設定によって監視することができます。
- 高性能で、コレクタークラスタ、マルチアイソレートネットワーク、クラウドエッジをサポート。
- 柔軟なアラーム閾値ルールで、メール、discord、slack、telegramなどを通じてタイムリーに通知。
- 強力なステータスページを簡単に構築し、リアルタイムのステータスをユーザーと共有。
> `HertzBeat`の強力なカスタマイズ、多種類のサポート、高性能および容易な拡張性は、ユーザーが迅速に独自の監視システムを構築するのを支援することを目的としています。
----
![hertzbeat](home/static/img/home/1.png)
![hertzbeat](home/static/img/home/status.png)
![hertzbeat](home/static/img/home/9.png)
----
## 🥐 モジュール
![hertzBeat](home/static/img/docs/hertzbeat-arch.png)
## ⛄ 利用可能
> `mysql`、`Java仮想マシン`、`k8s` などのすべての監視コレクション タイプを `YML` 監視テンプレートとして定義し、ユーザーがそれらをインポートして対応するタイプの監視をサポートできるようにしています。
> カスタマイズされた一般的なモニターのテンプレートを提供することを歓迎します。
- [Website](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-website.yml), [Port Telnet](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-port.yml),
[Http Api](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-api.yml), [Ping Connect](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-ping.yml),
[Jvm](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-jvm.yml), [SiteMap](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-fullsite.yml),
[Ssl Certificate](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-ssl_cert.yml), [SpringBoot2](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-springboot2.yml),
[FTP Server](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-ftp.yml), [SpringBoot3](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-springboot3.yml),
[Udp Port](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-udp_port.yml), [Dns](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-dns.yml),
[Pop3](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-pop3.yml), [Ntp](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-ntp.yml),
[Api Code](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-api_code.yml), [Smtp](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-smtp.yml),
[Nginx](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-nginx.yml)
- [Mysql](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-mysql.yml), [PostgreSQL](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-postgresql.yml),
[MariaDB](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-mariadb.yml), [Redis](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-redis.yml),
[ElasticSearch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-elasticsearch.yml), [SqlServer](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-sqlserver.yml),
[Oracle](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-oracle.yml), [MongoDB](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-mongodb.yml),
[DM](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-dm.yml), [OpenGauss](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-opengauss.yml),
[ClickHouse](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-clickhouse.yml), [IoTDB](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-iotdb.yml),
[Redis Cluster](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-redis_cluster.yml), [Redis Sentinel](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-redis_sentinel.yml)
[Doris BE](https://github.com/apache/hertzbeat/blob/master/hertzbeat-manager/src/main/resources/define/app-doris_be.yml), [Doris FE](https://github.com/apache/hertzbeat/blob/master/hertzbeat-manager/src/main/resources/define/app-doris_fe.yml),
[Memcached](https://github.com/apache/hertzbeat/blob/master/hertzbeat-manager/src/main/resources/define/app-memcached.yml), [NebulaGraph](https://github.com/apache/hertzbeat/blob/master/hertzbeat-manager/src/main/resources/define/app-nebula_graph.yml)
- [Linux](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-linux.yml), [Ubuntu](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-ubuntu.yml),
[CentOS](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-centos.yml), [Windows](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-windows.yml),
[EulerOS](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-euleros.yml), [Fedora CoreOS](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-coreos.yml),
[OpenSUSE](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-opensuse.yml), [Rocky Linux](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-rockylinux.yml),
[Red Hat](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-redhat.yml), [FreeBSD](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-freebsd.yml),
[AlmaLinux](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-almalinux.yml), [Debian Linux](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-debian.yml)
- [Tomcat](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-tomcat.yml), [Nacos](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-nacos.yml),
[Zookeeper](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-zookeeper.yml), [RabbitMQ](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-rabbitmq.yml),
[Flink](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-flink.yml), [Kafka](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-kafka.yml),
[ShenYu](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-shenyu.yml), [DynamicTp](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-dynamic_tp.yml),
[Jetty](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-jetty.yml), [ActiveMQ](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-activemq.yml),
[Spring Gateway](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-spring_gateway.yml), [EMQX MQTT](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-emqx.yml),
[AirFlow](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-airflow.yml), [Hive](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-hive.yml),
[Spark](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-spark.yml), [Hadoop](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-hadoop.yml)
- [Kubernetes](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-kubernetes.yml), [Docker](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-docker.yml)
- [CiscoSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-cisco_switch.yml), [HpeSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-hpe_switch.yml),
[HuaweiSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-huawei_switch.yml), [TpLinkSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-tplink_switch.yml),
[H3cSwitch](https://raw.githubusercontent.com/apache/hertzbeat/master/hertzbeat-manager/src/main/resources/define/app-h3c_switch.yml)
- その他、カスタマイズされたモニターテンプレート。
- 通知利用可能 `Discord` `Slack` `Telegram` `Email` `Dingtalk` `WeChat` `FeiShu` `Webhook` `SMS` `ServerChan`
## 🐕 クイックスタート
- HertzBeat をローカルに展開する場合は、以下のデプロイメントドキュメントを参照してください。
### 🍞 HertzBeatのインストール
> HertzBeatは、ソースコードのインストールとブート、Dockerコンテナの実行とインストールパッケージによるインストールとデプロイをサポートし、CPUアーキテクチャはx86/arm64をサポートします。
##### 方式1:Docker
1. `docker` で以下の指令を実行します:
```shell
docker run -d -p 1157:1157 -p 1158:1158 --name hertzbeat apache/hertzbeat
```
2. スタート:`http://localhost:4200`にアクセスします。デフォルトのアカウントとパスワード:`admin/hertzbeat`。
3. コレクタークラスタのデプロイメント(オプション)
```shell
docker run -d -e IDENTITY=custom-collector-name -e MANAGER_HOST=127.0.0.1 -e MANAGER_PORT=1158 --name hertzbeat-collector apache/hertzbeat-collector
```
- `-e IDENTITY=custom-collector-name` :コレクターのユニーク ID。
- `-e MODE=public` :実行モード(パブリッククラスタまたはプライベートクラウドエッジ)。
- `-e MANAGER_HOST=127.0.0.1` :メインhertzbeatサーバーのIP。
- `-e MANAGER_PORT=1158` :メインhertzbeatサーバポート。
詳細ステップ [通过 Docker 方式安装 HertzBeat](https://hertzbeat.apache.org/docs/start/docker-deploy)
##### 方式2:インストールパッケージ
1. リリースパッケージをダウンロード `hertzbeat-xx.tar.gz` [Download](https://hertzbeat.apache.org/docs/download)
2. HertzBeatのymlファイルを設定 `hertzbeat/config/application.yml` (オプション)
3. コマンド`$ ./bin/startup.sh`または`bin/startup.bat`を実行
4. スタート:`http://localhost:4200`にアクセスします。デフォルトのアカウントとパスワード:`admin/hertzbeat`
5. コレクタークラスタのデプロイメント(オプション)
- コレクターパッケージを別のホストにダウンロード `hertzbeat-collector-xx.tar.gz` [Download](https://hertzbeat.apache.org/docs/download)
- コレクターのymlファイルを設定 `hertzbeat-collector/config/application.yml`
```yaml
collector:
dispatch:
entrance:
netty:
enabled: true
identity: ${IDENTITY:}
mode: ${MODE:public}
manager-host: ${MANAGER_HOST:127.0.0.1}
manager-port: ${MANAGER_PORT:1158}
```
- `identity: ${IDENTITY:}`:コレクターのユニークID。
- `mode: ${MODE:public}`:実行モード(パブリッククラスタまたはプライベートクラウドエッジ)。
- `manager-host: ${MANAGER_HOST:127.0.0.1}`:メインhertzbeatサーバーのIP。
- `manager-port: ${MANAGER_PORT:1158}`:メインhertzbeatサーバポート。
- コマンド`$ ./bin/startup.sh`または`bin/startup.bat`を実行。
- `http://localhost:1157`にアクセスし、登録された新しいコレクターを見ることがでます。
詳細ステップ [通过安装包安装HertzBeat](https://hertzbeat.apache.org/docs/start/package-deploy)
##### 方式3:ローカルの実行
1. ローカルの実行には、バックエンドのプロジェクト`manager`とフロントエンドのプロジェクト`web-app`を起動する必要があります。
2. バックエンド:`maven3+`、`java17`と`lombok`の環境は必要です。`YML` 設定を修正し、Java仮想マシンパラメータに`--add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED` を追加し、`manager` を起動します。
3. フロントエンド:`nodejs npm angular-cli`の環境は必要です。ローカルのバックエンドが立ち上がったら、`web-app` ディレクトリで `ng serve --open` というコマンドを実行します。
4. スタート:`http://localhost:4200`にアクセスします。デフォルトのアカウントとパスワード:`admin/hertzbeat`。
詳細ステップ [貢献ガイド](CONTRIBUTING.md)
##### 方式4:Docker-Compose
[Docker-Compose 部署脚本](script/docker-compose)でpostgresql/mysqlデータベース、victoria-metrics、iotdb、またはtdengine時系列データベースとHertzbeat一括デプロイ。
詳細ステップ [通过 Docker-Compose 安装 HertzBeat](script/docker-compose/README.md)
##### 方式5:Kubernetes Helm Charts
Helm ChartでHertzBeatクラスタコンポーネントをKubernetesクラスタに一括デプロイ。
詳細ステップ [Artifact Hub](https://artifacthub.io/packages/helm/hertzbeat/hertzbeat)
**HAVE FUN**
## ✨ Contributors
Thanks these wonderful people, welcome to join us:
[貢献ガイド](CONTRIBUTING.md)
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tomsun28"><img src="https://avatars.githubusercontent.com/u/24788200?v=4?s=100" width="100px;" alt="tomsun28"/><br /><sub><b>tomsun28</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=tomsun28" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=tomsun28" title="Documentation">📖</a> <a href="#design-tomsun28" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wang1027-wqh"><img src="https://avatars.githubusercontent.com/u/71161318?v=4?s=100" width="100px;" alt="会编程的王学长"/><br /><sub><b>会编程的王学长</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wang1027-wqh" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=wang1027-wqh" title="Documentation">📖</a> <a href="#design-wang1027-wqh" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.maxkey.top/"><img src="https://avatars.githubusercontent.com/u/1563377?v=4?s=100" width="100px;" alt="MaxKey"/><br /><sub><b>MaxKey</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=shimingxy" title="Code">💻</a> <a href="#design-shimingxy" title="Design">🎨</a> <a href="#ideas-shimingxy" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://blog.gcdd.top/"><img src="https://avatars.githubusercontent.com/u/26523525?v=4?s=100" width="100px;" alt="观沧海"/><br /><sub><b>观沧海</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gcdd1993" title="Code">💻</a> <a href="#design-gcdd1993" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Agcdd1993" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/a25017012"><img src="https://avatars.githubusercontent.com/u/32265356?v=4?s=100" width="100px;" alt="yuye"/><br /><sub><b>yuye</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=a25017012" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=a25017012" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jx10086"><img src="https://avatars.githubusercontent.com/u/5323228?v=4?s=100" width="100px;" alt="jx10086"/><br /><sub><b>jx10086</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jx10086" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ajx10086" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/winnerTimer"><img src="https://avatars.githubusercontent.com/u/76024658?v=4?s=100" width="100px;" alt="winnerTimer"/><br /><sub><b>winnerTimer</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=winnerTimer" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AwinnerTimer" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/goo-kits"><img src="https://avatars.githubusercontent.com/u/13163673?v=4?s=100" width="100px;" alt="goo-kits"/><br /><sub><b>goo-kits</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=goo-kits" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Agoo-kits" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/brave4Time"><img src="https://avatars.githubusercontent.com/u/105094014?v=4?s=100" width="100px;" alt="brave4Time"/><br /><sub><b>brave4Time</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=brave4Time" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Abrave4Time" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/walkerlee-lab"><img src="https://avatars.githubusercontent.com/u/8426753?v=4?s=100" width="100px;" alt="WalkerLee"/><br /><sub><b>WalkerLee</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=walkerlee-lab" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Awalkerlee-lab" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fullofjoy"><img src="https://avatars.githubusercontent.com/u/30247571?v=4?s=100" width="100px;" alt="jianghang"/><br /><sub><b>jianghang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=fullofjoy" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Afullofjoy" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ChineseTony"><img src="https://avatars.githubusercontent.com/u/24618786?v=4?s=100" width="100px;" alt="ChineseTony"/><br /><sub><b>ChineseTony</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ChineseTony" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AChineseTony" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wyt199905"><img src="https://avatars.githubusercontent.com/u/85098809?v=4?s=100" width="100px;" alt="wyt199905"/><br /><sub><b>wyt199905</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wyt199905" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/weifuqing"><img src="https://avatars.githubusercontent.com/u/13931013?v=4?s=100" width="100px;" alt="卫傅庆"/><br /><sub><b>卫傅庆</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=weifuqing" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Aweifuqing" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zklmcookle"><img src="https://avatars.githubusercontent.com/u/107192352?v=4?s=100" width="100px;" alt="zklmcookle"/><br /><sub><b>zklmcookle</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zklmcookle" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DevilX5"><img src="https://avatars.githubusercontent.com/u/13269921?v=4?s=100" width="100px;" alt="DevilX5"/><br /><sub><b>DevilX5</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=DevilX5" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=DevilX5" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/djzeng"><img src="https://avatars.githubusercontent.com/u/14074864?v=4?s=100" width="100px;" alt="tea"/><br /><sub><b>tea</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=djzeng" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yangshihui"><img src="https://avatars.githubusercontent.com/u/28550208?v=4?s=100" width="100px;" alt="yangshihui"/><br /><sub><b>yangshihui</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yangshihui" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayangshihui" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/DreamGirl524"><img src="https://avatars.githubusercontent.com/u/81132838?v=4?s=100" width="100px;" alt="DreamGirl524"/><br /><sub><b>DreamGirl524</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=DreamGirl524" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=DreamGirl524" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gzwlly"><img src="https://avatars.githubusercontent.com/u/83171907?v=4?s=100" width="100px;" alt="gzwlly"/><br /><sub><b>gzwlly</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gzwlly" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cuipiheqiuqiu"><img src="https://avatars.githubusercontent.com/u/76642201?v=4?s=100" width="100px;" alt="cuipiheqiuqiu"/><br /><sub><b>cuipiheqiuqiu</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=cuipiheqiuqiu" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=cuipiheqiuqiu" title="Tests">⚠️</a> <a href="#design-cuipiheqiuqiu" title="Design">🎨</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/oyiyou"><img src="https://avatars.githubusercontent.com/u/39228891?v=4?s=100" width="100px;" alt="lambert"/><br /><sub><b>lambert</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=oyiyou" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://mroldx.xyz/"><img src="https://avatars.githubusercontent.com/u/34847828?v=4?s=100" width="100px;" alt="mroldx"/><br /><sub><b>mroldx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mroldx" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/woshiniusange"><img src="https://avatars.githubusercontent.com/u/91513022?v=4?s=100" width="100px;" alt="woshiniusange"/><br /><sub><b>woshiniusange</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=woshiniusange" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://vampireachao.github.io/"><img src="https://avatars.githubusercontent.com/u/52746628?v=4?s=100" width="100px;" alt="VampireAchao"/><br /><sub><b>VampireAchao</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=VampireAchao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ceilzcx"><img src="https://avatars.githubusercontent.com/u/48920254?v=4?s=100" width="100px;" alt="zcx"/><br /><sub><b>zcx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Ceilzcx" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACeilzcx" title="Bug reports">🐛</a> <a href="#design-Ceilzcx" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=Ceilzcx" title="Tests">⚠️</a> <a href="#blog-Ceilzcx" title="Blogposts">📝</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CharlieXCL"><img src="https://avatars.githubusercontent.com/u/91540487?v=4?s=100" width="100px;" alt="CharlieXCL"/><br /><sub><b>CharlieXCL</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=CharlieXCL" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Privauto"><img src="https://avatars.githubusercontent.com/u/36581456?v=4?s=100" width="100px;" alt="Privauto"/><br /><sub><b>Privauto</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Privauto" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Privauto" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/emrys-he"><img src="https://avatars.githubusercontent.com/u/5848915?v=4?s=100" width="100px;" alt="emrys"/><br /><sub><b>emrys</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=emrys-he" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SxLiuYu"><img src="https://avatars.githubusercontent.com/u/95198625?v=4?s=100" width="100px;" alt="SxLiuYu"/><br /><sub><b>SxLiuYu</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3ASxLiuYu" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://allcontributors.org"><img src="https://avatars.githubusercontent.com/u/46410174?v=4?s=100" width="100px;" alt="All Contributors"/><br /><sub><b>All Contributors</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=all-contributors" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gxc-myh"><img src="https://avatars.githubusercontent.com/u/85919258?v=4?s=100" width="100px;" alt="铁甲小宝"/><br /><sub><b>铁甲小宝</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gxc-myh" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=gxc-myh" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/click33"><img src="https://avatars.githubusercontent.com/u/36243476?v=4?s=100" width="100px;" alt="click33"/><br /><sub><b>click33</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=click33" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://jpom.io/"><img src="https://avatars.githubusercontent.com/u/16408873?v=4?s=100" width="100px;" alt="蒋小小"/><br /><sub><b>蒋小小</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bwcx-jzy" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.zhihu.com/people/kevinbauer"><img src="https://avatars.githubusercontent.com/u/28581579?v=4?s=100" width="100px;" alt="Kevin Huang"/><br /><sub><b>Kevin Huang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=kevinhuangwl" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TJxiaobao"><img src="https://avatars.githubusercontent.com/u/85919258?v=4?s=100" width="100px;" alt="铁甲小宝"/><br /><sub><b>铁甲小宝</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3ATJxiaobao" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=TJxiaobao" title="Tests">⚠️</a> <a href="#design-TJxiaobao" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jack-123-power"><img src="https://avatars.githubusercontent.com/u/84333501?v=4?s=100" width="100px;" alt="Captain Jack"/><br /><sub><b>Captain Jack</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Jack-123-power" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/haibo-duan"><img src="https://avatars.githubusercontent.com/u/7974845?v=4?s=100" width="100px;" alt="haibo.duan"/><br /><sub><b>haibo.duan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=haibo-duan" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=haibo-duan" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/assassinfym"><img src="https://avatars.githubusercontent.com/u/15188754?v=4?s=100" width="100px;" alt="assassin"/><br /><sub><b>assassin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3Aassassinfym" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=assassinfym" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/csyshu"><img src="https://avatars.githubusercontent.com/u/46591658?v=4?s=100" width="100px;" alt="Reverse wind"/><br /><sub><b>Reverse wind</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=csyshu" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=csyshu" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/luxx-lq"><img src="https://avatars.githubusercontent.com/u/58515565?v=4?s=100" width="100px;" alt="luxx"/><br /><sub><b>luxx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=luxx-lq" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=100" width="100px;" alt="Ikko Ashimine"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=eltociear" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zenan08"><img src="https://avatars.githubusercontent.com/u/80514991?v=4?s=100" width="100px;" alt="leizenan"/><br /><sub><b>leizenan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zenan08" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BKing2020"><img src="https://avatars.githubusercontent.com/u/28869121?v=4?s=100" width="100px;" alt="BKing"/><br /><sub><b>BKing</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=BKing2020" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xingshuaiLi"><img src="https://avatars.githubusercontent.com/u/119487588?v=4?s=100" width="100px;" alt="xingshuaiLi"/><br /><sub><b>xingshuaiLi</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xingshuaiLi" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wangke6666"><img src="https://avatars.githubusercontent.com/u/113656595?v=4?s=100" width="100px;" alt="wangke6666"/><br /><sub><b>wangke6666</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wangke6666" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LWBobo"><img src="https://avatars.githubusercontent.com/u/50368698?v=4?s=100" width="100px;" alt="刺猬"/><br /><sub><b>刺猬</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/issues?q=author%3ALWBobo" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=LWBobo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.zanglikun.com"><img src="https://avatars.githubusercontent.com/u/61591648?v=4?s=100" width="100px;" alt="Haste"/><br /><sub><b>Haste</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zanglikun" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SuitSmile"><img src="https://avatars.githubusercontent.com/u/38679717?v=4?s=100" width="100px;" alt="zhongshi.yi"/><br /><sub><b>zhongshi.yi</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=SuitSmile" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://www.smallq.cn"><img src="https://avatars.githubusercontent.com/u/39754275?v=4?s=100" width="100px;" alt="Qi Zhang"/><br /><sub><b>Qi Zhang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zzzhangqi" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MrAndyMing"><img src="https://avatars.githubusercontent.com/u/49541483?v=4?s=100" width="100px;" alt="MrAndyMing"/><br /><sub><b>MrAndyMing</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MrAndyMing" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://idongliming.github.io/"><img src="https://avatars.githubusercontent.com/u/31564353?v=4?s=100" width="100px;" alt="idongliming"/><br /><sub><b>idongliming</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=idongliming" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://earthjasonlin.github.io"><img src="https://avatars.githubusercontent.com/u/83632110?v=4?s=100" width="100px;" alt="Zichao Lin"/><br /><sub><b>Zichao Lin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=earthjasonlin" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=earthjasonlin" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://blog.liudonghua.com"><img src="https://avatars.githubusercontent.com/u/2276718?v=4?s=100" width="100px;" alt="liudonghua"/><br /><sub><b>liudonghua</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=liudonghua123" title="Code">💻</a> <a href="#ideas-liudonghua123" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/orangeyts"><img src="https://avatars.githubusercontent.com/u/4250869?v=4?s=100" width="100px;" alt="Jerry"/><br /><sub><b>Jerry</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=orangeyts" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=orangeyts" title="Tests">⚠️</a> <a href="#ideas-orangeyts" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://dynamictp.cn"><img src="https://avatars.githubusercontent.com/u/13051908?v=4?s=100" width="100px;" alt="yanhom"/><br /><sub><b>yanhom</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yanhom1314" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://www.jianshu.com/u/a8f822c04f67"><img src="https://avatars.githubusercontent.com/u/18587688?v=4?s=100" width="100px;" alt="fsl"/><br /><sub><b>fsl</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=fengshunli" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xttttv"><img src="https://avatars.githubusercontent.com/u/116323904?v=4?s=100" width="100px;" alt="xttttv"/><br /><sub><b>xttttv</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xttttv" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NavinKumarBarnwal"><img src="https://avatars.githubusercontent.com/u/44504274?v=4?s=100" width="100px;" alt="NavinKumarBarnwal"/><br /><sub><b>NavinKumarBarnwal</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=NavinKumarBarnwal" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/z641205699"><img src="https://avatars.githubusercontent.com/u/45276423?v=4?s=100" width="100px;" alt="Zakkary"/><br /><sub><b>Zakkary</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=z641205699" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/898349230"><img src="https://avatars.githubusercontent.com/u/21972532?v=4?s=100" width="100px;" alt="sunxinbo"/><br /><sub><b>sunxinbo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=898349230" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=898349230" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ldzbook"><img src="https://avatars.githubusercontent.com/u/13903790?v=4?s=100" width="100px;" alt="ldzbook"/><br /><sub><b>ldzbook</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ldzbook" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Aldzbook" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SurryChen"><img src="https://avatars.githubusercontent.com/u/91116490?v=4?s=100" width="100px;" alt="余与雨"/><br /><sub><b>余与雨</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=SurryChen" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=SurryChen" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MysticalDream"><img src="https://avatars.githubusercontent.com/u/78899028?v=4?s=100" width="100px;" alt="MysticalDream"/><br /><sub><b>MysticalDream</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MysticalDream" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=MysticalDream" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zhouyoulin12"><img src="https://avatars.githubusercontent.com/u/17086633?v=4?s=100" width="100px;" alt="zhouyoulin12"/><br /><sub><b>zhouyoulin12</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zhouyoulin12" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=zhouyoulin12" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jerjjj"><img src="https://avatars.githubusercontent.com/u/93431283?v=4?s=100" width="100px;" alt="jerjjj"/><br /><sub><b>jerjjj</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jerjjj" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://wjl110.xyz/"><img src="https://avatars.githubusercontent.com/u/53851034?v=4?s=100" width="100px;" alt="wjl110"/><br /><sub><b>wjl110</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wjl110" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ngyhd"><img src="https://avatars.githubusercontent.com/u/29095207?v=4?s=100" width="100px;" alt="Sean"/><br /><sub><b>Sean</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ngyhd" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Daydreamer-ia"><img src="https://avatars.githubusercontent.com/u/83362909?v=4?s=100" width="100px;" alt="chenyiqin"/><br /><sub><b>chenyiqin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Daydreamer-ia" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Daydreamer-ia" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hudongdong129"><img src="https://avatars.githubusercontent.com/u/34374227?v=4?s=100" width="100px;" alt="hudongdong129"/><br /><sub><b>hudongdong129</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=hudongdong129" title="Documentation">📖</a> <a href="#design-hudongdong129" title="Design">🎨</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TherChenYang"><img src="https://avatars.githubusercontent.com/u/124348939?v=4?s=100" width="100px;" alt="TherChenYang"/><br /><sub><b>TherChenYang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=TherChenYang" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=TherChenYang" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/HattoriHenzo"><img src="https://avatars.githubusercontent.com/u/5141285?v=4?s=100" width="100px;" alt="HattoriHenzo"/><br /><sub><b>HattoriHenzo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=HattoriHenzo" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=HattoriHenzo" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ycilry"><img src="https://avatars.githubusercontent.com/u/63967101?v=4?s=100" width="100px;" alt="ycilry"/><br /><sub><b>ycilry</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ycilry" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aoshiguchen"><img src="https://avatars.githubusercontent.com/u/10580997?v=4?s=100" width="100px;" alt="aoshiguchen"/><br /><sub><b>aoshiguchen</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=aoshiguchen" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=aoshiguchen" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/caibenxiang"><img src="https://avatars.githubusercontent.com/u/4568241?v=4?s=100" width="100px;" alt="蔡本祥"/><br /><sub><b>蔡本祥</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=caibenxiang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.fckeverything.cn:4000/"><img src="https://avatars.githubusercontent.com/u/13827124?v=4?s=100" width="100px;" alt="浮游"/><br /><sub><b>浮游</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lifefloating" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Grass-Life"><img src="https://avatars.githubusercontent.com/u/114381513?v=4?s=100" width="100px;" alt="Grass-Life"/><br /><sub><b>Grass-Life</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Grass-Life" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xiaohe428"><img src="https://avatars.githubusercontent.com/u/99130317?v=4?s=100" width="100px;" alt="xiaohe428"/><br /><sub><b>xiaohe428</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xiaohe428" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=xiaohe428" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/baiban114"><img src="https://avatars.githubusercontent.com/u/59152619?v=4?s=100" width="100px;" alt="TableRow"/><br /><sub><b>TableRow</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=baiban114" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=baiban114" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ByteIDance"><img src="https://avatars.githubusercontent.com/u/100207562?v=4?s=100" width="100px;" alt="ByteIDance"/><br /><sub><b>ByteIDance</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ByteIDance" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mangel2002"><img src="https://avatars.githubusercontent.com/u/9348020?v=4?s=100" width="100px;" alt="Jangfe"/><br /><sub><b>Jangfe</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mangel2002" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zqr10159"><img src="https://avatars.githubusercontent.com/u/30048352?v=4?s=100" width="100px;" alt="zqr10159"/><br /><sub><b>zqr10159</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Code">💻</a> <a href="#blog-zqr10159" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Azqr10159" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=zqr10159" title="Tests">⚠️</a> <a href="#design-zqr10159" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vinci-897"><img src="https://avatars.githubusercontent.com/u/55838224?v=4?s=100" width="100px;" alt="vinci"/><br /><sub><b>vinci</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=vinci-897" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=vinci-897" title="Documentation">📖</a> <a href="#design-vinci-897" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/js110"><img src="https://avatars.githubusercontent.com/u/51191863?v=4?s=100" width="100px;" alt="js110"/><br /><sub><b>js110</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=js110" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JavaLionLi"><img src="https://avatars.githubusercontent.com/u/31852897?v=4?s=100" width="100px;" alt="CrazyLionLi"/><br /><sub><b>CrazyLionLi</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=JavaLionLi" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.banmajio.com"><img src="https://avatars.githubusercontent.com/u/53471385?v=4?s=100" width="100px;" alt="banmajio"/><br /><sub><b>banmajio</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=banmajio" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://suder.fun"><img src="https://avatars.githubusercontent.com/u/69955165?v=4?s=100" width="100px;" alt="topsuder"/><br /><sub><b>topsuder</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=topsuder" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/richar2022"><img src="https://avatars.githubusercontent.com/u/129016397?v=4?s=100" width="100px;" alt="richar2022"/><br /><sub><b>richar2022</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=richar2022" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fcb-xiaobo"><img src="https://avatars.githubusercontent.com/u/60566194?v=4?s=100" width="100px;" alt="fcb-xiaobo"/><br /><sub><b>fcb-xiaobo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=fcb-xiaobo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wenkyzhang"><img src="https://avatars.githubusercontent.com/u/13983669?v=4?s=100" width="100px;" alt="wenkyzhang"/><br /><sub><b>wenkyzhang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wenkyzhang" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZangJuxy"><img src="https://avatars.githubusercontent.com/u/71380295?v=4?s=100" width="100px;" alt="ZangJuxy"/><br /><sub><b>ZangJuxy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZangJuxy" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/l646505418"><img src="https://avatars.githubusercontent.com/u/50475131?v=4?s=100" width="100px;" alt="l646505418"/><br /><sub><b>l646505418</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=l646505418" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Al646505418" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.carpewang.com"><img src="https://avatars.githubusercontent.com/u/78642589?v=4?s=100" width="100px;" alt="Carpe-Wang"/><br /><sub><b>Carpe-Wang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Carpe-Wang" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACarpe-Wang" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/moshu023"><img src="https://avatars.githubusercontent.com/u/48593205?v=4?s=100" width="100px;" alt="莫枢"/><br /><sub><b>莫枢</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=moshu023" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/huangcanda"><img src="https://avatars.githubusercontent.com/u/4470566?v=4?s=100" width="100px;" alt="huangcanda"/><br /><sub><b>huangcanda</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=huangcanda" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.zrkizzy.com"><img src="https://avatars.githubusercontent.com/u/85340613?v=4?s=100" width="100px;" alt="世纪末的架构师"/><br /><sub><b>世纪末的架构师</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Architect-Java" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ShuningWan"><img src="https://avatars.githubusercontent.com/u/31086770?v=4?s=100" width="100px;" alt="ShuningWan"/><br /><sub><b>ShuningWan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ShuningWan" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MrYZhou"><img src="https://avatars.githubusercontent.com/u/44339602?v=4?s=100" width="100px;" alt="MrYZhou"/><br /><sub><b>MrYZhou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MrYZhou" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/suncqujsj"><img src="https://avatars.githubusercontent.com/u/8012932?v=4?s=100" width="100px;" alt="suncqujsj"/><br /><sub><b>suncqujsj</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=suncqujsj" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sunqinbo"><img src="https://avatars.githubusercontent.com/u/1428540?v=4?s=100" width="100px;" alt="sunqinbo"/><br /><sub><b>sunqinbo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=sunqinbo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/haoww"><img src="https://avatars.githubusercontent.com/u/32739294?v=4?s=100" width="100px;" alt="haoww"/><br /><sub><b>haoww</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=haoww" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/i-mayuan"><img src="https://avatars.githubusercontent.com/u/101498477?v=4?s=100" width="100px;" alt="i-mayuan"/><br /><sub><b>i-mayuan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=i-mayuan" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fengruge"><img src="https://avatars.githubusercontent.com/u/85803831?v=4?s=100" width="100px;" alt="fengruge"/><br /><sub><b>fengruge</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=fengruge" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aystzh"><img src="https://avatars.githubusercontent.com/u/38125392?v=4?s=100" width="100px;" alt="zhanghuan"/><br /><sub><b>zhanghuan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=aystzh" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/shenyumin"><img src="https://avatars.githubusercontent.com/u/8438506?v=4?s=100" width="100px;" alt="shenymin"/><br /><sub><b>shenymin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=shenyumin" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dhruva1995"><img src="https://avatars.githubusercontent.com/u/12976351?v=4?s=100" width="100px;" alt="Dhruva Chandra"/><br /><sub><b>Dhruva Chandra</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=dhruva1995" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/weiwang988"><img src="https://avatars.githubusercontent.com/u/58241726?v=4?s=100" width="100px;" alt="miss_z"/><br /><sub><b>miss_z</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=weiwang988" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wyt990"><img src="https://avatars.githubusercontent.com/u/86013697?v=4?s=100" width="100px;" alt="wyt990"/><br /><sub><b>wyt990</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wyt990" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/licocon"><img src="https://avatars.githubusercontent.com/u/36863277?v=4?s=100" width="100px;" alt="licocon"/><br /><sub><b>licocon</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=licocon" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/2406450951"><img src="https://avatars.githubusercontent.com/u/48074721?v=4?s=100" width="100px;" alt="Mi Na"/><br /><sub><b>Mi Na</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=2406450951" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Kylin-Guo"><img src="https://avatars.githubusercontent.com/u/131239856?v=4?s=100" width="100px;" alt="Kylin-Guo"/><br /><sub><b>Kylin-Guo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Kylin-Guo" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/1797899698"><img src="https://avatars.githubusercontent.com/u/40411650?v=4?s=100" width="100px;" alt="Mr灬Dong先生"/><br /><sub><b>Mr灬Dong先生</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=1797899698" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="http://neilblaze.live"><img src="https://avatars.githubusercontent.com/u/48355572?v=4?s=100" width="100px;" alt="Pratyay Banerjee"/><br /><sub><b>Pratyay Banerjee</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Neilblaze" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=Neilblaze" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yujianzhong520"><img src="https://avatars.githubusercontent.com/u/63705063?v=4?s=100" width="100px;" alt="yujianzhong520"/><br /><sub><b>yujianzhong520</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yujianzhong520" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://sppan24.github.io/"><img src="https://avatars.githubusercontent.com/u/15795173?v=4?s=100" width="100px;" alt="SPPan"/><br /><sub><b>SPPan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=sppan24" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/1130600015"><img src="https://avatars.githubusercontent.com/u/67859663?v=4?s=100" width="100px;" alt="ZhangJiashu"/><br /><sub><b>ZhangJiashu</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=1130600015" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/QZmp236478"><img src="https://avatars.githubusercontent.com/u/56623162?v=4?s=100" width="100px;" alt="impress"/><br /><sub><b>impress</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=QZmp236478" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jx3775250"><img src="https://avatars.githubusercontent.com/u/40455946?v=4?s=100" width="100px;" alt="凌晨一点半"/><br /><sub><b>凌晨一点半</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jx3775250" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/eeshaanSA"><img src="https://avatars.githubusercontent.com/u/100678386?v=4?s=100" width="100px;" alt="Eeshaan Sawant"/><br /><sub><b>Eeshaan Sawant</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=eeshaanSA" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nandofromthebando"><img src="https://avatars.githubusercontent.com/u/87321214?v=4?s=100" width="100px;" alt="nandofromthebando"/><br /><sub><b>nandofromthebando</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=nandofromthebando" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/caiboking"><img src="https://avatars.githubusercontent.com/u/6509883?v=4?s=100" width="100px;" alt="caiboking"/><br /><sub><b>caiboking</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=caiboking" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/baixing99"><img src="https://avatars.githubusercontent.com/u/73473087?v=4?s=100" width="100px;" alt="baixing99"/><br /><sub><b>baixing99</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=baixing99" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ifrenzyc"><img src="https://avatars.githubusercontent.com/u/543927?v=4?s=100" width="100px;" alt="Yang Chuang"/><br /><sub><b>Yang Chuang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ifrenzyc" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wlin20"><img src="https://avatars.githubusercontent.com/u/20657577?v=4?s=100" width="100px;" alt="wlin20"/><br /><sub><b>wlin20</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wlin20" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/guojing1983"><img src="https://avatars.githubusercontent.com/u/60596094?v=4?s=100" width="100px;" alt="guojing1983"/><br /><sub><b>guojing1983</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=guojing1983" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/itxxq"><img src="https://avatars.githubusercontent.com/u/46962357?v=4?s=100" width="100px;" alt="moxi"/><br /><sub><b>moxi</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=itxxq" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qq471754603"><img src="https://avatars.githubusercontent.com/u/23146592?v=4?s=100" width="100px;" alt="qq471754603"/><br /><sub><b>qq471754603</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=qq471754603" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/san346596324"><img src="https://avatars.githubusercontent.com/u/30828520?v=4?s=100" width="100px;" alt="渭雨"/><br /><sub><b>渭雨</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=san346596324" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/luoxuanzao"><img src="https://avatars.githubusercontent.com/u/44692579?v=4?s=100" width="100px;" alt="liuxuezhuo"/><br /><sub><b>liuxuezhuo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=luoxuanzao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lisongning"><img src="https://avatars.githubusercontent.com/u/93140178?v=4?s=100" width="100px;" alt="lisongning"/><br /><sub><b>lisongning</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lisongning" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/YutingNie"><img src="https://avatars.githubusercontent.com/u/104416402?v=4?s=100" width="100px;" alt="YutingNie"/><br /><sub><b>YutingNie</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=YutingNie" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=YutingNie" title="Documentation">📖</a> <a href="#design-YutingNie" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mikezzb"><img src="https://avatars.githubusercontent.com/u/23418428?v=4?s=100" width="100px;" alt="Mike Zhou"/><br /><sub><b>Mike Zhou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mikezzb" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=mikezzb" title="Documentation">📖</a> <a href="#design-mikezzb" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/a-little-fool"><img src="https://avatars.githubusercontent.com/u/105542329?v=4?s=100" width="100px;" alt="小笨蛋"/><br /><sub><b>小笨蛋</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=a-little-fool" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=a-little-fool" title="Documentation">📖</a> <a href="#blog-a-little-fool" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Aa-little-fool" title="Bug reports">🐛</a> <a href="#design-a-little-fool" title="Design">🎨</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/littlezhongzer"><img src="https://avatars.githubusercontent.com/u/33685289?v=4?s=100" width="100px;" alt="littlezhongzer"/><br /><sub><b>littlezhongzer</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=littlezhongzer" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ChenXiangxxxxx"><img src="https://avatars.githubusercontent.com/u/90089594?v=4?s=100" width="100px;" alt="ChenXiangxxxxx"/><br /><sub><b>ChenXiangxxxxx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ChenXiangxxxxx" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Mr-zhou315"><img src="https://avatars.githubusercontent.com/u/10276100?v=4?s=100" width="100px;" alt="Mr.zhou"/><br /><sub><b>Mr.zhou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Mr-zhou315" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/XimfengYao"><img src="https://avatars.githubusercontent.com/u/17541537?v=4?s=100" width="100px;" alt="姚贤丰"/><br /><sub><b>姚贤丰</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=XimfengYao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LINGLUOJUN"><img src="https://avatars.githubusercontent.com/u/16778977?v=4?s=100" width="100px;" alt="lingluojun"/><br /><sub><b>lingluojun</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LINGLUOJUN" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.luelueking.com"><img src="https://avatars.githubusercontent.com/u/93204032?v=4?s=100" width="100px;" alt="1ue"/><br /><sub><b>1ue</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=luelueking" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.jimmyqiao.top"><img src="https://avatars.githubusercontent.com/u/67301054?v=4?s=100" width="100px;" alt="qyaaaa"/><br /><sub><b>qyaaaa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=qyaaaa" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Aqyaaaa" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://novohit.top"><img src="https://avatars.githubusercontent.com/u/101090395?v=4?s=100" width="100px;" alt="novohit"/><br /><sub><b>novohit</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=novohit" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rbsrcy"><img src="https://avatars.githubusercontent.com/u/4798540?v=4?s=100" width="100px;" alt="zhuoshangyi"/><br /><sub><b>zhuoshangyi</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=rbsrcy" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ruanliang-hualun"><img src="https://avatars.githubusercontent.com/u/65543716?v=4?s=100" width="100px;" alt="ruanliang"/><br /><sub><b>ruanliang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ruanliang-hualun" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=ruanliang-hualun" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Eden4701"><img src="https://avatars.githubusercontent.com/u/68422437?v=4?s=100" width="100px;" alt="Eden4701"/><br /><sub><b>Eden4701</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Eden4701" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Eden4701" title="Documentation">📖</a> <a href="#design-Eden4701" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/XiaTian688"><img src="https://avatars.githubusercontent.com/u/111830921?v=4?s=100" width="100px;" alt="XiaTian688"/><br /><sub><b>XiaTian688</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=XiaTian688" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/liyin"><img src="https://avatars.githubusercontent.com/u/863169?v=4?s=100" width="100px;" alt="liyinjiang"/><br /><sub><b>liyinjiang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=liyin" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jiashu1024"><img src="https://avatars.githubusercontent.com/u/67859663?v=4?s=100" width="100px;" alt="ZhangJiashu"/><br /><sub><b>ZhangJiashu</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jiashu1024" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/1036664317"><img src="https://avatars.githubusercontent.com/u/7696697?v=4?s=100" width="100px;" alt="moghn"/><br /><sub><b>moghn</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=1036664317" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xiaoguolong"><img src="https://avatars.githubusercontent.com/u/33684988?v=4?s=100" width="100px;" alt="xiaoguolong"/><br /><sub><b>xiaoguolong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xiaoguolong" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Clownsw"><img src="https://avatars.githubusercontent.com/u/28394742?v=4?s=100" width="100px;" alt="Smliexx"/><br /><sub><b>Smliexx</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Clownsw" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AClownsw" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Calvin979"><img src="https://avatars.githubusercontent.com/u/131688897?v=4?s=100" width="100px;" alt="Naruse"/><br /><sub><b>Naruse</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Code">💻</a> <a href="#design-Calvin979" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ACalvin979" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=Calvin979" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bbelide2"><img src="https://avatars.githubusercontent.com/u/26840796?v=4?s=100" width="100px;" alt="Bala Sukesh"/><br /><sub><b>Bala Sukesh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bbelide2" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jinyaoMa"><img src="https://avatars.githubusercontent.com/u/25066570?v=4?s=100" width="100px;" alt="Jinyao Ma"/><br /><sub><b>Jinyao Ma</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jinyaoMa" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://linuxsuren.github.io/open-source-best-practice/"><img src="https://avatars.githubusercontent.com/u/1450685?v=4?s=100" width="100px;" alt="Rick"/><br /><sub><b>Rick</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LinuxSuRen" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=LinuxSuRen" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZY945"><img src="https://avatars.githubusercontent.com/u/74083801?v=4?s=100" width="100px;" alt="东风"/><br /><sub><b>东风</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Code">💻</a> <a href="#design-ZY945" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=ZY945" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AZY945" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/prolevel1"><img src="https://avatars.githubusercontent.com/u/51995525?v=4?s=100" width="100px;" alt="sonam singh"/><br /><sub><b>sonam singh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=prolevel1" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ZhangZixuan1994"><img src="https://avatars.githubusercontent.com/u/20011653?v=4?s=100" width="100px;" alt="ZhangZixuan1994"/><br /><sub><b>ZhangZixuan1994</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ZhangZixuan1994" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hurenjie1"><img src="https://avatars.githubusercontent.com/u/40120355?v=4?s=100" width="100px;" alt="SHIG"/><br /><sub><b>SHIG</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hurenjie1" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://tslj1024.github.io/"><img src="https://avatars.githubusercontent.com/u/155222677?v=4?s=100" width="100px;" alt="泰上老菌"/><br /><sub><b>泰上老菌</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=tslj1024" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ldysdu"><img src="https://avatars.githubusercontent.com/u/15815338?v=4?s=100" width="100px;" alt="ldysdu"/><br /><sub><b>ldysdu</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ldysdu" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GEM0816g"><img src="https://avatars.githubusercontent.com/u/85116017?v=4?s=100" width="100px;" alt="梁同学"/><br /><sub><b>梁同学</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=GEM0816g" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/avvCode"><img src="https://avatars.githubusercontent.com/u/113538532?v=4?s=100" width="100px;" alt="avv"/><br /><sub><b>avv</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=avvCode" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yqxxgh"><img src="https://avatars.githubusercontent.com/u/42080876?v=4?s=100" width="100px;" alt="yqxxgh"/><br /><sub><b>yqxxgh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yqxxgh" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=yqxxgh" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayqxxgh" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CharlieShi46"><img src="https://avatars.githubusercontent.com/u/149798885?v=4?s=100" width="100px;" alt="CharlieShi46"/><br /><sub><b>CharlieShi46</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=CharlieShi46" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Nctllnty"><img src="https://avatars.githubusercontent.com/u/33241818?v=4?s=100" width="100px;" alt="Nctllnty"/><br /><sub><b>Nctllnty</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Nctllnty" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Wang-Yonghao"><img src="https://avatars.githubusercontent.com/u/48146606?v=4?s=100" width="100px;" alt="Wang-Yonghao"/><br /><sub><b>Wang-Yonghao</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Wang-Yonghao" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.yuque.com/dudiao/yy"><img src="https://avatars.githubusercontent.com/u/38355949?v=4?s=100" width="100px;" alt="读钓"/><br /><sub><b>读钓</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=dudiao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starmilkxin"><img src="https://avatars.githubusercontent.com/u/55646681?v=4?s=100" width="100px;" alt="Xin"/><br /><sub><b>Xin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=starmilkxin" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Astarmilkxin" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/handy-git"><img src="https://avatars.githubusercontent.com/u/32837980?v=4?s=100" width="100px;" alt="handy"/><br /><sub><b>handy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=handy-git" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LiuTianyou"><img src="https://avatars.githubusercontent.com/u/30208283?v=4?s=100" width="100px;" alt="LiuTianyou"/><br /><sub><b>LiuTianyou</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ALiuTianyou" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=LiuTianyou" title="Tests">⚠️</a> <a href="#blog-LiuTianyou" title="Blogposts">📝</a> <a href="#design-LiuTianyou" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/WinterKi1ler"><img src="https://avatars.githubusercontent.com/u/160592092?v=4?s=100" width="100px;" alt="WinterKi1ler"/><br /><sub><b>WinterKi1ler</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=WinterKi1ler" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://sharehoo.cn/"><img src="https://avatars.githubusercontent.com/u/45377370?v=4?s=100" width="100px;" alt="miki"/><br /><sub><b>miki</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=miki-hmt" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://codeflex.substack.com/"><img src="https://avatars.githubusercontent.com/u/85513042?v=4?s=100" width="100px;" alt="Keshav Carpenter"/><br /><sub><b>Keshav Carpenter</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=alpha951" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=alpha951" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/makechoicenow"><img src="https://avatars.githubusercontent.com/u/9911918?v=4?s=100" width="100px;" alt="makechoicenow"/><br /><sub><b>makechoicenow</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=makechoicenow" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gjjjj0101"><img src="https://avatars.githubusercontent.com/u/71874373?v=4?s=100" width="100px;" alt="Gao Jian"/><br /><sub><b>Gao Jian</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Tests">⚠️</a> <a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=gjjjj0101" title="Documentation">📖</a> <a href="#design-gjjjj0101" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Agjjjj0101" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://jangto.tistory.com/"><img src="https://avatars.githubusercontent.com/u/37864182?v=4?s=100" width="100px;" alt="Hyeon Sung"/><br /><sub><b>Hyeon Sung</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=dukbong" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=dukbong" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://crossoverjie.top/"><img src="https://avatars.githubusercontent.com/u/15684156?v=4?s=100" width="100px;" alt="crossoverJie"/><br /><sub><b>crossoverJie</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Documentation">📖</a> <a href="#blog-crossoverJie" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/commits?author=crossoverJie" title="Tests">⚠️</a> <a href="#design-crossoverJie" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PeixyJ"><img src="https://avatars.githubusercontent.com/u/45998593?v=4?s=100" width="100px;" alt="PeixyJ"/><br /><sub><b>PeixyJ</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=PeixyJ" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Hi-Mr-Wind"><img src="https://avatars.githubusercontent.com/u/85803831?v=4?s=100" width="100px;" alt="风如歌"/><br /><sub><b>风如歌</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Hi-Mr-Wind" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MananPoojara"><img src="https://avatars.githubusercontent.com/u/104253184?v=4?s=100" width="100px;" alt="Manan Pujara"/><br /><sub><b>Manan Pujara</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MananPoojara" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xuziyang"><img src="https://avatars.githubusercontent.com/u/8465969?v=4?s=100" width="100px;" alt="xuziyang"/><br /><sub><b>xuziyang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xuziyang" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=xuziyang" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Axuziyang" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lwqzz"><img src="https://avatars.githubusercontent.com/u/62584513?v=4?s=100" width="100px;" alt="lwqzz"/><br /><sub><b>lwqzz</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lwqzz" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/YxYL6125"><img src="https://avatars.githubusercontent.com/u/91076160?v=4?s=100" width="100px;" alt="YxYL"/><br /><sub><b>YxYL</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=YxYL6125" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tomorrowshipyltm"><img src="https://avatars.githubusercontent.com/u/61336903?v=4?s=100" width="100px;" alt="tomorrowshipyltm"/><br /><sub><b>tomorrowshipyltm</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=tomorrowshipyltm" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/15613060203"><img src="https://avatars.githubusercontent.com/u/41351615?v=4?s=100" width="100px;" alt="栗磊"/><br /><sub><b>栗磊</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=15613060203" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Alanxtl"><img src="https://avatars.githubusercontent.com/u/25652981?v=4?s=100" width="100px;" alt="Alan"/><br /><sub><b>Alan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Alanxtl" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.hadoop.wiki/"><img src="https://avatars.githubusercontent.com/u/29418975?v=4?s=100" width="100px;" alt="Jast"/><br /><sub><b>Jast</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Code">💻</a> <a href="#ideas-zhangshenghang" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Documentation">📖</a> <a href="#blog-zhangshenghang" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Azhangshenghang" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=zhangshenghang" title="Tests">⚠️</a> <a href="#design-zhangshenghang" title="Design">🎨</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zuobiao-zhou"><img src="https://avatars.githubusercontent.com/u/61108539?v=4?s=100" width="100px;" alt="Zhang Yuxuan"/><br /><sub><b>Zhang Yuxuan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Azuobiao-zhou" title="Bug reports">🐛</a> <a href="#blog-zuobiao-zhou" title="Blogposts">📝</a> <a href="https://github.com/apache/hertzbeat/commits?author=zuobiao-zhou" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Pzz-2021"><img src="https://avatars.githubusercontent.com/u/118056735?v=4?s=100" width="100px;" alt="P.P."/><br /><sub><b>P.P.</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Pzz-2021" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LLP2333"><img src="https://avatars.githubusercontent.com/u/61670545?v=4?s=100" width="100px;" alt="llp2333"/><br /><sub><b>llp2333</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LLP2333" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/HeartLinked"><img src="https://avatars.githubusercontent.com/u/78212101?v=4?s=100" width="100px;" alt="feiyang li"/><br /><sub><b>feiyang li</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=HeartLinked" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Aias00"><img src="https://avatars.githubusercontent.com/u/25810623?v=4?s=100" width="100px;" alt="aias00"/><br /><sub><b>aias00</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AAias00" title="Bug reports">🐛</a> <a href="#ideas-Aias00" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/apache/hertzbeat/commits?author=Aias00" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/westboy"><img src="https://avatars.githubusercontent.com/u/6385565?v=4?s=100" width="100px;" alt="Jin"/><br /><sub><b>Jin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=westboy" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://blog.csdn.net/qq_52397471"><img src="https://avatars.githubusercontent.com/u/77964041?v=4?s=100" width="100px;" alt="YuLuo"/><br /><sub><b>YuLuo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yuluo-yx" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayuluo-yx" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=yuluo-yx" title="Tests">⚠️</a> <a href="#blog-yuluo-yx" title="Blogposts">📝</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Yanshuming1"><img src="https://avatars.githubusercontent.com/u/118667222?v=4?s=100" width="100px;" alt="linDong"/><br /><sub><b>linDong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Yanshuming1" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Yanshuming1" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AYanshuming1" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lwjxy"><img src="https://avatars.githubusercontent.com/u/52726400?v=4?s=100" width="100px;" alt="lwjxy"/><br /><sub><b>lwjxy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lwjxy" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://thespica.github.io/"><img src="https://avatars.githubusercontent.com/u/119573640?v=4?s=100" width="100px;" alt="John"/><br /><sub><b>John</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Thespica" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Thespica" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/boatrainlsz"><img src="https://avatars.githubusercontent.com/u/18243785?v=4?s=100" width="100px;" alt="boatrainlsz"/><br /><sub><b>boatrainlsz</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=boatrainlsz" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.yitianyigexiangfa.com/"><img src="https://avatars.githubusercontent.com/u/3973419?v=4?s=100" width="100px;" alt="Bill Lau"/><br /><sub><b>Bill Lau</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=JavaProgrammerLB" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lw-yang"><img src="https://avatars.githubusercontent.com/u/23456873?v=4?s=100" width="100px;" alt="lwyang"/><br /><sub><b>lwyang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lw-yang" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xfl12345"><img src="https://avatars.githubusercontent.com/u/17960863?v=4?s=100" width="100px;" alt="xfl12345"/><br /><sub><b>xfl12345</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=xfl12345" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yykaue"><img src="https://avatars.githubusercontent.com/u/22905143?v=4?s=100" width="100px;" alt="Limbo"/><br /><sub><b>Limbo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yykaue" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/irenhongyan"><img src="https://avatars.githubusercontent.com/u/53438321?v=4?s=100" width="100px;" alt="哈哈哈哈哈哈哈哈哈"/><br /><sub><b>哈哈哈哈哈哈哈哈哈</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=irenhongyan" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ileonli"><img src="https://avatars.githubusercontent.com/u/45332412?v=4?s=100" width="100px;" alt="Leon Li"/><br /><sub><b>Leon Li</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ileonli" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://fnil.net/"><img src="https://avatars.githubusercontent.com/u/14142?v=4?s=100" width="100px;" alt="dennis zhuang"/><br /><sub><b>dennis zhuang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=killme2008" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kerwin612"><img src="https://avatars.githubusercontent.com/u/3371163?v=4?s=100" width="100px;" alt="Kerwin Bryant"/><br /><sub><b>Kerwin Bryant</b></sub></a><br /><a href="#design-kerwin612" title="Design">🎨</a> <a href="https://github.com/apache/hertzbeat/commits?author=kerwin612" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=kerwin612" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Akerwin612" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ShineDevelopment"><img src="https://avatars.githubusercontent.com/u/59306780?v=4?s=100" width="100px;" alt="daixianglong"/><br /><sub><b>daixianglong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ShineDevelopment" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mchgood"><img src="https://avatars.githubusercontent.com/u/38482005?v=4?s=100" width="100px;" alt="mchgood"/><br /><sub><b>mchgood</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=mchgood" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pwallk"><img src="https://avatars.githubusercontent.com/u/69385076?v=4?s=100" width="100px;" alt="kangli"/><br /><sub><b>kangli</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=pwallk" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=pwallk" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Apwallk" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cdphantom"><img src="https://avatars.githubusercontent.com/u/12674795?v=4?s=100" width="100px;" alt="cdphantom"/><br /><sub><b>cdphantom</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=cdphantom" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/asd108908382"><img src="https://avatars.githubusercontent.com/u/77717999?v=4?s=100" width="100px;" alt="jiawei.guo"/><br /><sub><b>jiawei.guo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=asd108908382" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/QBH-insist"><img src="https://avatars.githubusercontent.com/u/39401478?v=4?s=100" width="100px;" alt="QBH-insist"/><br /><sub><b>QBH-insist</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=QBH-insist" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jiangsh-ui"><img src="https://avatars.githubusercontent.com/u/86990361?v=4?s=100" width="100px;" alt="jiangsh"/><br /><sub><b>jiangsh</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jiangsh-ui" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/keaifafafa"><img src="https://avatars.githubusercontent.com/u/83876361?v=4?s=100" width="100px;" alt="Keaifa"/><br /><sub><b>Keaifa</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=keaifafafa" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Akeaifafafa" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/loong95"><img src="https://avatars.githubusercontent.com/u/16333958?v=4?s=100" width="100px;" alt="Loong"/><br /><sub><b>Loong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=loong95" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ceekay47"><img src="https://avatars.githubusercontent.com/u/104664857?v=4?s=100" width="100px;" alt="Chandrakant Vankayalapati"/><br /><sub><b>Chandrakant Vankayalapati</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ceekay47" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MRgenial"><img src="https://avatars.githubusercontent.com/u/49973336?v=4?s=100" width="100px;" alt="b_mountain"/><br /><sub><b>b_mountain</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MRgenial" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TemirlanBasitov"><img src="https://avatars.githubusercontent.com/u/57500808?v=4?s=100" width="100px;" alt="TemirlanBasitov"/><br /><sub><b>TemirlanBasitov</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=TemirlanBasitov" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wyfvsfy"><img src="https://avatars.githubusercontent.com/u/11973517?v=4?s=100" width="100px;" alt="wyfvsfy"/><br /><sub><b>wyfvsfy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wyfvsfy" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sherry-peng2333"><img src="https://avatars.githubusercontent.com/u/70619577?v=4?s=100" width="100px;" alt="sherry-peng2333"/><br /><sub><b>sherry-peng2333</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=sherry-peng2333" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lixiaobaivv"><img src="https://avatars.githubusercontent.com/u/39290771?v=4?s=100" width="100px;" alt="Yzzz"/><br /><sub><b>Yzzz</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lixiaobaivv" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.bckf.cn/"><img src="https://avatars.githubusercontent.com/u/13309008?v=4?s=100" width="100px;" alt="puruidong"/><br /><sub><b>puruidong</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=pruidong" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/shinestare"><img src="https://avatars.githubusercontent.com/u/13570619?v=4?s=100" width="100px;" alt="shinestare"/><br /><sub><b>shinestare</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=shinestare" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/po-168"><img src="https://avatars.githubusercontent.com/u/185745593?v=4?s=100" width="100px;" alt="po-168"/><br /><sub><b>po-168</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=po-168" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/All-The-Best-for"><img src="https://avatars.githubusercontent.com/u/76414672?v=4?s=100" width="100px;" alt="wbs99"/><br /><sub><b>wbs99</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=All-The-Best-for" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/starryCoder"><img src="https://avatars.githubusercontent.com/u/46510059?v=4?s=100" width="100px;" alt="starryCoder"/><br /><sub><b>starryCoder</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=starryCoder" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hasimmollah"><img src="https://avatars.githubusercontent.com/u/32538599?v=4?s=100" width="100px;" alt="hasimmollah"/><br /><sub><b>hasimmollah</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=hasimmollah" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ayu-v0"><img src="https://avatars.githubusercontent.com/u/127600988?v=4?s=100" width="100px;" alt="Ayu"/><br /><sub><b>Ayu</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ayu-v0" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Rancho-7"><img src="https://avatars.githubusercontent.com/u/59016860?v=4?s=100" width="100px;" alt="Nick Guo"/><br /><sub><b>Nick Guo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Rancho-7" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=Rancho-7" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ARancho-7" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/doveLin0818"><img src="https://avatars.githubusercontent.com/u/190927907?v=4?s=100" width="100px;" alt="doveLin"/><br /><sub><b>doveLin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=doveLin0818" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://zzrl.cc/"><img src="https://avatars.githubusercontent.com/u/91836599?v=4?s=100" width="100px;" alt="yunfan24"/><br /><sub><b>yunfan24</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Ayunfan24" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=yunfan24" title="Tests">⚠️</a> <a href="#blog-yunfan24" title="Blogposts">📝</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lctking"><img src="https://avatars.githubusercontent.com/u/168249998?v=4?s=100" width="100px;" alt="nullwli"/><br /><sub><b>nullwli</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=lctking" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://simonsigre.com/"><img src="https://avatars.githubusercontent.com/u/14932913?v=4?s=100" width="100px;" alt="Simon Sigré"/><br /><sub><b>Simon Sigré</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=simonsigre" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/commits?author=simonsigre" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.ponfee.cn/"><img src="https://avatars.githubusercontent.com/u/46117331?v=4?s=100" width="100px;" alt="ponfee"/><br /><sub><b>ponfee</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ponfee" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Vedant7789"><img src="https://avatars.githubusercontent.com/u/147625492?v=4?s=100" width="100px;" alt="Vedant7789"/><br /><sub><b>Vedant7789</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Vedant7789" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Craaaaazy77"><img src="https://avatars.githubusercontent.com/u/23025522?v=4?s=100" width="100px;" alt="Craaaaazy77"/><br /><sub><b>Craaaaazy77</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Craaaaazy77" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Suvrat1629"><img src="https://avatars.githubusercontent.com/u/140749446?v=4?s=100" width="100px;" alt="Suvrat1629"/><br /><sub><b>Suvrat1629</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Suvrat1629" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://ghyghoo8.github.io/"><img src="https://avatars.githubusercontent.com/u/363129?v=4?s=100" width="100px;" alt="ghy"/><br /><sub><b>ghy</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=ghyghoo8" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/helei1030"><img src="https://avatars.githubusercontent.com/u/11839080?v=4?s=100" width="100px;" alt="helei1030"/><br /><sub><b>helei1030</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=helei1030" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://medium.com/@pjfanning"><img src="https://avatars.githubusercontent.com/u/11783444?v=4?s=100" width="100px;" alt="PJ Fanning"/><br /><sub><b>PJ Fanning</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=pjfanning" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Apjfanning" title="Bug reports">🐛</a> <a href="https://github.com/apache/hertzbeat/commits?author=pjfanning" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MonsterChenzhuo"><img src="https://avatars.githubusercontent.com/u/60029759?v=4?s=100" width="100px;" alt="monster"/><br /><sub><b>monster</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MonsterChenzhuo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MasamiYui"><img src="https://avatars.githubusercontent.com/u/22274133?v=4?s=100" width="100px;" alt="Sherlock Yin"/><br /><sub><b>Sherlock Yin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=MasamiYui" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=MasamiYui" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3AMasamiYui" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wanhao23"><img src="https://avatars.githubusercontent.com/u/29560961?v=4?s=100" width="100px;" alt="wanhao"/><br /><sub><b>wanhao</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=wanhao23" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=wanhao23" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jonasHanhan"><img src="https://avatars.githubusercontent.com/u/130035609?v=4?s=100" width="100px;" alt="jonasHanhan"/><br /><sub><b>jonasHanhan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=jonasHanhan" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NikhilMurugesan"><img src="https://avatars.githubusercontent.com/u/49281792?v=4?s=100" width="100px;" alt="NikhilMurugesan"/><br /><sub><b>NikhilMurugesan</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=NikhilMurugesan" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/myangle1120"><img src="https://avatars.githubusercontent.com/u/19237013?v=4?s=100" width="100px;" alt="myangle1120"/><br /><sub><b>myangle1120</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=myangle1120" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yasminvo"><img src="https://avatars.githubusercontent.com/u/107528848?v=4?s=100" width="100px;" alt="yasminvo"/><br /><sub><b>yasminvo</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yasminvo" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notbugggg"><img src="https://avatars.githubusercontent.com/u/147966331?v=4?s=100" width="100px;" alt="不关银渐层的事哦"/><br /><sub><b>不关银渐层的事哦</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=notbugggg" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Anotbugggg" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yyahang"><img src="https://avatars.githubusercontent.com/u/90464876?v=4?s=100" width="100px;" alt="yyahang"/><br /><sub><b>yyahang</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=yyahang" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JuJinPark"><img src="https://avatars.githubusercontent.com/u/44892459?v=4?s=100" width="100px;" alt="jujin"/><br /><sub><b>jujin</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=JuJinPark" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=JuJinPark" title="Documentation">📖</a> <a href="#ideas-JuJinPark" title="Ideas, Planning, & Feedback">🤔</a> <a href="#blog-JuJinPark" title="Blogposts">📝</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LL-LIN"><img src="https://avatars.githubusercontent.com/u/43002118?v=4?s=100" width="100px;" alt="LL-LIN"/><br /><sub><b>LL-LIN</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=LL-LIN" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3ALL-LIN" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://bigcyy.github.io/"><img src="https://avatars.githubusercontent.com/u/73413979?v=4?s=100" width="100px;" alt="Yang Chen"/><br /><sub><b>Yang Chen</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=bigcyy" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=bigcyy" title="Documentation">📖</a> <a href="https://github.com/apache/hertzbeat/issues?q=author%3Abigcyy" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sarthakeash"><img src="https://avatars.githubusercontent.com/u/74091160?v=4?s=100" width="100px;" alt="Sarthak Arora"/><br /><sub><b>Sarthak Arora</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=sarthakeash" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=sarthakeash" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PengJingzhao"><img src="https://avatars.githubusercontent.com/u/97368949?v=4?s=100" width="100px;" alt="彭镜肇"/><br /><sub><b>彭镜肇</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=PengJingzhao" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gagaradio"><img src="https://avatars.githubusercontent.com/u/18532370?v=4?s=100" width="100px;" alt="Walter Jia"/><br /><sub><b>Walter Jia</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=gagaradio" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/boyucjz"><img src="https://avatars.githubusercontent.com/u/18730041?v=4?s=100" width="100px;" alt="boyucjz"/><br /><sub><b>boyucjz</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=boyucjz" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Cyanty"><img src="https://avatars.githubusercontent.com/u/153884653?v=4?s=100" width="100px;" alt="Cyanty"/><br /><sub><b>Cyanty</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=Cyanty" title="Code">💻</a> <a href="https://github.com/apache/hertzbeat/commits?author=Cyanty" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KevinLLF"><img src="https://avatars.githubusercontent.com/u/85452733?v=4?s=100" width="100px;" alt="Jay丿167"/><br /><sub><b>Jay丿167</b></sub></a><br /><a href="https://github.com/apache/hertzbeat/commits?author=KevinLLF" title="Code">💻</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
## 💬 コミュニティ交流
##### チャネル
[メール](https://lists.apache.org/list.html?dev@hertzbeat.apache.org) : メーリングリストに登録するために、```dev-subscribe@hertzbeat.apache.org```にメールを送ってください。
[Chat On Discord](https://discord.gg/Fb6M73htGr)
WeChatグループ : `ahertzbeat` を検索.
WeChat公式アカウント : `usthecom`を検索.
[QQグループ](https://qm.qq.com/q/xxqecSC2cw) : グループ番号 `1035688434`
[Github Discussion](https://github.com/apache/hertzbeat/discussions)
[Reddit Community](https://www.reddit.com/r/hertzbeat/)
[Follow Us Twitter](https://x.com/hertzbeat1024)
[Subscribe YouTube](https://www.youtube.com/channel/UCri75zfWX0GHqJFPENEbLow)
##### Open-Source Project Build From Open-Source
HertzBeat is built on so many great open source projects, thanks to them!
- `Java Spring SpringBoot Jpa Maven Assembly Netty Lombok Sureness Protobuf HttpClient Guava SnakeYaml JsonPath ...`
- `TypeScript Angular NG-ZORRO NG-ALAIN NodeJs Npm Html Less Echarts Rxjs ZoneJs MonacoEditor SlickCarousel Docusaurus ...`
## Landscape
<p align="left">
<img src="./home/static/img/home/cncf-landscape-left-logo.svg" width="300">&nbsp;&nbsp;<img src="./home/static/img/home/cncf-right-logo.svg" width="345" />
<br /><br />
HertzBeat has been included in the <a href="https://landscape.cncf.io/guide?item=observability-and-analysis--monitoring--hertzbeat#observability-and-analysis--monitoring">
CNCF Observability And Analysis - Monitoring Landscape.</a>
</p>
## 🛡️ License
[`Apache License, Version 2.0`](https://www.apache.org/licenses/LICENSE-2.0.html)
+5
View File
@@ -29,6 +29,11 @@
"type": 0,
"paramValue": 1000
},
{
"field": "ssl",
"type": 1,
"paramValue": false
},
{
"field": "username",
"type": 1
+5
View File
@@ -73,6 +73,11 @@
"field": "successCode",
"type": 4,
"paramValue": "200, 201"
},
{
"field": "enableUrlEncoding",
"type": 1,
"paramValue": true
}
]
}
+39
View File
@@ -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.
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkakNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTkRVeU5ESTROamd3SGhjTk1qVXdOREl4TVRNME1UQTRXaGNOTXpVd05ERTVNVE0wTVRBNApXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTkRVeU5ESTROamd3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFUR2U2SW5hQko4RGRiQVdmZTRNM09yS3ZTR1IvWkROS0JJV2lMejZXckcKYmh4Mm5ncHJFQjhRYThEWDZocGRCVkI1RmN3L1hwTXZjRnNCeFh3MThPNkdvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWRXOEFySENLNVQ2OFdJeG1BUnlTCkJFcHJ6N1F3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnYlhwYXV0c2RlTlJHNm4zRmhBRkkzbncvWUErYTBBdi8KUE9HZzNhYWRCSDBDSUU5NW4vQW5yOXV2Z0tyczVrakpGKzAwci96SWpFdnQxNmhkOGdabFEzb1IKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
server: https://172.29.0.11:6443
name: default
contexts:
- context:
cluster: default
user: default
name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrVENDQVRlZ0F3SUJBZ0lJZm5OdzUyby9ybDB3Q2dZSUtvWkl6ajBFQXdJd0l6RWhNQjhHQTFVRUF3d1kKYXpOekxXTnNhV1Z1ZEMxallVQXhOelExTWpReU9EWTRNQjRYRFRJMU1EUXlNVEV6TkRFd09Gb1hEVEkyTURReQpNVEV6TkRFd09Gb3dNREVYTUJVR0ExVUVDaE1PYzNsemRHVnRPbTFoYzNSbGNuTXhGVEFUQmdOVkJBTVRESE41CmMzUmxiVHBoWkcxcGJqQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJHa3UxWDQvRGNMU1h4cXcKSzczdGhMUFd5Y3JCendrL3ZMbzkzMTZ0dXNXRWE4WnNMdytnYk5wWEVOSFNxQk8zdGcrYUFSdGhWakF3OU5GaApZWXNtaTQyalNEQkdNQTRHQTFVZER3RUIvd1FFQXdJRm9EQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBakFmCkJnTlZIU01FR0RBV2dCU1B5dEJrYlFaRmtxSEpOaHlHNjZ1K3ZqbjNhakFLQmdncWhrak9QUVFEQWdOSUFEQkYKQWlFQXZQVC9ENGs2S29tUUxaZjRNMTEvd1psT3QyZkpGTGhIY3EyOHMvUUVLcndDSUZVMWVzTGFFTnRWc2xUeAo0QTFtNkt4eEpUbmdNM0M3UXJ5OUs0Z2hzVDA0Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdFkyeHAKWlc1MExXTmhRREUzTkRVeU5ESTROamd3SGhjTk1qVXdOREl4TVRNME1UQTRXaGNOTXpVd05ERTVNVE0wTVRBNApXakFqTVNFd0h3WURWUVFEREJock0zTXRZMnhwWlc1MExXTmhRREUzTkRVeU5ESTROamd3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFSeENGL2FuNVUvS0xEUk9VUlZxdllWTHFsdWxXaE8rMzJpc1lRU1hlYUgKdnRBWHo3dFE2MkhrazNIdXZudnFmditvQlBKVUlzS3ExTyt6aytLT3JWa2dvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVWo4clFaRzBHUlpLaHlUWWNodXVyCnZyNDU5Mm93Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnWmxiRkpoZWwzQiszQ2FyZjUrdE5taDhkWkRUOC9yVDAKR01VVXlBNzlWSUVDSVFDSUQ1NkVQbmtOa0xmZExEZXloclBGWks3VWRTc2x2QWZGN2N4czF1MDBxZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
client-key-data: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUpMOGJrS1FMbEdZWUE0Ny9Lek9CRm5iZnI0NGQ5VndUWXlPT0dJdnNLOXNvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFYVM3VmZqOE53dEpmR3JBcnZlMkVzOWJKeXNIUENUKzh1ajNmWHEyNnhZUnJ4bXd2RDZCcwoybGNRMGRLb0U3ZTJENW9CRzJGV01ERDAwV0ZoaXlhTGpRPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
+1
View File
@@ -0,0 +1 @@
K10800b7e6b1f6390067e433bd30dff5f925893b60074f8c36f7725bfdce6a45917::server:ca7449eb0dddd8a4bb6e5ca86e2d0cdd
+37
View File
@@ -0,0 +1,37 @@
{
"detected": true,
"monitor": {
"intervals": 10,
"tags": [],
"app": "kubernetes",
"host": "172.29.0.11",
"name": "Brave_Stingray_55yR"
},
"collector": "",
"params": [
{
"display": true,
"field": "host",
"type": 1,
"paramValue": "172.29.0.11"
},
{
"display": true,
"field": "port",
"type": 0,
"paramValue": 6443
},
{
"display": true,
"field": "authType",
"type": 1,
"paramValue": "Bearer Token"
},
{
"display": true,
"field": "token",
"type": 1,
"paramValue": "#TOKEN#"
}
]
}
+69
View File
@@ -0,0 +1,69 @@
#!api-testing
# 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.
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-schema.json
name: hertzbeat
api: |
{{default "http://localhost:1157" (env "SERVER")}}
param:
monitorHTTP: "{{randAlpha 6}}"
monitorSiteMap: "{{randAlpha 6}}"
monitorPort: "{{randAlpha 6}}"
monitorSSL: "{{randAlpha 6}}"
monitorPing: "{{randAlpha 6}}"
monitorUDP: "{{randAlpha 6}}"
monitorWebsite: "{{randAlpha 6}}"
monitorFTP: "{{randAlpha 6}}"
tagName: "{{randAlpha 3}}"
items:
- name: login
request:
api: /api/account/auth/form
method: POST
header:
Content-type: application/json
body: |
{
"type": 0,
"identifier": "admin",
"credential": "hertzbeat"
}
expect:
bodyFieldsExpect:
code: "0"
- name: detectMonitor
request:
api: /api/monitor/detect
method: POST
header:
Authorization: Bearer {{.login.data.token}}
Content-type: application/json
bodyFromFile: data/tmp.json
expect:
statusCode: 200
- name: createMonitor
request:
api: /api/monitor
method: POST
header:
Authorization: Bearer {{.login.data.token}}
Content-type: application/json
bodyFromFile: data/tmp.json
expect:
statusCode: 200
+123
View File
@@ -0,0 +1,123 @@
# 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.
version: '3.8'
services:
init:
image: bitnami/kubectl:latest
privileged: true
depends_on:
k3s:
condition: service_healthy
entrypoint: /bin/bash
networks:
k3s_network:
ipv4_address: 172.29.0.10
volumes:
- ./data/config/k3s.yaml:/.kube/config
- ./data:/testcase
command:
- -c
- |
# Wait for k3s to start
until kubectl cluster-info; do sleep 1; done
sleep 5
# Create serviceaccount and clusterrolebinding
kubectl create serviceaccount -n kube-system cluster-admin-sa
kubectl create clusterrolebinding -n kube-system cluster-admin-binding --clusterrole=cluster-admin --serviceaccount=kube-system:cluster-admin-sa
cd /testcase
kubectl create token cluster-admin-sa -n kube-system --duration=24h
echo $(sed "s/#TOKEN#/$(echo $(kubectl create token cluster-admin-sa -n kube-system --duration=24h))/g" create_k8s_monitor_data.json)>tmp.json
# install metrics server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
sleep 30
tail -f /dev/null
k3s:
image: rancher/k3s:v1.31.0-k3s1
container_name: k3s
privileged: true
ports:
- "6443:6443"
- "80:80"
command: server --bind-address 172.29.0.11
networks:
k3s_network:
ipv4_address: 172.29.0.11
healthcheck:
test: [ "CMD-SHELL",
"kubectl cluster-info && echo $(cat /var/lib/rancher/k3s/server/node-token)>node-token.txt" ]
interval: 3s
retries: 30
start_period: 10s
timeout: 10s
volumes:
- ./data/config/k3s.yaml:/etc/rancher/k3s/k3s.yaml
- ./data/config/node-token.txt:/node-token.txt
testing:
image: ghcr.io/linuxsuren/api-testing:v0.0.17
environment:
SERVER: http://hertzbeat:1157
container_name: e2e-testing
volumes:
- ./data/:/work/data/
- ./data/testsuite.yaml:/work/testsuite.yaml
command: atest run -p /work/testsuite.yaml --level debug --thread 3
networks:
k3s_network:
ipv4_address: 172.29.0.12
depends_on:
checker:
condition: service_healthy
k3s:
condition: service_healthy
links:
- hertzbeat
- checker
- k3s
checker:
image: alpine:latest
container_name: e2e-checker
command: sh -c "apk add --update curl && tail -f /dev/null"
healthcheck:
test: [ "CMD-SHELL",
"curl -s -X POST -H \"Content-Type: application/json\" -d '{\"type\": 0,\"identifier\": \"admin\",\"credential\": \"hertzbeat\"}' http://hertzbeat:1157/api/account/auth/form | grep -q token"
]
interval: 3s
timeout: 60s
retries: 10
start_period: 10s
networks:
k3s_network:
ipv4_address: 172.29.0.13
depends_on:
- init
hertzbeat:
image: apache/hertzbeat:test
container_name: e2e-hertzbeat
volumes:
- ./logs/:/opt/hertzbeat/logs/
ports:
- "1157:1157"
networks:
k3s_network:
ipv4_address: 172.29.0.14
networks:
k3s_network:
driver: bridge
ipam:
config:
- subnet: 172.29.0.0/16
+19 -23
View File
@@ -29,7 +29,7 @@ param:
monitorUDP: "{{randAlpha 6}}"
monitorWebsite: "{{randAlpha 6}}"
monitorFTP: "{{randAlpha 6}}"
tagName: "{{randAlpha 3}}"
labelName: "{{randAlpha 3}}"
items:
- name: login
request:
@@ -302,13 +302,13 @@ items:
Authorization: Bearer {{.login.data.token}}
- name: deleteAlertDefine
request:
api: /api/alert/defines?ids={{(index .listAlertDefines.data.content 0).id | int64}}
api: /api/alert/defines?ids=1
method: DELETE
header:
Authorization: Bearer {{.login.data.token}}
- name: listAlertConverges
- name: listAlertGroupConverges
request:
api: /api/alert/converges
api: /api/alert/groups
header:
Authorization: Bearer {{.login.data.token}}
- name: listAlertSilences
@@ -316,9 +316,9 @@ items:
api: /api/alert/silences
header:
Authorization: Bearer {{.login.data.token}}
- name: listAlerts
- name: listGroupAlerts
request:
api: /api/alerts
api: /api/alerts/group
header:
Authorization: Bearer {{.login.data.token}}
- name: listReceivers
@@ -342,39 +342,35 @@ items:
header:
Authorization: Bearer {{.login.data.token}}
## Tag
- name: createTag
## Label
- name: createLabel
request:
api: /api/tag
api: /api/label
method: POST
header:
Authorization: Bearer {{.login.data.token}}
Content-type: application/json
body: |
[
{
"color": "#ff4081",
"name": "{{.param.tagName}}"
}
]
- name: listTags
{
"name": "{{.param.labelName}}"
}
- name: listLabels
request:
api: /api/tag?pageIndex=0&pageSize=8&type=1
api: /api/label?pageIndex=0&pageSize=8&type=1
header:
Authorization: Bearer {{.login.data.token}}
- name: updateTag
- name: updateLabel
request:
api: /api/tag
api: /api/label
method: PUT
header:
Authorization: Bearer {{.login.data.token}}
Content-type: application/json
body: |
{
"id": {{(index .listTags.data.content 0).id | int64}},
"id": {{(index .listLabels.data.content 0).id | int64}},
"name": "{{randAlpha 3}}",
"tagValue": "{{randAlpha 3}}",
"color": "#ff4081",
"type": 1,
"creator": "admin",
"modifier": "admin"
@@ -382,9 +378,9 @@ items:
expect:
bodyFieldsExpect:
code: "0"
- name: deleteTag
- name: deleteLabel
request:
api: /api/tag?ids={{(index .listTags.data.content 0).id | int64}}
api: /api/label?ids={{(index .listLabels.data.content 0).id | int64}}
method: DELETE
header:
Authorization: Bearer {{.login.data.token}}
+37 -1
View File
@@ -32,9 +32,19 @@
<!-- common -->
<dependency>
<groupId>org.apache.hertzbeat</groupId>
<artifactId>hertzbeat-common</artifactId>
<artifactId>hertzbeat-base</artifactId>
<scope>provided</scope>
</dependency>
<!-- plugin -->
<dependency>
<groupId>org.apache.hertzbeat</groupId>
<artifactId>hertzbeat-plugin</artifactId>
</dependency>
<!-- warehouse -->
<dependency>
<groupId>org.apache.hertzbeat</groupId>
<artifactId>hertzbeat-warehouse</artifactId>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -50,6 +60,21 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- email -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>${nekohtml.version}</version>
</dependency>
<!-- kafka -->
<dependency>
<groupId>org.apache.kafka</groupId>
@@ -73,6 +98,17 @@
<version>${easy-poi.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.huaweicloud.sdk</groupId>
<artifactId>huaweicloud-sdk-smn</artifactId>
<version>${huawei.sdk.version}</version>
<exclusions>
<exclusion>
<groupId>org.openeuler</groupId>
<artifactId>bgmprovider</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.arrow</groupId>
<artifactId>arrow-vector</artifactId>
@@ -79,6 +79,11 @@ public class AlerterProperties {
*/
private EntranceProperties entrance;
/**
* Inhibit configuration properties
*/
private InhibitProperties inhibit;
/**
* Data entry configuration properties
*/
@@ -105,4 +110,17 @@ public class AlerterProperties {
}
}
/**
* Inhibit configuration properties
*/
@Getter
@Setter
public static class InhibitProperties {
/**
* inhibit rule cache ttl, default 4h
*/
private long ttl = 4 * 60 * 60 * 1000L;
}
}
@@ -44,7 +44,7 @@ public class AlerterWorkerPool {
private void initWorkExecutor() {
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setUncaughtExceptionHandler((thread, throwable) -> {
log.error("workerExecutor has uncaughtException.");
log.error("Alerter workerExecutor has uncaughtException.");
log.error(throwable.getMessage(), throwable);
})
.setDaemon(true)
@@ -62,7 +62,7 @@ public class AlerterWorkerPool {
private void initNotifyExecutor() {
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setUncaughtExceptionHandler((thread, throwable) -> {
log.error("notifyExecutor has uncaughtException.");
log.error("Alerter notifyExecutor has uncaughtException.");
log.error(throwable.getMessage(), throwable);
})
.setDaemon(true)
@@ -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.hertzbeat.alert.calculate;
import org.apache.hertzbeat.alert.dao.SingleAlertDao;
import org.apache.hertzbeat.alert.util.AlertUtil;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* alert cache manager
*/
@Component
public class AlarmCacheManager {
/**
* The alarm in the process is triggered
* key - labels fingerprint
*/
private final Map<String, SingleAlert> pendingAlertMap;
/**
* The not recover alert
* key - labels fingerprint
*/
private final Map<String, SingleAlert> firingAlertMap;
public AlarmCacheManager(SingleAlertDao singleAlertDao) {
this.pendingAlertMap = new ConcurrentHashMap<>(8);
this.firingAlertMap = new ConcurrentHashMap<>(8);
List<SingleAlert> singleAlerts = singleAlertDao.querySingleAlertsByStatus(CommonConstants.ALERT_STATUS_FIRING);
for (SingleAlert singleAlert : singleAlerts) {
String fingerprint = AlertUtil.calculateFingerprint(singleAlert.getLabels());
singleAlert.setId(null);
this.firingAlertMap.put(fingerprint, singleAlert);
}
}
public void putPending(String fingerPrint, SingleAlert alert) {
this.pendingAlertMap.put(fingerPrint, alert);
}
public SingleAlert getPending(String fingerPrint) {
return this.pendingAlertMap.get(fingerPrint);
}
public SingleAlert removePending(String fingerPrint) {
return this.pendingAlertMap.remove(fingerPrint);
}
public void putFiring(String fingerPrint, SingleAlert alert) {
this.firingAlertMap.put(fingerPrint, alert);
}
public SingleAlert getFiring(String fingerPrint) {
return this.firingAlertMap.get(fingerPrint);
}
public SingleAlert removeFiring(String fingerPrint) {
return this.firingAlertMap.remove(fingerPrint);
}
}
@@ -1,492 +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.hertzbeat.alert.calculate;
import static org.apache.hertzbeat.common.constants.CommonConstants.ALERT_STATUS_CODE_NOT_REACH;
import static org.apache.hertzbeat.common.constants.CommonConstants.ALERT_STATUS_CODE_PENDING;
import static org.apache.hertzbeat.common.constants.CommonConstants.ALERT_STATUS_CODE_SOLVED;
import static org.apache.hertzbeat.common.constants.CommonConstants.TAG_CODE;
import static org.apache.hertzbeat.common.constants.CommonConstants.TAG_METRIC;
import static org.apache.hertzbeat.common.constants.CommonConstants.TAG_METRICS;
import static org.apache.hertzbeat.common.constants.CommonConstants.TAG_MONITOR_APP;
import static org.apache.hertzbeat.common.constants.CommonConstants.TAG_MONITOR_ID;
import static org.apache.hertzbeat.common.constants.CommonConstants.TAG_MONITOR_NAME;
import com.google.common.collect.Maps;
import jakarta.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.jexl3.JexlException;
import org.apache.commons.jexl3.JexlExpression;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.alert.AlerterWorkerPool;
import org.apache.hertzbeat.alert.dao.AlertMonitorDao;
import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce;
import org.apache.hertzbeat.alert.service.AlertDefineService;
import org.apache.hertzbeat.alert.service.AlertService;
import org.apache.hertzbeat.alert.util.AlertTemplateUtil;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.constants.MetricDataConstants;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.apache.hertzbeat.common.entity.arrow.RowWrapper;
import org.apache.hertzbeat.common.entity.manager.Monitor;
import org.apache.hertzbeat.common.entity.manager.TagItem;
import org.apache.hertzbeat.common.entity.message.CollectRep;
import org.apache.hertzbeat.common.queue.CommonDataQueue;
import org.apache.hertzbeat.common.support.event.MonitorDeletedEvent;
import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
import org.apache.hertzbeat.common.util.CommonUtil;
import org.apache.hertzbeat.common.util.JexlExpressionRunner;
import org.apache.hertzbeat.common.util.ResourceBundleUtil;
import org.springframework.context.event.EventListener;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* Calculate alarms based on the alarm definition rules and collected data
*/
@Component
@Slf4j
public class CalculateAlarm {
private static final String SYSTEM_VALUE_ROW_COUNT = "system_value_row_count";
private static final int CALCULATE_THREADS = 3;
/**
* The alarm in the process is triggered
* key - monitorId+alertDefineId+tags The alarm is a common threshold alarm
* key - monitorId Indicates the monitoring status availability reachability alarm
*/
private final Map<String, Alert> triggeredAlertMap;
/**
* The not recover alert
* key - monitorId + alertDefineId + tags
*/
private final Map<String, Alert> notRecoveredAlertMap;
private final AlerterWorkerPool workerPool;
private final CommonDataQueue dataQueue;
private final AlertDefineService alertDefineService;
private final AlarmCommonReduce alarmCommonReduce;
private ResourceBundle bundle;
private final AlertService alertService;
public CalculateAlarm(AlerterWorkerPool workerPool, CommonDataQueue dataQueue,
AlertDefineService alertDefineService, AlertMonitorDao monitorDao,
AlarmCommonReduce alarmCommonReduce, AlertService alertService) {
this.workerPool = workerPool;
this.dataQueue = dataQueue;
this.alarmCommonReduce = alarmCommonReduce;
this.alertDefineService = alertDefineService;
this.alertService = alertService;
this.bundle = ResourceBundleUtil.getBundle("alerter");
this.triggeredAlertMap = new ConcurrentHashMap<>(16);
this.notRecoveredAlertMap = new ConcurrentHashMap<>(16);
// Initialize stateAlertMap
List<Monitor> monitors = monitorDao.findMonitorsByStatus(CommonConstants.MONITOR_DOWN_CODE);
if (monitors != null) {
for (Monitor monitor : monitors) {
HashMap<String, String> tags = new HashMap<>(8);
tags.put(TAG_MONITOR_ID, String.valueOf(monitor.getId()));
tags.put(TAG_MONITOR_NAME, monitor.getName());
tags.put(TAG_MONITOR_APP, monitor.getApp());
this.notRecoveredAlertMap.put(monitor.getId() + CommonConstants.AVAILABILITY,
Alert.builder().tags(tags).target(CommonConstants.AVAILABILITY).status(ALERT_STATUS_CODE_PENDING).build());
}
}
startCalculate();
}
private void startCalculate() {
Runnable runnable = () -> {
while (!Thread.currentThread().isInterrupted()) {
try {
CollectRep.MetricsData metricsData = dataQueue.pollMetricsDataToAlerter();
if (metricsData != null) {
calculate(metricsData);
}
dataQueue.sendMetricsDataToStorage(metricsData);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error("calculate alarm error: {}.", e.getMessage(), e);
}
}
};
for (int i = 0; i < CALCULATE_THREADS; i++) {
workerPool.executeJob(runnable);
}
}
private void calculate(CollectRep.MetricsData metricsData) {
long currentTimeMilli = System.currentTimeMillis();
long monitorId = metricsData.getId();
String app = metricsData.getApp();
if (app.startsWith(CommonConstants.PROMETHEUS_APP_PREFIX)) {
app = CommonConstants.PROMETHEUS;
}
String metrics = metricsData.getMetrics();
// If the metrics whose scheduling priority is 0 has the status of collecting response data UN_REACHABLE/UN_CONNECTABLE,
// the highest severity alarm is generated to monitor the status change
if (metricsData.getPriority() == 0) {
handlerAvailableMetrics(monitorId, app, metricsData);
}
// Query the alarm definitions associated with the metrics of the monitoring type
// field - define[]
Map<String, List<AlertDefine>> defineMap = alertDefineService.getMonitorBindAlertDefines(monitorId, app, metrics);
if (defineMap.isEmpty()) {
return;
}
Map<String, Object> fieldValueMap = Maps.newHashMapWithExpectedSize(8);
try {
for (Map.Entry<String, List<AlertDefine>> entry : defineMap.entrySet()) {
List<AlertDefine> defines = entry.getValue();
for (AlertDefine define : defines) {
final String expr = define.getExpr();
if (StringUtils.isBlank(expr)) {
continue;
}
if (expr.contains(SYSTEM_VALUE_ROW_COUNT) && metricsData.getValues().size() == 0L) {
fieldValueMap.put(SYSTEM_VALUE_ROW_COUNT, 0);
try {
boolean match = execAlertExpression(fieldValueMap, expr);
try {
if (match) {
// If the threshold rule matches, the number of times the threshold has been triggered is determined and an alarm is triggered
afterThresholdRuleMatch(currentTimeMilli, monitorId, app, metrics, "", fieldValueMap, define);
// if the threshold is triggered, ignore other data rows
continue;
} else {
String alarmKey = String.valueOf(monitorId) + define.getId();
triggeredAlertMap.remove(alarmKey);
if (define.isRecoverNotice()) {
handleRecoveredAlert(currentTimeMilli, define, expr, alarmKey);
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
} catch (Exception ignored) {}
}
RowWrapper rowWrapper = metricsData.readRow();
while (rowWrapper.hasNextRow()) {
rowWrapper = rowWrapper.nextRow();
StringBuilder tagBuilder = new StringBuilder();
fieldValueMap.clear();
fieldValueMap.put(SYSTEM_VALUE_ROW_COUNT, metricsData.getValues().size());
rowWrapper.cellStream().forEach(cell -> {
String valueStr = cell.getValue();
if (CommonConstants.NULL_VALUE.equals(valueStr)) {
return;
}
final String fieldName = cell.getField().getName();
final int fieldType = cell.getMetadataAsInteger(MetricDataConstants.TYPE);
if (fieldType == CommonConstants.TYPE_NUMBER) {
final Double doubleValue;
if ((doubleValue = CommonUtil.parseStrDouble(valueStr)) != null) {
fieldValueMap.put(fieldName, doubleValue);
}
} else if (fieldType == CommonConstants.TYPE_TIME) {
final Integer integerValue;
if ((integerValue = CommonUtil.parseStrInteger(valueStr)) != null) {
fieldValueMap.put(fieldName, integerValue);
}
} else {
if (StringUtils.isNotEmpty(valueStr)) {
fieldValueMap.put(fieldName, valueStr);
}
}
if (cell.getMetadataAsBoolean(MetricDataConstants.LABEL)) {
tagBuilder.append("-").append(valueStr);
}
});
try {
boolean match = execAlertExpression(fieldValueMap, expr);
try {
if (match) {
// If the threshold rule matches, the number of times the threshold has been triggered is determined and an alarm is triggered
afterThresholdRuleMatch(currentTimeMilli, monitorId, app, metrics, tagBuilder.toString(), fieldValueMap, define);
} else {
String alarmKey = String.valueOf(monitorId) + define.getId() + tagBuilder;
triggeredAlertMap.remove(alarmKey);
if (define.isRecoverNotice()) {
handleRecoveredAlert(currentTimeMilli, define, expr, alarmKey);
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
} catch (Exception ignored) {}
}
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
private void handleRecoveredAlert(long currentTimeMilli, AlertDefine define, String expr, String alarmKey) {
Alert notResolvedAlert = notRecoveredAlertMap.remove(alarmKey);
if (notResolvedAlert != null) {
// Sending an alarm Restore
Map<String, String> tags = notResolvedAlert.getTags();
String content = this.bundle.getString("alerter.alarm.recover") + " : " + expr;
Alert resumeAlert = Alert.builder()
.tags(tags)
.target(define.getApp() + "." + define.getMetric() + "." + define.getField())
.content(content)
.priority(CommonConstants.ALERT_PRIORITY_CODE_WARNING)
.status(CommonConstants.ALERT_STATUS_CODE_RESTORED)
.firstAlarmTime(currentTimeMilli)
.lastAlarmTime(notResolvedAlert.getLastAlarmTime())
.triggerTimes(1)
.build();
alarmCommonReduce.reduceAndSendAlarm(resumeAlert);
}
}
private void afterThresholdRuleMatch(long currentTimeMilli, long monitorId, String app, String metrics, String tagStr,
Map<String, Object> fieldValueMap, AlertDefine define) {
String alarmKey = String.valueOf(monitorId) + define.getId() + tagStr;
Alert triggeredAlert = triggeredAlertMap.get(alarmKey);
if (triggeredAlert != null) {
int times = triggeredAlert.getTriggerTimes() + 1;
triggeredAlert.setTriggerTimes(times);
triggeredAlert.setFirstAlarmTime(currentTimeMilli);
triggeredAlert.setLastAlarmTime(currentTimeMilli);
int defineTimes = define.getTimes() == null ? 1 : define.getTimes();
if (times >= defineTimes) {
triggeredAlert.setStatus(ALERT_STATUS_CODE_PENDING);
triggeredAlertMap.remove(alarmKey);
notRecoveredAlertMap.put(alarmKey, triggeredAlert);
alarmCommonReduce.reduceAndSendAlarm(triggeredAlert.clone());
}
} else {
fieldValueMap.put(TAG_MONITOR_APP, app);
fieldValueMap.put(TAG_METRICS, metrics);
fieldValueMap.put(TAG_METRIC, define.getField());
Map<String, String> tags = new HashMap<>(8);
tags.put(TAG_MONITOR_ID, String.valueOf(monitorId));
tags.put(TAG_MONITOR_APP, app);
tags.put(CommonConstants.TAG_THRESHOLD_ID, String.valueOf(define.getId()));
if (!CollectionUtils.isEmpty(define.getTags())) {
for (TagItem tagItem : define.getTags()) {
fieldValueMap.put(tagItem.getName(), tagItem.getValue());
tags.put(tagItem.getName(), tagItem.getValue());
}
}
Alert alert = Alert.builder()
.tags(tags)
.priority(define.getPriority())
.status(ALERT_STATUS_CODE_NOT_REACH)
.target(app + "." + metrics + "." + define.getField())
.triggerTimes(1)
.firstAlarmTime(currentTimeMilli)
.lastAlarmTime(currentTimeMilli)
// Keyword matching and substitution in the template
.content(AlertTemplateUtil.render(define.getTemplate(), fieldValueMap))
.build();
int defineTimes = define.getTimes() == null ? 1 : define.getTimes();
if (1 >= defineTimes) {
alert.setStatus(ALERT_STATUS_CODE_PENDING);
notRecoveredAlertMap.put(alarmKey, alert);
alarmCommonReduce.reduceAndSendAlarm(alert.clone());
} else {
triggeredAlertMap.put(alarmKey, alert);
}
}
}
private boolean execAlertExpression(Map<String, Object> fieldValueMap, String expr) {
Boolean match;
JexlExpression expression;
try {
expression = JexlExpressionRunner.compile(expr);
} catch (JexlException jexlException) {
log.error("Alarm Rule: {} Compile Error: {}.", expr, jexlException.getMessage());
throw jexlException;
} catch (Exception e) {
log.error("Alarm Rule: {} Unknown Error: {}.", expr, e.getMessage());
throw e;
}
try {
match = (Boolean) JexlExpressionRunner.evaluate(expression, fieldValueMap);
} catch (JexlException jexlException) {
log.error("Alarm Rule: {} Run Error: {}.", expr, jexlException.getMessage());
throw jexlException;
} catch (Exception e) {
log.error("Alarm Rule: {} Unknown Error: {}.", expr, e.getMessage());
throw e;
}
return match != null && match;
}
private void handlerAvailableMetrics(long monitorId, String app, CollectRep.MetricsData metricsData) {
if (metricsData.getCode() == CollectRep.Code.TIMEOUT) {
return;
}
// TODO CACHE getMonitorBindAlertAvaDefine
AlertDefine avaAlertDefine = alertDefineService.getMonitorBindAlertAvaDefine(monitorId, app, CommonConstants.AVAILABILITY);
if (avaAlertDefine == null) {
return;
}
long currentTimeMill = System.currentTimeMillis();
if (metricsData.getCode() != CollectRep.Code.SUCCESS) {
Alert preAlert = triggeredAlertMap.get(String.valueOf(monitorId));
Map<String, String> tags = new HashMap<>(6);
tags.put(TAG_MONITOR_ID, String.valueOf(monitorId));
tags.put(TAG_MONITOR_APP, app);
tags.put(CommonConstants.TAG_THRESHOLD_ID, String.valueOf(avaAlertDefine.getId()));
tags.put(TAG_METRICS, CommonConstants.AVAILABILITY);
tags.put(TAG_CODE, metricsData.getCode().name());
Map<String, Object> valueMap = tags.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
if (!CollectionUtils.isEmpty(avaAlertDefine.getTags())) {
for (TagItem tagItem : avaAlertDefine.getTags()) {
valueMap.put(tagItem.getName(), tagItem.getValue());
tags.put(tagItem.getName(), tagItem.getValue());
}
}
if (preAlert == null) {
Alert.AlertBuilder alertBuilder = Alert.builder()
.tags(tags)
.priority(avaAlertDefine.getPriority())
.status(ALERT_STATUS_CODE_NOT_REACH)
.target(CommonConstants.AVAILABILITY)
.content(AlertTemplateUtil.render(avaAlertDefine.getTemplate(), valueMap))
.firstAlarmTime(currentTimeMill)
.lastAlarmTime(currentTimeMill)
.triggerTimes(1);
if (avaAlertDefine.getTimes() == null || avaAlertDefine.getTimes() <= 1) {
String notResolvedAlertKey = monitorId + CommonConstants.AVAILABILITY;
alertBuilder.status(ALERT_STATUS_CODE_PENDING);
notRecoveredAlertMap.put(notResolvedAlertKey, alertBuilder.build());
alarmCommonReduce.reduceAndSendAlarm(alertBuilder.build());
} else {
triggeredAlertMap.put(String.valueOf(monitorId), alertBuilder.build());
}
} else {
int times = preAlert.getTriggerTimes() + 1;
preAlert.setTriggerTimes(times);
preAlert.setFirstAlarmTime(currentTimeMill);
preAlert.setLastAlarmTime(currentTimeMill);
int defineTimes = avaAlertDefine.getTimes() == null ? 1 : avaAlertDefine.getTimes();
if (times >= defineTimes) {
preAlert.setStatus(ALERT_STATUS_CODE_PENDING);
String notResolvedAlertKey = monitorId + CommonConstants.AVAILABILITY;
notRecoveredAlertMap.put(notResolvedAlertKey, preAlert.clone());
alarmCommonReduce.reduceAndSendAlarm(preAlert.clone());
triggeredAlertMap.remove(String.valueOf(monitorId));
}
}
} else {
// Check whether an availability or unreachable alarm is generated before the association monitoring
// and send a clear alarm to clear the monitoring status
triggeredAlertMap.remove(String.valueOf(monitorId));
String notResolvedAlertKey = monitorId + CommonConstants.AVAILABILITY;
Alert notResolvedAlert = notRecoveredAlertMap.remove(notResolvedAlertKey);
if (notResolvedAlert != null) {
// Sending an alarm Restore
Map<String, String> tags = notResolvedAlert.getTags();
if (!avaAlertDefine.isRecoverNotice()) {
tags.put(CommonConstants.IGNORE, CommonConstants.IGNORE);
}
String content = this.bundle.getString("alerter.availability.recover");
Alert resumeAlert = Alert.builder()
.tags(tags)
.target(CommonConstants.AVAILABILITY)
.content(content)
.priority(CommonConstants.ALERT_PRIORITY_CODE_WARNING)
.status(CommonConstants.ALERT_STATUS_CODE_RESTORED)
.firstAlarmTime(currentTimeMill)
.lastAlarmTime(notResolvedAlert.getLastAlarmTime())
.triggerTimes(1)
.build();
alarmCommonReduce.reduceAndSendAlarm(resumeAlert);
Runnable updateStatusJob = () -> {
// todo update pre all type alarm status
updateAvailabilityAlertStatus(monitorId, resumeAlert);
};
workerPool.executeJob(updateStatusJob);
}
}
}
private void updateAvailabilityAlertStatus(long monitorId, Alert restoreAlert) {
List<Alert> availabilityAlerts = queryAvailabilityAlerts(monitorId, restoreAlert);
availabilityAlerts.stream().parallel().forEach(alert -> {
log.info("updating alert status solved id: {}", alert.getId());
alertService.editAlertStatus(ALERT_STATUS_CODE_SOLVED, List.of(alert.getId()));
});
}
private List<Alert> queryAvailabilityAlerts(long monitorId, Alert restoreAlert) {
//create query condition
Specification<Alert> specification = (root, query, criteriaBuilder) -> {
List<Predicate> andList = new ArrayList<>();
Predicate predicateTags = criteriaBuilder.like(root.get("tags").as(String.class), "%" + monitorId + "%");
andList.add(predicateTags);
Predicate predicatePriority = criteriaBuilder.equal(root.get("priority"), CommonConstants.ALERT_PRIORITY_CODE_EMERGENCY);
andList.add(predicatePriority);
Predicate predicateStatus = criteriaBuilder.equal(root.get("status"), ALERT_STATUS_CODE_PENDING);
andList.add(predicateStatus);
Predicate predicateAlertTime = criteriaBuilder.lessThanOrEqualTo(root.get("lastAlarmTime"), restoreAlert.getLastAlarmTime());
andList.add(predicateAlertTime);
Predicate[] predicates = new Predicate[andList.size()];
return criteriaBuilder.and(andList.toArray(predicates));
};
//query results
return alertService.getAlerts(specification);
}
@EventListener(SystemConfigChangeEvent.class)
public void onSystemConfigChangeEvent(SystemConfigChangeEvent event) {
log.info("calculate alarm receive system config change event: {}.", event.getSource());
this.bundle = ResourceBundleUtil.getBundle("alerter");
}
@EventListener(MonitorDeletedEvent.class)
public void onMonitorDeletedEvent(MonitorDeletedEvent event) {
log.info("calculate alarm receive monitor {} has been deleted.", event.getMonitorId());
this.triggeredAlertMap.remove(String.valueOf(event.getMonitorId()));
}
}
@@ -0,0 +1,129 @@
/*
* 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.hertzbeat.alert.calculate;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.dao.AlertCollectorDao;
import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce;
import org.apache.hertzbeat.alert.util.AlertUtil;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
import org.apache.hertzbeat.common.entity.manager.Collector;
import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
import org.apache.hertzbeat.common.util.ResourceBundleUtil;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
/**
* handle collector alarm
*/
@Component
@Slf4j
public class CollectorAlertHandler {
private static final String KEY_COLLECTOR_NAME = "collectorName";
private static final String KEY_COLLECTOR_VERSION = "collectorVersion";
private static final String KEY_COLLECTOR_HOST = "collectorHost";
private final AlertCollectorDao alertCollectorDao;
private final AlarmCommonReduce alarmCommonReduce;
private final AlarmCacheManager alarmCacheManager;
private ResourceBundle bundle;
public CollectorAlertHandler(AlarmCommonReduce alarmCommonReduce, AlertCollectorDao alertCollectorDao,
AlarmCacheManager alarmCacheManager) {
this.alarmCommonReduce = alarmCommonReduce;
this.alertCollectorDao = alertCollectorDao;
this.alarmCacheManager = alarmCacheManager;
this.bundle = ResourceBundleUtil.getBundle("alerter");
}
/**
* handle collector online
*
* @param identity collector name
*/
public void online(final String identity) {
Collector collector = alertCollectorDao.findCollectorByName(identity);
if (collector == null) {
return;
}
Map<String, String> fingerPrints = new HashMap<>(8);
fingerPrints.put(KEY_COLLECTOR_NAME, collector.getName());
fingerPrints.put(KEY_COLLECTOR_VERSION, collector.getVersion());
fingerPrints.put(KEY_COLLECTOR_HOST, collector.getIp());
String fingerprint = AlertUtil.calculateFingerprint(fingerPrints);
SingleAlert firingAlert = alarmCacheManager.getFiring(fingerprint);
if (firingAlert != null) {
firingAlert.setTriggerTimes(1);
firingAlert.setEndAt(System.currentTimeMillis());
firingAlert.setStatus(CommonConstants.ALERT_STATUS_RESOLVED);
alarmCommonReduce.reduceAndSendAlarm(firingAlert.clone());
}
}
/**
* handle collector offline
*
* @param identity collector name
*/
public void offline(final String identity) {
Collector collector = alertCollectorDao.findCollectorByName(identity);
if (collector == null) {
return;
}
long currentTimeMill = System.currentTimeMillis();
Map<String, String> fingerPrints = new HashMap<>(8);
fingerPrints.put(KEY_COLLECTOR_NAME, collector.getName());
fingerPrints.put(KEY_COLLECTOR_VERSION, collector.getVersion());
fingerPrints.put(KEY_COLLECTOR_HOST, collector.getIp());
String fingerprint = AlertUtil.calculateFingerprint(fingerPrints);
SingleAlert existingAlert = alarmCacheManager.getFiring(fingerprint);
if (existingAlert == null) {
SingleAlert newAlert = SingleAlert.builder()
.labels(fingerPrints)
.annotations(fingerPrints)
.content(this.bundle.getString("alerter.availability.collector.offline"))
.status(CommonConstants.ALERT_STATUS_FIRING)
.triggerTimes(1)
.startAt(currentTimeMill)
.activeAt(currentTimeMill)
.build();
alarmCacheManager.putFiring(fingerprint, newAlert);
alarmCommonReduce.reduceAndSendAlarm(newAlert.clone());
}
}
@EventListener(SystemConfigChangeEvent.class)
public void onSystemConfigChangeEvent(SystemConfigChangeEvent event) {
log.info("calculate alarm receive system config change event: {}.", event.getSource());
this.bundle = ResourceBundleUtil.getBundle("alerter");
}
}
@@ -0,0 +1,171 @@
/*
* 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.hertzbeat.alert.calculate;
import java.util.HashMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce;
import org.apache.hertzbeat.alert.service.DataSourceService;
import org.apache.hertzbeat.alert.util.AlertTemplateUtil;
import org.apache.hertzbeat.alert.util.AlertUtil;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
/**
* Periodic Alert Calculator
*/
@Slf4j
@Component
public class PeriodicAlertCalculator {
private static final String VALUE = "__value__";
private static final String TIMESTAMP = "__timestamp__";
private final DataSourceService dataSourceService;
private final AlarmCommonReduce alarmCommonReduce;
private final AlarmCacheManager alarmCacheManager;
public PeriodicAlertCalculator(DataSourceService dataSourceService, AlarmCommonReduce alarmCommonReduce,
AlarmCacheManager alarmCacheManager) {
this.dataSourceService = dataSourceService;
this.alarmCommonReduce = alarmCommonReduce;
this.alarmCacheManager = alarmCacheManager;
}
public void calculate(AlertDefine rule) {
if (!rule.isEnable() || StringUtils.isEmpty(rule.getExpr())) {
log.error("Periodic rule {} is disabled or expression is empty", rule.getName());
return;
}
long currentTimeMilli = System.currentTimeMillis();
try {
// for prometheus is instant promql query, for db is sql query
// result: [{'value': 100, 'timestamp': 1343554, 'instance': 'node1'},{'value': 200, 'timestamp': 1343555, 'instance': 'node2'}]
// the return result should be matched with threshold
try {
List<Map<String, Object>> results = dataSourceService.calculate(
rule.getDatasource(),
rule.getExpr()
);
// if no match the expr threshold, the results item map {'value': null} should be null and others field keep
// if results has multi list, should trigger multi alert
if (CollectionUtils.isEmpty(results)) {
return;
}
for (Map<String, Object> result : results) {
Map<String, String> fingerPrints = new HashMap<>(8);
// here use the alert name as finger, not care the alert name may be changed
fingerPrints.put(CommonConstants.LABEL_ALERT_NAME, rule.getName());
fingerPrints.putAll(rule.getLabels());
for (Map.Entry<String, Object> entry : result.entrySet()) {
if (entry.getValue() != null && !VALUE.equals(entry.getKey())
&& !TIMESTAMP.equals(entry.getKey())) {
fingerPrints.put(entry.getKey(), entry.getValue().toString());
}
}
if (result.get(VALUE) == null) {
// recovery the alert
handleRecoveredAlert(fingerPrints);
continue;
}
Map<String, Object> fieldValueMap = new HashMap<>(8);
fieldValueMap.putAll(rule.getLabels());
fieldValueMap.put(CommonConstants.LABEL_ALERT_NAME, rule.getName());
for (Map.Entry<String, Object> entry : result.entrySet()) {
if (entry.getValue() != null) {
fieldValueMap.put(entry.getKey(), entry.getValue());
}
}
afterThresholdRuleMatch(currentTimeMilli, fingerPrints, fieldValueMap, rule);
}
} catch (Exception ignored) {
// ignore the query exception eg: no result, timeout, etc
return;
}
} catch (Exception e) {
log.error("Calculate periodic rule {} failed: {}", rule.getName(), e.getMessage());
}
}
private void afterThresholdRuleMatch(long currentTimeMilli, Map<String, String> fingerPrints,
Map<String, Object> fieldValueMap, AlertDefine define) {
String fingerprint = AlertUtil.calculateFingerprint(fingerPrints);
SingleAlert existingAlert = alarmCacheManager.getPending(fingerprint);
Map<String, String> labels = new HashMap<>(8);
fieldValueMap.putAll(define.getLabels());
labels.putAll(fingerPrints);
int requiredTimes = define.getTimes() == null ? 1 : define.getTimes();
if (existingAlert == null) {
// First time triggering alert, create new alert and set to pending status
SingleAlert newAlert = SingleAlert.builder()
.labels(labels)
// todo render var content in annotations
.annotations(define.getAnnotations())
.content(AlertTemplateUtil.render(define.getTemplate(), fieldValueMap))
.status(CommonConstants.ALERT_STATUS_PENDING)
.triggerTimes(1)
.startAt(currentTimeMilli)
.activeAt(currentTimeMilli)
.build();
// If required trigger times is 1, set to firing status directly
if (requiredTimes <= 1) {
newAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING);
alarmCacheManager.putFiring(fingerprint, newAlert);
alarmCommonReduce.reduceAndSendAlarm(newAlert.clone());
} else {
// Otherwise put into pending queue first
alarmCacheManager.putPending(fingerprint, newAlert);
}
} else {
// Update existing alert
existingAlert.setTriggerTimes(existingAlert.getTriggerTimes() + 1);
existingAlert.setActiveAt(currentTimeMilli);
// Check if required trigger times reached
if (existingAlert.getStatus().equals(CommonConstants.ALERT_STATUS_PENDING) && existingAlert.getTriggerTimes() >= requiredTimes) {
// Reached trigger times threshold, change to firing status
alarmCacheManager.removePending(fingerprint);
existingAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING);
alarmCacheManager.putFiring(fingerprint, existingAlert);
alarmCommonReduce.reduceAndSendAlarm(existingAlert.clone());
}
}
}
private void handleRecoveredAlert(Map<String, String> fingerprints) {
String fingerprint = AlertUtil.calculateFingerprint(fingerprints);
SingleAlert firingAlert = alarmCacheManager.removeFiring(fingerprint);
if (firingAlert != null) {
// todo consider multi times to tig for resolved alert
firingAlert.setTriggerTimes(1);
firingAlert.setEndAt(System.currentTimeMillis());
firingAlert.setStatus(CommonConstants.ALERT_STATUS_RESOLVED);
alarmCommonReduce.reduceAndSendAlarm(firingAlert.clone());
}
alarmCacheManager.removePending(fingerprint);
}
}
@@ -0,0 +1,95 @@
/*
* 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.hertzbeat.alert.calculate;
import static org.apache.hertzbeat.common.constants.CommonConstants.ALERT_THRESHOLD_TYPE_PERIODIC;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.dao.AlertDefineDao;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
/**
* Periodic Alert Rule Scheduler
*/
@Slf4j
@Component
public class PeriodicAlertRuleScheduler implements CommandLineRunner {
private final PeriodicAlertCalculator calculator;
private final AlertDefineDao alertDefineDao;
private final ScheduledExecutorService scheduledExecutor;
private final Map<Long, ScheduledFuture<?>> scheduledFutures;
public PeriodicAlertRuleScheduler(PeriodicAlertCalculator calculator, AlertDefineDao alertDefineDao) {
this.calculator = calculator;
this.alertDefineDao = alertDefineDao;
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setUncaughtExceptionHandler((thread, throwable) -> {
log.error("Scheduled periodic alert threshold has uncaughtException.");
log.error(throwable.getMessage(), throwable);
})
.setDaemon(true)
.setNameFormat("periodic-alert-threshold-worker-%d")
.build();
this.scheduledExecutor = Executors.newScheduledThreadPool(10, threadFactory);
this.scheduledFutures = new ConcurrentHashMap<>();
}
public void cancelSchedule(Long ruleId) {
if (ruleId == null) {
return;
}
ScheduledFuture<?> future = scheduledFutures.get(ruleId);
if (future != null) {
future.cancel(true);
scheduledFutures.remove(ruleId);
}
}
public void updateSchedule(AlertDefine rule) {
if (rule == null || rule.getId() == null) {
log.error("Alert rule is null or rule id is null.");
return;
}
cancelSchedule(rule.getId());
if (rule.getType().equals(ALERT_THRESHOLD_TYPE_PERIODIC)) {
ScheduledFuture<?> future = scheduledExecutor.scheduleAtFixedRate(() -> {
calculator.calculate(rule);
}, 0, rule.getPeriod(), java.util.concurrent.TimeUnit.SECONDS);
scheduledFutures.put(rule.getId(), future);
}
}
@Override
public void run(String... args) throws Exception {
log.info("Starting periodic alert rule scheduler...");
List<AlertDefine> periodicRules = alertDefineDao.findAlertDefinesByTypeAndEnableTrue(ALERT_THRESHOLD_TYPE_PERIODIC);
for (AlertDefine rule : periodicRules) {
updateSchedule(rule);
}
}
}
@@ -0,0 +1,444 @@
/*
* 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.hertzbeat.alert.calculate;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.jexl3.JexlException;
import org.apache.commons.jexl3.JexlExpression;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.alert.AlerterWorkerPool;
import org.apache.hertzbeat.alert.dao.SingleAlertDao;
import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce;
import org.apache.hertzbeat.alert.service.AlertDefineService;
import org.apache.hertzbeat.alert.util.AlertTemplateUtil;
import org.apache.hertzbeat.alert.util.AlertUtil;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
import org.apache.hertzbeat.common.entity.message.CollectRep;
import org.apache.hertzbeat.common.queue.CommonDataQueue;
import org.apache.hertzbeat.common.util.CommonUtil;
import org.apache.hertzbeat.common.util.JexlExpressionRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* Calculate alarms based on the alarm definition rules and collected data
*/
@Component
@Slf4j
public class RealTimeAlertCalculator {
private static final int CALCULATE_THREADS = 3;
private static final String KEY_INSTANCE = "__instance__";
private static final String KEY_INSTANCE_NAME = "__instancename__";
private static final String KEY_INSTANCE_HOST = "__instancehost__";
private static final String KEY_APP = "__app__";
private static final String KEY_METRICS = "__metrics__";
private static final String KEY_PRIORITY = "__priority__";
private static final String KEY_CODE = "__code__";
private static final String KEY_AVAILABLE = "__available__";
private static final String KEY_LABELS = "__labels__";
private static final String UP = "up";
private static final String DOWN = "down";
private static final String KEY_ROW = "__row__";
private static final Pattern APP_PATTERN = Pattern.compile("equals\\(__app__,\"([^\"]+)\"\\)");
private static final Pattern AVAILABLE_PATTERN = Pattern.compile("equals\\(__available__,\"([^\"]+)\"\\)");
private static final Pattern LABEL_PATTERN = Pattern.compile("contains\\(__labels__,\\s*\"([^\"]+)\"\\)");
private static final Pattern INSTANCE_PATTERN = Pattern.compile("equals\\(__instance__,\\s*\"(\\d+)\"\\)");
private static final Pattern METRICS_PATTERN = Pattern.compile("equals\\(__metrics__,\"([^\"]+)\"\\)");
private final AlerterWorkerPool workerPool;
private final CommonDataQueue dataQueue;
private final AlertDefineService alertDefineService;
private final AlarmCommonReduce alarmCommonReduce;
private final AlarmCacheManager alarmCacheManager;
@Autowired
public RealTimeAlertCalculator(AlerterWorkerPool workerPool, CommonDataQueue dataQueue,
AlertDefineService alertDefineService, SingleAlertDao singleAlertDao,
AlarmCommonReduce alarmCommonReduce, AlarmCacheManager alarmCacheManager) {
this(workerPool, dataQueue, alertDefineService, singleAlertDao, alarmCommonReduce, alarmCacheManager, true);
}
/**
* Constructor for RealTimeAlertCalculator with a toggle to control whether to start alert calculation threads.
*
* @param workerPool The worker pool used for concurrent alert calculation.
* @param dataQueue The queue from which metric data is pulled and pushed.
* @param alertDefineService The service providing alert definition rules.
* @param singleAlertDao The DAO for fetching persisted alert states from storage.
* @param alarmCommonReduce The component responsible for reducing and sending alerts.
* @param start If true, the alert calculation threads will start automatically;
* set to false to disable thread start (useful for unit testing).
*/
public RealTimeAlertCalculator(AlerterWorkerPool workerPool, CommonDataQueue dataQueue,
AlertDefineService alertDefineService, SingleAlertDao singleAlertDao,
AlarmCommonReduce alarmCommonReduce, AlarmCacheManager alarmCacheManager, boolean start) {
this.workerPool = workerPool;
this.dataQueue = dataQueue;
this.alarmCommonReduce = alarmCommonReduce;
this.alertDefineService = alertDefineService;
this.alarmCacheManager = alarmCacheManager;
if (start) {
startCalculate();
}
}
public void startCalculate() {
Runnable runnable = () -> {
while (!Thread.currentThread().isInterrupted()) {
try {
CollectRep.MetricsData metricsData = dataQueue.pollMetricsDataToAlerter();
calculate(metricsData);
dataQueue.sendMetricsDataToStorage(metricsData);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error("calculate alarm error: {}.", e.getMessage(), e);
}
}
};
for (int i = 0; i < CALCULATE_THREADS; i++) {
workerPool.executeJob(runnable);
}
}
private void calculate(CollectRep.MetricsData metricsData) {
long currentTimeMilli = System.currentTimeMillis();
String instance = String.valueOf(metricsData.getId());
String instanceName = metricsData.getInstanceName();
String instanceHost = metricsData.getInstanceHost();
String app = metricsData.getApp();
String metrics = metricsData.getMetrics();
if ((CommonConstants.PROMETHEUS_APP_PREFIX + instanceName).equals(metricsData.getApp())) {
app = CommonConstants.PROMETHEUS;
}
int priority = metricsData.getPriority();
int code = metricsData.getCode().getNumber();
Map<String, String> labels = metricsData.getLabels();
Map<String, String> annotations = metricsData.getAnnotations();
List<AlertDefine> thresholds = this.alertDefineService.getRealTimeAlertDefines();
// Filter thresholds by app, metrics, labels and instance
thresholds = filterThresholdsByAppAndMetrics(thresholds, app, metrics, labels, instance, priority);
if (thresholds.isEmpty()) {
return;
}
Map<String, Object> commonContext = new HashMap<>(8);
commonContext.put(KEY_INSTANCE, instance);
commonContext.put(KEY_INSTANCE_NAME, instanceName);
commonContext.put(KEY_INSTANCE_HOST, instanceHost);
commonContext.put(KEY_APP, app);
commonContext.put(KEY_PRIORITY, priority);
commonContext.put(KEY_CODE, code);
commonContext.put(KEY_METRICS, metrics);
commonContext.put(KEY_LABELS, String.join(",", kvLabelsToKvStringSet(labels)));
if (priority == 0) {
commonContext.put(KEY_AVAILABLE, metricsData.getCode() == CollectRep.Code.SUCCESS ? UP : DOWN);
}
if (labels != null) {
commonContext.putAll(labels);
}
List<CollectRep.Field> fields = metricsData.getFields();
Map<String, Object> fieldValueMap = new HashMap<>(8);
int valueRowCount = metricsData.getValuesCount();
for (AlertDefine define : thresholds) {
if (define.getLabels() == null) {
define.setLabels(new HashMap<>(8));
}
if (define.getAnnotations() == null) {
define.setAnnotations(new HashMap<>(8));
}
fieldValueMap.clear();
fieldValueMap.putAll(commonContext);
final String expr = define.getExpr();
if (StringUtils.isBlank(expr)) {
continue;
}
Map<String, String> commonFingerPrints = new HashMap<>(8);
commonFingerPrints.put(CommonConstants.LABEL_INSTANCE, instance);
// here use the alert name as finger, not care the alert name may be changed
commonFingerPrints.put(CommonConstants.LABEL_ALERT_NAME, define.getName());
commonFingerPrints.put(CommonConstants.LABEL_INSTANCE_NAME, instanceName);
commonFingerPrints.put(CommonConstants.LABEL_INSTANCE_HOST, instanceHost);
commonFingerPrints.putAll(define.getLabels());
if (labels != null) {
commonFingerPrints.putAll(labels);
}
{
// trigger the expr before the metrics data, due the available up down or others
try {
boolean match = execAlertExpression(fieldValueMap, expr, true);
try {
if (match) {
// If the threshold rule matches, the number of times the threshold has been triggered is determined and an alarm is triggered
afterThresholdRuleMatch(currentTimeMilli, commonFingerPrints, fieldValueMap, define, annotations);
} else {
handleRecoveredAlert(commonFingerPrints);
}
// if this threshold pre compile success, ignore blew
continue;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
} catch (Exception ignored) {}
}
Map<String, String> fingerPrints = new HashMap<>(8);
for (CollectRep.ValueRow valueRow : metricsData.getValues()) {
if (CollectionUtils.isEmpty(valueRow.getColumnsList())) {
continue;
}
fieldValueMap.clear();
fieldValueMap.put(KEY_ROW, valueRowCount);
fieldValueMap.putAll(commonContext);
fingerPrints.clear();
fingerPrints.putAll(commonFingerPrints);
for (int index = 0; index < valueRow.getColumnsList().size(); index++) {
String valueStr = valueRow.getColumns(index);
final CollectRep.Field field = fields.get(index);
if (CommonConstants.NULL_VALUE.equals(valueStr)) {
fieldValueMap.put(field.getName(), null);
continue;
}
final int fieldType = field.getType();
if (fieldType == CommonConstants.TYPE_NUMBER) {
final Double doubleValue;
if ((doubleValue = CommonUtil.parseStrDouble(valueStr)) != null) {
fieldValueMap.put(field.getName(), doubleValue);
}
} else if (fieldType == CommonConstants.TYPE_TIME) {
final Integer integerValue;
if ((integerValue = CommonUtil.parseStrInteger(valueStr)) != null) {
fieldValueMap.put(field.getName(), integerValue);
}
} else {
if (StringUtils.isNotEmpty(valueStr)) {
fieldValueMap.put(field.getName(), valueStr);
}
}
if (field.getLabel()) {
fingerPrints.put(field.getName(), valueStr);
}
}
try {
boolean match = execAlertExpression(fieldValueMap, expr, false);
try {
if (match) {
afterThresholdRuleMatch(currentTimeMilli, fingerPrints, fieldValueMap, define, annotations);
} else {
handleRecoveredAlert(fingerPrints);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
} catch (Exception ignored) {}
}
}
}
/**
* Filter alert definitions by app, metrics and instance
*
* @param thresholds Alert definitions to filter
* @param app Current app name
* @param metrics Current metrics name
* @param instance Current instance id
* @param priority Current priority
* @return Filtered alert definitions
*/
public List<AlertDefine> filterThresholdsByAppAndMetrics(List<AlertDefine> thresholds, String app, String metrics, Map<String, String> labels, String instance, int priority) {
return thresholds.stream()
.filter(define -> {
if (StringUtils.isBlank(define.getExpr())) {
return false;
}
String expr = define.getExpr();
// Extract and check app - required
Matcher appMatcher = APP_PATTERN.matcher(expr);
if (!appMatcher.find() || !app.equals(appMatcher.group(1))) {
return false;
}
// Extract and check available - required
if (priority != 0) {
Matcher availableMatcher = AVAILABLE_PATTERN.matcher(expr);
if (availableMatcher.find()) {
return false;
}
}
// Extract and check metrics - optional
Matcher metricsMatcher = METRICS_PATTERN.matcher(expr);
if (metricsMatcher.find() && !metrics.equals(metricsMatcher.group(1))) {
return false;
}
// Extract and check instance - optional with multiple values
Matcher instanceMatcher = INSTANCE_PATTERN.matcher(expr);
Matcher labelMatcher = LABEL_PATTERN.matcher(expr);
// If no instance and instance labels specified in expr, accept all instances
if (!instanceMatcher.find() && !labelMatcher.find()) {
return true;
}
// Reset matcher to check all instances
instanceMatcher.reset();
labelMatcher.reset();
// If instances specified, current instance must match one of them
while (instanceMatcher.find()) {
if (Objects.equals(instance, instanceMatcher.group(1))) {
return true;
}
}
// If instance labels specified, current instance must match one of them
Set<String> labelKvStringSet = kvLabelsToKvStringSet(labels);
while (labelMatcher.find()) {
String label = labelMatcher.group(1);
if (labelKvStringSet.contains(label)) {
return true;
}
}
return false;
})
.collect(Collectors.toList());
}
private void handleRecoveredAlert(Map<String, String> fingerprints) {
String fingerprint = AlertUtil.calculateFingerprint(fingerprints);
SingleAlert firingAlert = alarmCacheManager.removeFiring(fingerprint);
if (firingAlert != null) {
// todo consider multi times to tig for resolved alert
firingAlert.setTriggerTimes(1);
firingAlert.setEndAt(System.currentTimeMillis());
firingAlert.setStatus(CommonConstants.ALERT_STATUS_RESOLVED);
alarmCommonReduce.reduceAndSendAlarm(firingAlert.clone());
}
alarmCacheManager.removePending(fingerprint);
}
private void afterThresholdRuleMatch(long currentTimeMilli, Map<String, String> fingerPrints,
Map<String, Object> fieldValueMap, AlertDefine define, Map<String, String> annotations) {
String fingerprint = AlertUtil.calculateFingerprint(fingerPrints);
SingleAlert existingAlert = alarmCacheManager.getPending(fingerprint);
fieldValueMap.putAll(define.getLabels());
int requiredTimes = define.getTimes() == null ? 1 : define.getTimes();
if (existingAlert == null) {
// First time triggering alert, create new alert and set to pending status
Map<String, String> alertLabels = new HashMap<>(8);
alertLabels.putAll(fingerPrints);
Map<String, String> alertAnnotations = new HashMap<>(8);
if (annotations != null) {
alertAnnotations.putAll(annotations);
}
if (define.getAnnotations() != null) {
alertAnnotations.putAll(define.getAnnotations());
}
// render var content in annotations
for (Map.Entry<String, String> entry : alertAnnotations.entrySet()) {
entry.setValue(AlertTemplateUtil.render(entry.getValue(), fieldValueMap));
}
SingleAlert newAlert = SingleAlert.builder()
.labels(alertLabels)
.annotations(alertAnnotations)
// render var content in content
.content(AlertTemplateUtil.render(define.getTemplate(), fieldValueMap))
.status(CommonConstants.ALERT_STATUS_PENDING)
.triggerTimes(1)
.startAt(currentTimeMilli)
.activeAt(currentTimeMilli)
.build();
// If required trigger times is 1, set to firing status directly
if (requiredTimes <= 1) {
newAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING);
alarmCacheManager.putFiring(fingerprint, newAlert);
alarmCommonReduce.reduceAndSendAlarm(newAlert.clone());
} else {
// Otherwise put into pending queue first
alarmCacheManager.putPending(fingerprint, newAlert);
}
} else {
// Update existing alert
existingAlert.setTriggerTimes(existingAlert.getTriggerTimes() + 1);
existingAlert.setActiveAt(currentTimeMilli);
// Check if required trigger times reached
if (existingAlert.getStatus().equals(CommonConstants.ALERT_STATUS_PENDING) && existingAlert.getTriggerTimes() >= requiredTimes) {
// Reached trigger times threshold, change to firing status
alarmCacheManager.removePending(fingerprint);
existingAlert.setStatus(CommonConstants.ALERT_STATUS_FIRING);
alarmCacheManager.putFiring(fingerprint, existingAlert);
alarmCommonReduce.reduceAndSendAlarm(existingAlert.clone());
}
}
}
private boolean execAlertExpression(Map<String, Object> fieldValueMap, String expr, boolean ignoreJexlException) {
Boolean match;
JexlExpression expression;
try {
expression = JexlExpressionRunner.compile(expr);
} catch (JexlException jexlException) {
log.warn("Alarm Rule: {} Compile Error: {}.", expr, jexlException.getMessage());
throw jexlException;
} catch (Exception e) {
log.error("Alarm Rule: {} Unknown Error: {}.", expr, e.getMessage());
throw e;
}
try {
match = (Boolean) JexlExpressionRunner.evaluate(expression, fieldValueMap);
} catch (JexlException jexlException) {
if (ignoreJexlException) {
log.debug("Alarm Rule: {} Run Error: {}.", expr, jexlException.getMessage());
} else {
log.error("Alarm Rule: {} Run Error: {}.", expr, jexlException.getMessage());
}
throw jexlException;
} catch (Exception e) {
log.error("Alarm Rule: {} Unknown Error: {}.", expr, e.getMessage());
throw e;
}
return match != null && match;
}
private Set<String> kvLabelsToKvStringSet(Map<String, String> labels) {
if (labels == null || labels.isEmpty()) {
return Collections.singleton("");
}
return labels.entrySet().stream()
.map(item -> item.getKey() + ":" + item.getValue())
.collect(Collectors.toSet());
}
}
@@ -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.hertzbeat.alert.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* SSE manager for alert
*/
@Slf4j
@Component
public class AlertSseManager {
private final Map<Long, SseEmitter> emitters = new ConcurrentHashMap<>();
public SseEmitter createEmitter(Long clientId) {
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
emitter.onCompletion(() -> removeEmitter(clientId));
emitter.onTimeout(() -> removeEmitter(clientId));
emitter.onError((ex) -> removeEmitter(clientId));
emitters.put(clientId, emitter);
return emitter;
}
@Async
public void broadcast(String data) {
emitters.forEach((clientId, emitter) -> {
try {
emitter.send(SseEmitter.event()
.id(String.valueOf(System.currentTimeMillis()))
.name("ALERT_EVENT")
.data(data));
} catch (IOException | IllegalStateException e) {
emitter.complete();
removeEmitter(clientId);
} catch (Exception exception) {
log.error("Failed to broadcast alert data to client: {}", exception.getMessage());
emitter.complete();
removeEmitter(clientId);
}
});
}
private void removeEmitter(Long clientId) {
emitters.remove(clientId);
}
}
@@ -0,0 +1,55 @@
/*
* 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.hertzbeat.alert.config;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Alibaba Cloud SMS configuration properties
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AlibabaSmsProperties {
/**
* Alibaba Cloud access key id
*/
@NotBlank(message = "AccessKeyId cannot be empty")
private String accessKeyId;
/**
* Alibaba Cloud access key secret
*/
@NotBlank(message = "AccessKeySecret cannot be empty")
private String accessKeySecret;
/**
* SMS signature
*/
@NotBlank(message = "SignName cannot be empty")
private String signName;
/**
* SMS template Code
*/
@NotBlank(message = "TemplateCode cannot be null")
private String templateCode;
}
@@ -0,0 +1,46 @@
/*
* 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.hertzbeat.alert.config;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* AWS Cloud SMS configuration properties
*/
@Data
public class AwsSmsProperties {
/**
* AWS Cloud access key id
*/
@NotBlank(message = "AccessKeyId cannot be empty")
private String accessKeyId;
/**
* AWS Cloud access key secret
*/
@NotBlank(message = "AccessKeySecret cannot be empty")
private String accessKeySecret;
/**
* AWS Cloud region
*/
@NotBlank(message = "region cannot be empty")
private String region;
}
@@ -0,0 +1,77 @@
/*
* 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.hertzbeat.alert.config;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* SMS configuration
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@ConfigurationProperties(prefix = "alerter.sms")
public class SmsConfig {
/**
* whether to enable SMS, default is false
*/
private boolean enable = false;
/**
* sms service provider
*/
@NotBlank(message = "Type cannot be empty")
private String type;
/**
* Tencent cloud SMS configuration
*/
private TencentSmsProperties tencent;
/**
* Aliyun SMS configuration
*/
private AlibabaSmsProperties alibaba;
/**
* UniSMS configuration
*/
private UniSmsProperties unisms;
/**
* Aws configuration
*/
private AwsSmsProperties aws;
/**
* Twilio SMS configuration
*/
private TwilioSmsProperties twilio;
/**
* Smslocal SMS configuration
*/
private SmslocalSmsProperties smslocal;
}
@@ -0,0 +1,37 @@
/*
* 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.hertzbeat.alert.config;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Smslocal SMS Properties
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SmslocalSmsProperties {
/**
* SmsLocal account api key
*/
private String apiKey;
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.pojo.dto;
package org.apache.hertzbeat.alert.config;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
@@ -23,26 +23,39 @@ import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Tencent Sms Sender configuration dto
* Tencent Cloud SMS properties
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SmsTencentConfig {
public class TencentSmsProperties {
/**
* Tencent cloud account secret id
*/
@NotBlank(message = "SecretId cannot be empty")
private String secretId;
/**
* Tencent cloud account secret key
*/
@NotBlank(message = "SecretKey cannot be empty")
private String secretKey;
@NotBlank(message = "SignName cannot be empty")
private String signName;
/**
* SMS app id
*/
@NotBlank(message = "AppId cannot be null")
private String appId;
/**
* SMS signature
*/
@NotBlank(message = "SignName cannot be empty")
private String signName;
/**
* SMS template ID
*/
@NotBlank(message = "templateId cannot be null")
private String templateId;
}
}
@@ -0,0 +1,49 @@
/*
* 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.hertzbeat.alert.config;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Twilio SMS configuration properties
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TwilioSmsProperties {
/**
* Twilio Account SID
*/
@NotBlank(message = "Account SID cannot be empty")
private String accountSid;
/**
* Twilio Auth Token
*/
@NotBlank(message = "Auth Token cannot be empty")
private String authToken;
/**
* Twilio Issued Phone Number
*/
@NotBlank(message = "Twilio Phone Number cannot be empty")
private String twilioPhoneNumber;
}
@@ -0,0 +1,60 @@
/*
* 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.hertzbeat.alert.config;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* UniSMS properties
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UniSmsProperties {
/**
* UniSMS access key id
*/
@NotBlank(message = "accessKeyId cannot be empty")
private String accessKeyId;
/**
* UniSMS access key secret, required for HMAC mode
*/
private String accessKeySecret;
/**
* SMS signature
*/
@NotBlank(message = "signature cannot be null")
private String signature;
/**
* SMS template ID
*/
@NotBlank(message = "templateId cannot be null")
private String templateId;
/**
* Authentication mode: simple or hmac, default is simple
*/
@NotBlank(message = "authMode cannot be null")
private String authMode = "simple";
}
@@ -17,20 +17,16 @@
package org.apache.hertzbeat.alert.controller;
import static org.apache.hertzbeat.common.constants.CommonConstants.MONITOR_NOT_EXIST_CODE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.hertzbeat.alert.service.AlertDefineService;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.apache.hertzbeat.common.entity.alerter.AlertDefineMonitorBind;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.apache.hertzbeat.common.support.exception.AlertExpressionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@@ -39,8 +35,17 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static org.apache.hertzbeat.common.constants.CommonConstants.FAIL_CODE;
import static org.apache.hertzbeat.common.constants.CommonConstants.MONITOR_NOT_EXIST_CODE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
* Alarm definition management API
*/
@@ -93,24 +98,18 @@ public class AlertDefineController {
return ResponseEntity.ok(Message.success("Delete success"));
}
@PostMapping(path = "/{alertDefineId}/monitors")
@Operation(summary = "Application alarm definition is associated with monitoring",
description = "Applies the association between specified alarm definitions and monitoring")
public ResponseEntity<Message<Void>> applyAlertDefineMonitorsBind(
@Parameter(description = "Alarm Definition ID", example = "6565463543") @PathVariable("alertDefineId") long alertDefineId,
@RequestBody List<AlertDefineMonitorBind> alertDefineMonitorBinds) {
alertDefineService.applyBindAlertDefineMonitors(alertDefineId, alertDefineMonitorBinds);
return ResponseEntity.ok(Message.success("Apply success"));
}
@GetMapping(path = "/{alertDefineId}/monitors")
@Operation(summary = "Application alarm definition is associated with monitoring",
description = "Applies the association between specified alarm definitions and monitoring")
public ResponseEntity<Message<List<AlertDefineMonitorBind>>> getAlertDefineMonitorsBind(
@Parameter(description = "Alarm Definition ID", example = "6565463543") @PathVariable("alertDefineId") long alertDefineId) {
List<AlertDefineMonitorBind> defineBinds = alertDefineService.getBindAlertDefineMonitors(alertDefineId);
defineBinds = defineBinds.stream().filter(item -> item.getMonitor() != null).collect(Collectors.toList());
return ResponseEntity.ok(Message.success(defineBinds));
@GetMapping(path = "/preview/{datasource}")
@Operation(summary = "Alarm definition expression preview",
description = "If the expression is formal, then the result of the query will be returned, otherwise it will respond with an error")
public ResponseEntity<Message<List<Map<String, Object>>>> getDefinePreview(
@Parameter(description = "Data Source Type", example = "promql") @PathVariable("datasource") String datasource,
@Parameter(description = "alert threshold type:realtime,periodic") @RequestParam String type,
@Parameter(description = "alert threshold expression") @RequestParam String expr) {
try {
return ResponseEntity.ok(Message.successWithData(alertDefineService.getDefinePreview(datasource, type, expr)));
} catch (AlertExpressionException ae) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Message.fail(FAIL_CODE, ae.getMessage()));
}
}
}
@@ -55,12 +55,11 @@ public class AlertDefinesController {
public ResponseEntity<Message<Page<AlertDefine>>> getAlertDefines(
@Parameter(description = "Alarm Definition ID", example = "6565463543") @RequestParam(required = false) List<Long> ids,
@Parameter(description = "Search-Target Expr Template", example = "x") @RequestParam(required = false) String search,
@Parameter(description = "Alarm Definition Severity", example = "6565463543") @RequestParam(required = false) Byte priority,
@Parameter(description = "Sort field, default id", example = "id") @RequestParam(defaultValue = "id") String sort,
@Parameter(description = "Sort mode: asc: ascending, desc: descending", example = "desc") @RequestParam(defaultValue = "desc") String order,
@Parameter(description = "List current page", example = "0") @RequestParam(defaultValue = "0") int pageIndex,
@Parameter(description = "Number of list pages", example = "8") @RequestParam(defaultValue = "8") int pageSize) {
Page<AlertDefine> alertDefinePage = alertDefineService.getAlertDefines(ids, search, priority, sort, order, pageIndex, pageSize);
Page<AlertDefine> alertDefinePage = alertDefineService.getAlertDefines(ids, search, sort, order, pageIndex, pageSize);
return ResponseEntity.ok(Message.success(alertDefinePage));
}
@@ -24,8 +24,8 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.Objects;
import org.apache.hertzbeat.alert.service.AlertConvergeService;
import org.apache.hertzbeat.common.entity.alerter.AlertConverge;
import org.apache.hertzbeat.alert.service.AlertGroupConvergeService;
import org.apache.hertzbeat.common.entity.alerter.AlertGroupConverge;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
@@ -42,38 +42,38 @@ import org.springframework.web.bind.annotation.RestController;
*/
@Tag(name = "Alert Converge API")
@RestController
@RequestMapping(path = "/api/alert/converge", produces = {APPLICATION_JSON_VALUE})
public class AlertConvergeController {
@RequestMapping(path = "/api/alert/group", produces = {APPLICATION_JSON_VALUE})
public class AlertGroupConvergeController {
@Autowired
private AlertConvergeService alertConvergeService;
private AlertGroupConvergeService alertGroupConvergeService;
@PostMapping
@Operation(summary = "New Alarm Converge", description = "Added an alarm Converge")
public ResponseEntity<Message<Void>> addNewAlertConverge(@Valid @RequestBody AlertConverge alertConverge) {
alertConvergeService.validate(alertConverge, false);
alertConvergeService.addAlertConverge(alertConverge);
@Operation(summary = "New Alarm Group Converge", description = "Added an alarm Group Converge")
public ResponseEntity<Message<Void>> addNewAlertGroupConverge(@Valid @RequestBody AlertGroupConverge alertGroupConverge) {
alertGroupConvergeService.validate(alertGroupConverge, false);
alertGroupConvergeService.addAlertGroupConverge(alertGroupConverge);
return ResponseEntity.ok(Message.success("Add success"));
}
@PutMapping
@Operation(summary = "Modifying an Alarm Converge", description = "Modify an existing alarm Converge")
public ResponseEntity<Message<Void>> modifyAlertConverge(@Valid @RequestBody AlertConverge alertConverge) {
alertConvergeService.validate(alertConverge, true);
alertConvergeService.modifyAlertConverge(alertConverge);
@Operation(summary = "Modifying an Alarm Group Converge", description = "Modify an existing alarm Group Converge")
public ResponseEntity<Message<Void>> modifyAlertGroupConverge(@Valid @RequestBody AlertGroupConverge alertGroupConverge) {
alertGroupConvergeService.validate(alertGroupConverge, true);
alertGroupConvergeService.modifyAlertGroupConverge(alertGroupConverge);
return ResponseEntity.ok(Message.success("Modify success"));
}
@GetMapping(path = "/{id}")
@Operation(summary = "Querying Alarm Converge",
description = "You can obtain alarm Converge information based on the alarm Converge ID")
public ResponseEntity<Message<AlertConverge>> getAlertConverge(
@Operation(summary = "Querying Alarm Group Converge",
description = "You can obtain alarm Group Converge information based on the alarm Converge ID")
public ResponseEntity<Message<AlertGroupConverge>> getAlertGroupConverge(
@Parameter(description = "Alarm Converge ID", example = "6565463543") @PathVariable("id") long id) {
AlertConverge alertConverge = alertConvergeService.getAlertConverge(id);
AlertGroupConverge alertGroupConverge = alertGroupConvergeService.getAlertGroupConverge(id);
return Objects.isNull(alertConverge)
? ResponseEntity.ok(Message.fail(MONITOR_NOT_EXIST_CODE, "AlertConverge not exist."))
: ResponseEntity.ok(Message.success(alertConverge));
return Objects.isNull(alertGroupConverge)
? ResponseEntity.ok(Message.fail(MONITOR_NOT_EXIST_CODE, "Alert Group Converge not exist."))
: ResponseEntity.ok(Message.success(alertGroupConverge));
}
}
@@ -23,8 +23,8 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.HashSet;
import java.util.List;
import org.apache.hertzbeat.alert.service.AlertConvergeService;
import org.apache.hertzbeat.common.entity.alerter.AlertConverge;
import org.apache.hertzbeat.alert.service.AlertGroupConvergeService;
import org.apache.hertzbeat.common.entity.alerter.AlertGroupConverge;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
@@ -40,34 +40,34 @@ import org.springframework.web.bind.annotation.RestController;
*/
@Tag(name = "Alert Converge Batch API")
@RestController
@RequestMapping(path = "/api/alert/converges", produces = {APPLICATION_JSON_VALUE})
public class AlertConvergesController {
@RequestMapping(path = "/api/alert/groups", produces = {APPLICATION_JSON_VALUE})
public class AlertGroupConvergesController {
@Autowired
private AlertConvergeService alertConvergeService;
private AlertGroupConvergeService alertGroupConvergeService;
@GetMapping
@Operation(summary = "Query the alarm converge list",
description = "You can obtain the list of alarm converge by querying filter items")
public ResponseEntity<Message<Page<AlertConverge>>> getAlertConverges(
@Operation(summary = "Query the alarm group converge list",
description = "You can obtain the list of alarm group group converge by querying filter items")
public ResponseEntity<Message<Page<AlertGroupConverge>>> getAlertGroupConverges(
@Parameter(description = "Alarm Converge ID", example = "6565463543") @RequestParam(required = false) List<Long> ids,
@Parameter(description = "Search Name", example = "x") @RequestParam(required = false) String search,
@Parameter(description = "Sort field, default id", example = "id") @RequestParam(defaultValue = "id") String sort,
@Parameter(description = "Sort mode: asc: ascending, desc: descending", example = "desc") @RequestParam(defaultValue = "desc") String order,
@Parameter(description = "List current page", example = "0") @RequestParam(defaultValue = "0") int pageIndex,
@Parameter(description = "Number of list pages", example = "8") @RequestParam(defaultValue = "8") int pageSize) {
Page<AlertConverge> alertConvergePage = alertConvergeService.getAlertConverges(ids, search, sort, order, pageIndex, pageSize);
return ResponseEntity.ok(Message.success(alertConvergePage));
Page<AlertGroupConverge> alertGroupConvergePage = alertGroupConvergeService.getAlertGroupConverges(ids, search, sort, order, pageIndex, pageSize);
return ResponseEntity.ok(Message.success(alertGroupConvergePage));
}
@DeleteMapping
@Operation(summary = "Delete alarm converge in batches",
description = "Delete alarm converge in batches based on the alarm converge ID list")
@Operation(summary = "Delete alarm group converge in batches",
description = "Delete alarm group converge in batches based on the alarm group converge ID list")
public ResponseEntity<Message<Void>> deleteAlertDefines(
@Parameter(description = "Alarm Converge IDs", example = "6565463543") @RequestParam(required = false) List<Long> ids
) {
if (ids != null && !ids.isEmpty()) {
alertConvergeService.deleteAlertConverges(new HashSet<>(ids));
alertGroupConvergeService.deleteAlertGroupConverges(new HashSet<>(ids));
}
return ResponseEntity.ok(Message.success());
}
@@ -0,0 +1,79 @@
/*
* 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.hertzbeat.alert.controller;
import static org.apache.hertzbeat.common.constants.CommonConstants.MONITOR_NOT_EXIST_CODE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.Objects;
import org.apache.hertzbeat.alert.service.AlertInhibitService;
import org.apache.hertzbeat.common.entity.alerter.AlertInhibit;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Alarm Inhibit management API
*/
@Tag(name = "Alert Inhibit API")
@RestController
@RequestMapping(path = "/api/alert/inhibit", produces = {APPLICATION_JSON_VALUE})
public class AlertInhibitController {
@Autowired
private AlertInhibitService alertInhibitService;
@PostMapping
@Operation(summary = "New Alarm Inhibit", description = "Added an alarm Inhibit")
public ResponseEntity<Message<Void>> addNewAlertInhibit(@Valid @RequestBody AlertInhibit alertInhibit) {
alertInhibitService.validate(alertInhibit, false);
alertInhibitService.addAlertInhibit(alertInhibit);
return ResponseEntity.ok(Message.success("Add success"));
}
@PutMapping
@Operation(summary = "Modifying an Alarm Inhibit", description = "Modify an existing alarm Inhibit")
public ResponseEntity<Message<Void>> modifyAlertInhibit(@Valid @RequestBody AlertInhibit alertInhibit) {
alertInhibitService.validate(alertInhibit, true);
alertInhibitService.modifyAlertInhibit(alertInhibit);
return ResponseEntity.ok(Message.success("Modify success"));
}
@GetMapping(path = "/{id}")
@Operation(summary = "Querying Alarm Inhibit",
description = "You can obtain alarm Inhibit information based on the alarm Inhibit ID")
public ResponseEntity<Message<AlertInhibit>> getAlertInhibit(
@Parameter(description = "Alarm Inhibit ID", example = "6565463543") @PathVariable("id") long id) {
AlertInhibit alertInhibit = alertInhibitService.getAlertInhibit(id);
return Objects.isNull(alertInhibit)
? ResponseEntity.ok(Message.fail(MONITOR_NOT_EXIST_CODE, "AlertInhibit not exist."))
: ResponseEntity.ok(Message.success(alertInhibit));
}
}
@@ -0,0 +1,76 @@
/*
* 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.hertzbeat.alert.controller;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.HashSet;
import java.util.List;
import org.apache.hertzbeat.alert.service.AlertInhibitService;
import org.apache.hertzbeat.common.entity.alerter.AlertInhibit;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Inhibit the batch API for alarms
*/
@Tag(name = "Alert Inhibit Batch API")
@RestController
@RequestMapping(path = "/api/alert/inhibits", produces = {APPLICATION_JSON_VALUE})
public class AlertInhibitsController {
@Autowired
private AlertInhibitService alertInhibitService;
@GetMapping
@Operation(summary = "Query the alarm inhibit list",
description = "You can obtain the list of alarm inhibit by querying filter items")
public ResponseEntity<Message<Page<AlertInhibit>>> getAlertInhibits(
@Parameter(description = "Alarm Inhibit ID", example = "6565463543") @RequestParam(required = false) List<Long> ids,
@Parameter(description = "Search Name", example = "x") @RequestParam(required = false) String search,
@Parameter(description = "Sort field, default id", example = "id") @RequestParam(defaultValue = "id") String sort,
@Parameter(description = "Sort mode: asc: ascending, desc: descending", example = "desc") @RequestParam(defaultValue = "desc") String order,
@Parameter(description = "List current page", example = "0") @RequestParam(defaultValue = "0") int pageIndex,
@Parameter(description = "Number of list pages", example = "8") @RequestParam(defaultValue = "8") int pageSize) {
Page<AlertInhibit> alertInhibitPage = alertInhibitService.getAlertInhibits(ids, search, sort, order, pageIndex, pageSize);
return ResponseEntity.ok(Message.success(alertInhibitPage));
}
@DeleteMapping
@Operation(summary = "Delete alarm inhibit in batches",
description = "Delete alarm inhibit in batches based on the alarm inhibit ID list")
public ResponseEntity<Message<Void>> deleteAlertDefines(
@Parameter(description = "Alarm Inhibit IDs", example = "6565463543") @RequestParam(required = false) List<Long> ids
) {
if (ids != null && !ids.isEmpty()) {
alertInhibitService.deleteAlertInhibits(new HashSet<>(ids));
}
Message<Void> message = Message.success();
return ResponseEntity.ok(message);
}
}
@@ -17,19 +17,19 @@
package org.apache.hertzbeat.alert.controller;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.dto.GeneralCloudAlertReport;
import org.apache.hertzbeat.alert.service.AlertService;
import org.apache.hertzbeat.alert.service.ExternAlertService;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
@@ -37,27 +37,79 @@ import org.springframework.web.bind.annotation.RestController;
*/
@Tag(name = "Extern Alarm Manage API")
@RestController
@RequestMapping(path = "/api/alerts/report", produces = {APPLICATION_JSON_VALUE})
@Slf4j
public class AlertReportController {
@Autowired
private AlertService alertService;
@PostMapping("/{cloud}")
@Operation(summary = "Interface for reporting external alarm information of cloud service")
public ResponseEntity<Message<Void>> addNewAlertReportFromCloud(@PathVariable("cloud") String cloudServiceName,
@RequestBody String alertReport) {
alertService.addNewAlertReportFromCloud(cloudServiceName, alertReport);
return ResponseEntity.ok(Message.success("Add report success"));
}
@PostMapping
@Operation(summary = "Interface for reporting external and general alarm information",
description = "The interface is used to report external and general alarm information")
public ResponseEntity<Message<Void>> addNewAlertReport(@RequestBody GeneralCloudAlertReport alertReport) {
alertReport.refreshAlertTime();
alertService.addNewAlertReport(alertReport);
return ResponseEntity.ok(Message.success("Add report success"));
private final List<ExternAlertService> externAlertServiceList;
public AlertReportController(List<ExternAlertService> externAlertServiceList) {
this.externAlertServiceList = externAlertServiceList;
}
@PostMapping("/api/alerts/report/{source}")
@Operation(summary = "Api for receive external alarm information")
public ResponseEntity<Message<Void>> receiveExternAlert(@PathVariable(value = "source") String source,
@RequestBody String content) {
log.info("Receive extern alert from source: {}, content: {}", source, content);
if (!StringUtils.hasText(source)) {
source = "default";
}
for (ExternAlertService externAlertService : externAlertServiceList) {
if (externAlertService.supportSource().equals(source)) {
try {
externAlertService.addExternAlert(content);
return ResponseEntity.ok(Message.success("Add extern alert success"));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Message.fail(CommonConstants.FAIL_CODE,
"Add extern alert failed: " + e.getMessage()));
}
}
}
log.warn("Not support extern alert from source: {}", source);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Message.fail(CommonConstants.FAIL_CODE, "Not support the " + source + " source alert"));
}
@PostMapping("/api/alerts/report")
@Operation(summary = "Api for receive default external alarm information")
public ResponseEntity<Message<Void>> receiveDefaultExternAlert(@RequestBody String content) {
log.info("Receive default extern alert content: {}", content);
ExternAlertService externAlertService = externAlertServiceList.stream()
.filter(item -> "default".equals(item.supportSource())).findFirst().orElse(null);
if (externAlertService != null) {
try {
externAlertService.addExternAlert(content);
return ResponseEntity.ok(Message.success("Add extern alert success"));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Message.fail(CommonConstants.FAIL_CODE,
"Add extern alert failed: " + e.getMessage()));
}
}
log.error("Not support default extern alert");
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Message.success("Not support the default source alert"));
}
@PostMapping("/api/v2/alerts")
@Operation(summary = "Api for receive external alarm information")
public ResponseEntity<Message<Void>> receivePrometheusServerAlert(@RequestBody String content) {
log.info("Receive prometheus server alert, content: {}", content);
ExternAlertService externAlertService = externAlertServiceList.stream()
.filter(item -> "prometheus".equals(item.supportSource())).findFirst().orElse(null);
if (externAlertService != null) {
try {
externAlertService.addExternAlert(content);
return ResponseEntity.ok(Message.success("Add extern alert success"));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Message.fail(CommonConstants.FAIL_CODE,
"Add extern alert failed: " + e.getMessage()));
}
}
log.error("Not support prometheus extern alert");
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Message.success("Not support the prometheus source alert"));
}
}
@@ -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.hertzbeat.alert.controller;
import static org.springframework.http.MediaType.TEXT_EVENT_STREAM_VALUE;
import org.apache.hertzbeat.alert.config.AlertSseManager;
import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/**
* SSE controller for alert
*/
@RestController
@RequestMapping(path = "/api/alert/sse", produces = {TEXT_EVENT_STREAM_VALUE})
public class AlertSseController {
private final AlertSseManager emitterManager;
public AlertSseController(AlertSseManager emitterManager) {
this.emitterManager = emitterManager;
}
@GetMapping(path = "/subscribe")
public SseEmitter subscribe() {
Long clientId = SnowFlakeIdGenerator.generateId();
return emitterManager.createEmitter(clientId);
}
}
@@ -25,7 +25,8 @@ import java.util.HashSet;
import java.util.List;
import org.apache.hertzbeat.alert.dto.AlertSummary;
import org.apache.hertzbeat.alert.service.AlertService;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
@@ -50,47 +51,49 @@ public class AlertsController {
private AlertService alertService;
@GetMapping
@Operation(summary = "Get a list of alarm information based on query filter items", description = "according to the query filter items to obtain a list of alarm information")
public ResponseEntity<Message<Page<Alert>>> getAlerts(
@Parameter(description = "Alarm ID List", example = "6565466456") @RequestParam(required = false) List<Long> ids,
@Parameter(description = "Alarm monitor object ID", example = "6565463543") @RequestParam(required = false) Long monitorId,
@Parameter(description = "Alarm level", example = "6565463543") @RequestParam(required = false) Byte priority,
@Parameter(description = "Alarm Status", example = "6565463543") @RequestParam(required = false) Byte status,
@Parameter(description = "Alarm content fuzzy query", example = "linux") @RequestParam(required = false) String content,
@Parameter(description = "Sort field, default id", example = "name") @RequestParam(defaultValue = "id") String sort,
@Operation(summary = "Query Alarms")
public ResponseEntity<Message<Page<SingleAlert>>> getAlerts(
@Parameter(description = "Alarm Status", example = "resolved") @RequestParam(required = false) String status,
@Parameter(description = "Alarm content fuzzy query", example = "linux") @RequestParam(required = false) String search,
@Parameter(description = "Sort field, default id", example = "name") @RequestParam(defaultValue = "gmtUpdate") String sort,
@Parameter(description = "Sort Type", example = "desc") @RequestParam(defaultValue = "desc") String order,
@Parameter(description = "List current page", example = "0") @RequestParam(defaultValue = "0") int pageIndex,
@Parameter(description = "Number of list pagination", example = "8") @RequestParam(defaultValue = "8") int pageSize) {
Page<Alert> alertPage = alertService.getAlerts(ids, monitorId, priority, status, content, sort, order, pageIndex, pageSize);
Page<SingleAlert> alertPage = alertService.getSingleAlerts(status, search, sort, order, pageIndex, pageSize);
return ResponseEntity.ok(Message.success(alertPage));
}
@DeleteMapping
@Operation(summary = "Delete alarms in batches", description = "according to the alarm ID list to delete the alarm information in batches")
@GetMapping("/group")
@Operation(summary = "Query Group Alarms")
public ResponseEntity<Message<Page<GroupAlert>>> getGroupAlerts(
@Parameter(description = "Alarm Status", example = "resolved") @RequestParam(required = false) String status,
@Parameter(description = "Alarm content fuzzy query", example = "linux") @RequestParam(required = false) String search,
@Parameter(description = "Sort field, default id", example = "name") @RequestParam(defaultValue = "gmtUpdate") String sort,
@Parameter(description = "Sort Type", example = "desc") @RequestParam(defaultValue = "desc") String order,
@Parameter(description = "List current page", example = "0") @RequestParam(defaultValue = "0") int pageIndex,
@Parameter(description = "Number of list pagination", example = "8") @RequestParam(defaultValue = "8") int pageSize) {
Page<GroupAlert> alertPage = alertService.getGroupAlerts(status, search, sort, order, pageIndex, pageSize);
return ResponseEntity.ok(Message.success(alertPage));
}
@DeleteMapping("/group")
@Operation(summary = "Delete group alarms in batches", description = "according to the alarm ID list to delete the alarm information in batches")
public ResponseEntity<Message<Void>> deleteAlerts(
@Parameter(description = "Alarm List ID", example = "6565463543") @RequestParam(required = false) List<Long> ids) {
if (ids != null && !ids.isEmpty()) {
alertService.deleteAlerts(new HashSet<>(ids));
alertService.deleteGroupAlerts(new HashSet<>(ids));
}
Message<Void> message = Message.success();
return ResponseEntity.ok(message);
}
@DeleteMapping("/clear")
@Operation(summary = "Delete alarms in batches", description = "delete all alarm information")
public ResponseEntity<Message<Void>> clearAllAlerts() {
alertService.clearAlerts();
Message<Void> message = Message.success();
return ResponseEntity.ok(message);
}
@PutMapping(path = "/status/{status}")
@Operation(summary = "Batch modify alarm status, set read and unread", description = "Batch modify alarm status, set read and unread")
@PutMapping(path = "/group/status/{status}")
@Operation(summary = "Batch modify alarm status, set firing or resolved", description = "Batch modify alarm status, set firing or resolved")
public ResponseEntity<Message<Void>> applyAlertDefinesStatus(
@Parameter(description = "Alarm status value", example = "0") @PathVariable Byte status,
@Parameter(description = "Alarm status value", example = "resolved") @PathVariable String status,
@Parameter(description = "Alarm List IDS", example = "6565463543") @RequestParam(required = false) List<Long> ids) {
if (ids != null && status != null && !ids.isEmpty()) {
alertService.editAlertStatus(status, ids);
alertService.editGroupAlertStatus(status, ids);
}
Message<Void> message = Message.success();
return ResponseEntity.ok(message);
@@ -15,22 +15,23 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.controller;
package org.apache.hertzbeat.alert.controller;
import static org.apache.hertzbeat.common.constants.CommonConstants.FAIL_CODE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Optional;
import javax.validation.Valid;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.manager.NoticeRule;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.manager.service.NoticeConfigService;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeRule;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.alert.service.NoticeConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@@ -82,9 +83,18 @@ public class NoticeConfigController {
@GetMapping(path = "/receivers")
@Operation(summary = "Get a list of message notification recipients based on query filter items",
description = "Get a list of message notification recipients based on query filter items")
public ResponseEntity<Message<List<NoticeReceiver>>> getReceivers(
@Parameter(description = "en: Recipient name,support fuzzy query", example = "tom") @RequestParam(required = false) final String name) {
return ResponseEntity.ok(Message.success(noticeConfigService.getNoticeReceivers(name)));
public ResponseEntity<Message<Page<NoticeReceiver>>> getReceivers(
@Parameter(description = "en: Recipient name,support fuzzy query", example = "tom") @RequestParam(required = false) final String name,
@Parameter(description = "en: List current page", example = "0") @RequestParam(defaultValue = "0") final int pageIndex,
@Parameter(description = "en: Number of list pages", example = "8") @RequestParam(defaultValue = "8") final int pageSize) {
return ResponseEntity.ok(Message.success(noticeConfigService.getNoticeReceivers(name, pageIndex, pageSize)));
}
@GetMapping(path = "/receivers/all")
@Operation(summary = "Get a list of all message notification recipients",
description = "Get a list of all message notification recipients")
public ResponseEntity<Message<List<NoticeReceiver>>> getAllReceivers() {
return ResponseEntity.ok(Message.success(noticeConfigService.getAllNoticeReceivers()));
}
@GetMapping(path = "/receiver/{id}")
@@ -129,9 +139,11 @@ public class NoticeConfigController {
@GetMapping(path = "/rules")
@Operation(summary = "Get a list of message notification policies based on query filter items",
description = "Get a list of message notification policies based on query filter items")
public ResponseEntity<Message<List<NoticeRule>>> getRules(
@Parameter(description = "en: Recipient name", example = "rule1") @RequestParam(required = false) final String name) {
return ResponseEntity.ok(Message.success(noticeConfigService.getNoticeRules(name)));
public ResponseEntity<Message<Page<NoticeRule>>> getRules(
@Parameter(description = "en: Recipient name", example = "rule1") @RequestParam(required = false) final String name,
@Parameter(description = "en: List current page", example = "0") @RequestParam(defaultValue = "0") final int pageIndex,
@Parameter(description = "en: Number of list pages", example = "8") @RequestParam(defaultValue = "8") final int pageSize) {
return ResponseEntity.ok(Message.success(noticeConfigService.getNoticeRules(name, pageIndex, pageSize)));
}
@GetMapping(path = "/rule/{id}")
@@ -176,12 +188,22 @@ public class NoticeConfigController {
@GetMapping(path = "/templates")
@Operation(summary = "Get a list of message notification templates based on query filter items",
description = "Get a list of message notification templates based on query filter items")
public ResponseEntity<Message<List<NoticeTemplate>>> getTemplates(
@Parameter(description = "Template name,support fuzzy query", example = "rule1") @RequestParam(required = false) final String name) {
List<NoticeTemplate> templatePage = noticeConfigService.getNoticeTemplates(name);
public ResponseEntity<Message<Page<NoticeTemplate>>> getTemplates(
@Parameter(description = "Template name,support fuzzy query", example = "rule1") @RequestParam(required = false) final String name,
@Parameter(description = "Whether it is a preset template", example = "true") @RequestParam(defaultValue = "true") final boolean preset,
@Parameter(description = "List current page", example = "0") @RequestParam(defaultValue = "0") final int pageIndex,
@Parameter(description = "Number of list pages", example = "8") @RequestParam(defaultValue = "8") final int pageSize) {
Page<NoticeTemplate> templatePage = noticeConfigService.getNoticeTemplates(name, preset, pageIndex, pageSize);
return ResponseEntity.ok(Message.success(templatePage));
}
@GetMapping(path = "/templates/all")
@Operation(summary = "Get a list of all message notification templates",
description = "Get a list of all message notification templates")
public ResponseEntity<Message<List<NoticeTemplate>>> getAllTemplates() {
return ResponseEntity.ok(Message.success(noticeConfigService.getAllNoticeTemplates()));
}
@GetMapping(path = "/template/{id}")
@Operation(summary = "Get the notification template information based on the template ID",
description = "Get the notification template information based on the template ID")
@@ -17,21 +17,19 @@
package org.apache.hertzbeat.alert.dao;
import java.util.Set;
import org.apache.hertzbeat.common.entity.alerter.AlertConverge;
import org.apache.hertzbeat.common.entity.manager.Collector;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
/**
* AlertConverge Dao
* Alert Collector Dao
*/
public interface AlertConvergeDao extends JpaRepository<AlertConverge, Long>, JpaSpecificationExecutor<AlertConverge> {
public interface AlertCollectorDao extends JpaRepository<Collector, Long>, JpaSpecificationExecutor<Collector> {
/**
* Delete alarm converge based on the ID list
* @param convergeIds alert converge id list
* Query collector by name
* @param name collector name
* @return collector
*/
@Modifying
void deleteAlertConvergesByIdIn(Set<Long> convergeIds);
Collector findCollectorByName(String name);
}
@@ -18,12 +18,11 @@
package org.apache.hertzbeat.alert.dao;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
/**
* AlertDefine Dao
@@ -37,31 +36,16 @@ public interface AlertDefineDao extends JpaRepository<AlertDefine, Long>, JpaSpe
void deleteAlertDefinesByIdIn(Set<Long> alertDefineIds);
/**
* Query the default alarm thresholds based on the monitoring metrics type
* @param app monitoring type
* @param metric metrics
* Query the alarm define by type
* @param type alarm type
* @return alarm defines
*/
List<AlertDefine> queryAlertDefinesByAppAndMetricAndPresetTrueAndEnableTrue(String app, String metric);
List<AlertDefine> findAlertDefinesByTypeAndEnableTrue(String type);
/**
* Query app metric alert define
* @param app app
* @param metric metric
* @return alert define
* Query the alarm define by name
* @param name alarm name
* @return alarm define
*/
List<AlertDefine> queryAlertDefineByAppAndMetric(String app, String metric);
/**
* Query the alarm definition list associated with the monitoring ID
* @param monitorId monitor id
* @param app monitor type
* @param metrics metrics
* @return Alarm Definition List
*/
@Query("select define from AlertDefine define join AlertDefineMonitorBind bind on bind.alertDefineId = define.id "
+ "where bind.monitorId = :monitorId and define.app = :app and define.metric = :metrics and define.enable = true and define.preset = false")
List<AlertDefine> queryAlertDefinesByMonitor(@Param(value = "monitorId") Long monitorId,
@Param(value = "app") String app,
@Param(value = "metrics") String metrics);
Optional<AlertDefine> findAlertDefineByName(String name);
}
@@ -15,36 +15,31 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.dao;
package org.apache.hertzbeat.alert.dao;
import java.util.List;
import java.util.Set;
import org.apache.hertzbeat.common.entity.manager.TagMonitorBind;
import org.apache.hertzbeat.common.entity.alerter.AlertGroupConverge;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
/**
* TagMonitorBindDao repository
* AlertConverge Dao
*/
public interface TagMonitorBindDao extends JpaRepository<TagMonitorBind, Long>, JpaSpecificationExecutor<TagMonitorBind> {
public interface AlertGroupConvergeDao extends JpaRepository<AlertGroupConverge, Long>, JpaSpecificationExecutor<AlertGroupConverge> {
/**
* delete tags bind by monitor id
* @param monitorId monitorId
* Delete group alarm converge based on the ID list
* @param ids alert converge id list
*/
void deleteTagMonitorBindsByMonitorId(Long monitorId);
@Modifying
void deleteAlertGroupConvergesByIdIn(Set<Long> ids);
/**
* delete tags bind by monitor id
* @param monitorIds monitor list
* Query the enable true group alarm converge list
* @return group alarm converge list
*/
void deleteTagMonitorBindsByMonitorIdIn(Set<Long> monitorIds);
/**
* count tags bind relation by tag id
* @param tagIds list of tagId
* @return count
*/
long countByTagIdIn(Set<Long> tagIds);
List<AlertGroupConverge> findAlertGroupConvergesByEnableIsTrue();
}
@@ -0,0 +1,45 @@
/*
* 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.hertzbeat.alert.dao;
import java.util.List;
import java.util.Set;
import org.apache.hertzbeat.common.entity.alerter.AlertInhibit;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
/**
* AlertInhibit Dao
*/
public interface AlertInhibitDao extends JpaRepository<AlertInhibit, Long>, JpaSpecificationExecutor<AlertInhibit> {
/**
* Delete alarm inhibit based on the ID list
*
* @param ids alert inhibit id list
*/
@Modifying
void deleteAlertInhibitsByIdIn(Set<Long> ids);
/**
* Query the enable true alarm inhibit list
* @return alarm inhibit list
*/
List<AlertInhibit> findAlertInhibitsByEnableIsTrue();
}
@@ -18,8 +18,8 @@
package org.apache.hertzbeat.alert.dao;
import java.util.List;
import java.util.Optional;
import org.apache.hertzbeat.common.entity.manager.Monitor;
import org.apache.hertzbeat.common.entity.manager.Tag;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
@@ -36,12 +36,13 @@ public interface AlertMonitorDao extends JpaRepository<Monitor, Long>, JpaSpecif
* @return Monitor the list
*/
List<Monitor> findMonitorsByStatus(Byte status);
/**
* find monitor bind tags by monitorId
* @param monitorId monitorId
* @return bind tags
* Query the monitoring
* @param id id
* @return monitor
*/
@Query("select tag from Tag tag join TagMonitorBind bind on bind.tagId = tag.id where bind.monitorId = :monitorId")
List<Tag> findMonitorIdBindTags(@Param(value = "monitorId") Long monitorId);
@Query("select monitor from Monitor monitor where monitor.id = :id")
Optional<Monitor> findMonitorById(@Param(value = "id") Long id);
}
@@ -17,6 +17,7 @@
package org.apache.hertzbeat.alert.dao;
import java.util.List;
import java.util.Set;
import org.apache.hertzbeat.common.entity.alerter.AlertSilence;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -35,4 +36,10 @@ public interface AlertSilenceDao extends JpaRepository<AlertSilence, Long>, JpaS
*/
@Modifying
void deleteAlertSilencesByIdIn(Set<Long> silenceIds);
/**
* find enabled alert silence
* @return enabled alert silence list
*/
List<AlertSilence> findAlertSilencesByEnableTrue();
}
@@ -17,10 +17,9 @@
package org.apache.hertzbeat.alert.dao;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.hertzbeat.alert.dto.AlertPriorityNum;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
@@ -28,29 +27,37 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
/**
* Alert Database Operations
* Group Alert Database Operations
*/
public interface AlertDao extends JpaRepository<Alert, Long>, JpaSpecificationExecutor<Alert> {
public interface GroupAlertDao extends JpaRepository<GroupAlert, Long>, JpaSpecificationExecutor<GroupAlert> {
/**
* Query alert group by groupKey
* @param groupKey group key identifier
* @return alert group
*/
GroupAlert findByGroupKey(String groupKey);
/**
* Delete alerts based on ID list
* @param alertIds Alert ID List
* @param ids Alert ID List
*/
void deleteAlertsByIdIn(Set<Long> alertIds);
@Modifying
void deleteGroupAlertsByIdIn(HashSet<Long> ids);
/**
* Updates the alarm status based on the alarm ID-status value
* @param status status value
* @param ids alarm ids
* @param ids alarm ids
*/
@Modifying
@Query("update Alert set status = :status where id in :ids")
void updateAlertsStatus(@Param(value = "status") Byte status, @Param(value = "ids") List<Long> ids);
@Query("update GroupAlert set status = :status where id in :ids")
void updateGroupAlertsStatus(@Param(value = "status") String status, @Param(value = "ids") List<Long> ids);
/**
* Query the number of unhandled alarms of each alarm severity
* @return List of alerts num
* find group alerts by id list
* @param ids ids
* @return group alerts
*/
@Query("select new org.apache.hertzbeat.alert.dto.AlertPriorityNum(mo.priority, count(mo.id)) from Alert mo where mo.status = 0 group by mo.priority")
List<AlertPriorityNum> findAlertPriorityNum();
List<GroupAlert> findGroupAlertsByIdIn(HashSet<Long> ids);
}
@@ -15,9 +15,9 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.dao;
package org.apache.hertzbeat.alert.dao;
import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -15,10 +15,10 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.dao;
package org.apache.hertzbeat.alert.dao;
import java.util.List;
import org.apache.hertzbeat.common.entity.manager.NoticeRule;
import org.apache.hertzbeat.common.entity.alerter.NoticeRule;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -15,9 +15,9 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.dao;
package org.apache.hertzbeat.alert.dao;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -0,0 +1,77 @@
/*
* 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.hertzbeat.alert.dao;
import java.util.HashSet;
import java.util.List;
import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
/**
* Single Alert Database Operations
*/
public interface SingleAlertDao extends JpaRepository<SingleAlert, Long>, JpaSpecificationExecutor<SingleAlert> {
/**
* Query alert by fingerprint
* @param fingerprint alert fingerprint
* @return alert
*/
SingleAlert findByFingerprint(String fingerprint);
/**
* Query alerts by fingerprint list
* @param fingerprints alert fingerprint list
* @return alerts
*/
List<SingleAlert> findSingleAlertsByFingerprintIn(List<String> fingerprints);
/**
* Query alerts by status
* @param status status firing or resolved
* @return alerts
*/
List<SingleAlert> querySingleAlertsByStatus(String status);
/**
* Delete alerts based on ID list
* @param ids Alert ID List
*/
@Modifying
void deleteSingleAlertsByIdIn(HashSet<Long> ids);
/**
* Updates the alarm status based on the alarm ID-status value
* @param status status value
* @param ids alarm ids
*/
@Modifying
@Query("update SingleAlert set status = :status where id in :ids")
void updateSingleAlertsStatus(@Param(value = "status") String status, @Param(value = "ids") List<Long> ids);
/**
* delete alerts by fingerprint list
* @param firingAlerts fingerprint list
*/
@Modifying
void deleteSingleAlertsByFingerprintIn(List<String> firingAlerts);
}
@@ -21,9 +21,8 @@ import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelTarget;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
import java.util.Map;
import lombok.Data;
import org.apache.hertzbeat.common.entity.manager.TagItem;
/**
* Data transfer object for alert configuration
@@ -34,26 +33,22 @@ import org.apache.hertzbeat.common.entity.manager.TagItem;
@JsonIgnoreProperties(ignoreUnknown = true)
@ExcelTarget(value = "AlertDefineDTO")
public class AlertDefineDTO {
@Excel(name = "App")
private String app;
@Excel(name = "Metric")
private String metric;
@Excel(name = "Field")
private String field;
@Excel(name = "Preset")
private Boolean preset;
@Excel(name = "Name")
private String name;
@Excel(name = "Type")
private String type;
@Excel(name = "Expr")
private String expr;
@Excel(name = "Priority")
private Byte priority;
@Excel(name = "Period")
private Integer period;
@Excel(name = "Times")
private Integer times;
@Excel(name = "Tags")
private List<TagItem> tags;
@Excel(name = "Enable")
private Boolean enable;
@Excel(name = "RecoverNotice")
private Boolean recoverNotice;
@Excel(name = "Labels")
private Map<String, String> labels;
@Excel(name = "Annotations")
private Map<String, String> annotations;
@Excel(name = "Template")
private String template;
@Excel(name = "Enable")
private Boolean enable;
}
@@ -0,0 +1,51 @@
/*
* 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.hertzbeat.alert.dto;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* AlertManagerExternAlert
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AlertManagerExternAlert {
private String groupKey;
private String externalURL;
private String version;
private String status;
private Map<String, String> groupLabels;
private Map<String, String> commonLabels;
private Map<String, String> commonAnnotations;
private List<PrometheusExternAlert> alerts;
}
@@ -0,0 +1,184 @@
/*
* 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.hertzbeat.alert.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Alibaba Cloud 'Simple Log Service(SLS)' alert content entity.
*
* @see <a href="https://help.aliyun.com/zh/sls/user-guide/variables-in-new-alert-templates"/>
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AlibabaCloudSlsExternAlert {
/**
* The id of the instance on which the alarm was triggered
*/
@JsonProperty("alert_instance_id")
private String alertInstanceId;
/**
* Alarm rule id, unique within project
*/
@JsonProperty("alert_id")
private String alertId;
/**
* Alarm rule name
*/
@JsonProperty("alert_name")
private String alertName;
/**
* Region
*/
private String region;
/**
* Alarm rule belongs to Project
*/
private String project;
/**
* Time of this evaluation
*/
@JsonProperty("alert_time")
private int alertTime;
/**
* First trigger time
*/
@JsonProperty("fire_time")
private int fireTime;
/**
* Alarm recovery time
* If the alarm status is firing, the value is 0.
* If the alarm state is resolved, the value is the specific recovery time.
*/
@JsonProperty("resolve_time")
private int resolveTime;
/**
* Alarm status.
* firing: Triggers an alarm.
* resolved: Notification of resumption.
*/
private String status;
/**
* The total number of entries in the data that triggered the alert,
* which may be more than 100, for example after a Cartesian product operation.
*/
@JsonProperty("fire_results_count")
private int fireResultsCount;
/**
* Tag list
* Example: {"env":"test"}
*/
private Map<String, String> labels;
/**
* Labeled lists
* Example: { "title": "Alarm title","desc": "Alarm desc" }
*/
private Map<String, String> annotations;
/**
* Alarm severity.
*
* 10: Critical
* 8: High
* 6: Medium
* 4: Low
* 2: Report only
*/
private int severity;
/**
*
*/
@JsonProperty("signin_url")
private String signinUrl;
public String getAnnotation(String key) {
if (null == this.annotations || this.annotations.isEmpty()) {
return "N/A";
}
return this.annotations.get(key);
}
/**
* Severity
*/
public enum Severity {
CRITICAL(10, "Critical"),
HIGH(8, "High"),
MEDIUM(6, "Medium"),
LOW(4, "Low"),
REPORT_ONLY(2, "Report only");
private static final Map<Integer, Severity> STATUS_MAP;
static {
STATUS_MAP = Arrays.stream(Severity.values()).collect(Collectors.toMap(Severity::getStatus, t -> t, (oldVal, newVal) -> newVal));
}
private final int status;
private final String alias;
Severity(int status, String alias) {
this.status = status;
this.alias = alias;
}
public static Optional<Severity> convert(int severity) {
return Optional.ofNullable(STATUS_MAP.get(severity));
}
public int getStatus() {
return status;
}
public String getAlias() {
return alias;
}
}
}
@@ -1,78 +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.hertzbeat.alert.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Map;
import org.apache.hertzbeat.common.entity.dto.AlertReport;
/**
* Abstract parent of cloud service alarm information
* {@link AlertReport} - The method corresponds to the parameter of this class one by one. For details about the method, see this class
*/
public abstract class CloudAlertReportAbstract {
/**
* This parameter specifies the alarm name when a cloud alarm is converted to an internal alarm
*/
@JsonIgnore
public abstract String getAlertName();
/**
* Interval when a cloud alarm is converted to an internal alarm
*/
@JsonIgnore
public abstract Integer getAlertDuration();
/**
* Specifies the alarm time when a cloud alarm is converted to an internal alarm
*/
@JsonIgnore
public abstract long getAlertTime();
/**
* Severity of an alarm when a cloud alarm is converted to an internal alarm
*/
@JsonIgnore
public abstract Integer getPriority();
/**
* This parameter specifies the alarm type when a cloud alarm is converted to an internal alarm
*/
@JsonIgnore
public abstract Integer getReportType();
/**
* Alarm label information about a cloud alarm that is converted to an internal alarm
*/
@JsonIgnore
public abstract Map<String, String> getLabels();
/**
* Alarm labels when a cloud alarm is converted to an internal alarm
*/
@JsonIgnore
public abstract Map<String, String> getAnnotations();
/**
* This topic describes the alarm content when a cloud alarm is converted to an internal alarm
*/
@JsonIgnore
public abstract String getContent();
}
@@ -1,79 +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.hertzbeat.alert.dto;
import java.util.Optional;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.alert.util.DateUtil;
import org.apache.hertzbeat.common.entity.dto.AlertReport;
/**
* Generic cloud alarm entity class
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class GeneralCloudAlertReport extends AlertReport {
/**
* Alarm date and time
*/
private String alertDateTime;
/**
* DATE TIME FORMAT
*/
private String dateTimeFormat;
/**
* You can refresh the timestamp of the alarm time with enhanced properties
*/
public void refreshAlertTime() {
if (getAlertTime() != 0L) {
return;
}
if (StringUtils.isNotBlank(alertDateTime)) {
Long timeStamp = null;
if (StringUtils.isNotBlank(dateTimeFormat)) {
Optional<Long> tsf = DateUtil.getTimeStampFromFormat(alertDateTime, dateTimeFormat);
boolean present = tsf.isPresent();
if (present) {
timeStamp = tsf.get();
}
}
if (timeStamp == null) {
Optional<Long> tsf = DateUtil.getTimeStampFromSomeFormats(alertDateTime);
boolean present = tsf.isPresent();
if (present) {
timeStamp = tsf.get();
}
}
if (timeStamp != null) {
setAlertTime(timeStamp);
return;
}
}
throw new RuntimeException("parse alarm time error");
}
}
@@ -0,0 +1,237 @@
/*
* 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.hertzbeat.alert.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Arrays;
/**
* Huawei Cloud (CES) alert content entity.
*
* @see <a href="https://support.huaweicloud.com/usermanual-ces/ces_01_0218.html"/>
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HuaweiCloudExternAlert {
public static final String FIELD_MESSAGE = "message";
public static final String FIELD_MESSAGE_ID = "message_id";
public static final String FIELD_TIMESTAMP = "timestamp";
public static final String FIELD_TOPIC_URN = "topic_urn";
public static final String FIELD_TYPE = "type";
public static final String FIELD_SUBJECT = "subject";
public static final String FIELD_SUBSCRIBE_URL = "subscribe_url";
/**
* Signature information.
*/
private String signature;
/**
* Subject
*/
private String subject;
/**
* The unique identifier of a topic, indicating the topic to which the message belongs.
*/
@JsonProperty("topic_urn")
private String topicUrn;
/**
* Message unique identifier.
*/
@JsonProperty("message_id")
private String messageId;
/**
* Message
*/
private String message;
/**
* message types, the message types are respectively:
* SubscriptionConfirmation、Notification、UnsubscribeConfirmation
*/
private String type;
/**
* Subscription confirms the URL that needs to be accessed
*/
@JsonProperty("subscribe_url")
private String subscribeUrl;
/**
* The certificate URL used for message signing, which does not require authentication and can be accessed directly.
*/
@JsonProperty("signing_cert_url")
private String signingCertUrl;
/**
* The timestamp of when the message was first sent.
*/
private String timestamp;
/**
* Alert message
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class AlertMessage {
private String version;
private AlertData data;
}
/**
* Alert data
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class AlertData {
/**
* Whether an alarm occurs.
* Note: Empty and false are both recovery notifications.
* Note: There are no recovery notifications for event types
*/
@JsonProperty("IsAlarm")
private Boolean alarm;
/**
* Alarm time
*/
@JsonProperty("AlarmTime")
private String alarmTime;
/**
* Resource ID
*/
@JsonProperty("ResourceId")
private String resourceId;
/**
* The name of the metric
*/
@JsonProperty("MetricName")
private String metricName;
/**
* Specifies the alarm severity, which can be Critical, Major, Minor, or Informational.
*/
@JsonProperty("AlarmLevel")
private String alarmLevel;
/**
* Namespace
*/
@JsonProperty("Namespace")
private String namespace;
/**
* Region
*/
@JsonProperty("Region")
private String region;
/**
* Dimension name
*/
@JsonProperty("DimensionName")
private String dimensionName;
/**
* Resource name
*/
@JsonProperty("ResourceName")
private String resourceName;
/**
* Alarm record ID
*/
@JsonProperty("AlarmRecordID")
private String alarmRecordId;
/**
* Current data
*/
@JsonProperty("CurrentData")
private String currentData;
/**
* The comparison conditions for the alarm thresholds can be >, =, <, >=, <=.
*/
@JsonProperty("ComparisonOperator")
private String comparisonOperator;
/**
* Alarm value
*/
@JsonProperty("Value")
private String value;
/**
* Number of consecutive occurrences of triggered alarms
*/
@JsonProperty("Count")
private int count;
}
/**
* Huawei cloud alert type
*/
public enum AlertType {
SUBSCRIPTION("SubscriptionConfirmation"),
UNSUBSCRIBE("UnsubscribeConfirmation"),
NOTIFICATION("Notification");
private final String type;
AlertType(String type) {
this.type = type;
}
public static boolean valid(String type) {
if (null == type || type.isEmpty()) {
return false;
}
return Arrays.stream(AlertType.values()).anyMatch(alertType -> alertType.getType().equals(type));
}
public String getType() {
return type;
}
}
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.pojo.dto;
package org.apache.hertzbeat.alert.dto;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max;
@@ -32,7 +32,7 @@ import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EmailNoticeSender {
public class MailServerConfig {
@NotNull(message = "Type cannot be empty")
private Integer type;
@@ -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.hertzbeat.alert.dto;
import java.time.Instant;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Prometheus Alert Content Entity
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PrometheusExternAlert {
private Map<String, String> labels;
private Map<String, String> annotations;
private String status;
private Instant startsAt;
private Instant endsAt;
private String generatorURL;
}
@@ -0,0 +1,66 @@
/*
* 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.hertzbeat.alert.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* SkyWalking Alert Content Entity
* @see <a href="https://skywalking.apache.org/docs/main/latest/en/setup/backend/backend-alarm/">backend-alarm</a>
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SkyWalkingExternAlert {
private Long scopeId;
private String scope;
private String name;
private String id0;
private String id1;
private String ruleName;
private String alarmMessage;
private Long startTime;
private List<Tag> tags;
/**
* SkyWalking Tag Entity
*/
@Data
public static class Tag {
private String key;
private String value;
}
}
@@ -1,227 +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.hertzbeat.alert.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.apache.hertzbeat.alert.util.DateUtil;
/**
*
* Tencent cloud alarm entity class
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Builder
public class TenCloudAlertReport extends CloudAlertReportAbstract implements Serializable {
@JsonProperty("sessionID")
private String sessionId;
private String alarmStatus;
private String alarmType;
private AlarmObjInfo alarmObjInfo;
private AlarmPolicyInfo alarmPolicyInfo;
private String firstOccurTime;
private int durationTime;
private String recoverTime;
/**
* Alarm Object information
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class AlarmObjInfo {
private String region;
private String namespace;
@JsonProperty("appID")
private String appId;
private String uin;
private Dimensions dimensions;
}
/**
* Uniform Resource ID information
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Dimensions {
@JsonProperty("unInstanceID")
private String unInstanceId;
@JsonProperty("objID")
private String objId;
}
/**
* Alarm policy information
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class AlarmPolicyInfo {
@JsonProperty("policyID")
private String policyId;
private String policyType;
private String policyName;
@JsonProperty("policyTypeCName")
private String policyTypeCname;
private Conditions conditions;
}
/**
* Parameters of indicator alarms
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Conditions {
// alarm metrics parameters
private String metricName;
private String metricShowName;
private String calcType;
private String calcValue;
private String calcUnit;
private String currentValue;
private String historyValue;
private String unit;
private String period;
private String periodNum;
private String alarmNotifyType;
private long alarmNotifyPeriod;
// alarm event parameters
private String productName;
private String productShowName;
private String eventName;
private String eventShowName;
}
@Override
public String getAlertName() {
return "TenCloud|腾讯云";
}
@Override
public Integer getAlertDuration() {
return this.durationTime;
}
@Override
public long getAlertTime() {
return DateUtil.getTimeStampFromFormat(getFirstOccurTime(), "yyyy-MM-dd HH:mm:ss")
.orElse(0L);
}
@Override
public Integer getPriority() {
return 1;
}
@Override
public Integer getReportType() {
return 1;
}
@Override
public Map<String, String> getLabels() {
return Map.of("app", "TenCloud");
}
@Override
public Map<String, String> getAnnotations() {
return Map.of("app", "TenCloud");
}
/**
* Transaction alarm
*/
private static final String EVENT = "event";
/**
* Indicator alarm
*/
private static final String METRIC = "metric";
/**
* If the following alarm types increase, the entity class can be divided into a parent class and multiple subclasses, and then the method can be implemented in the subclass
* Since there are only two, it will not be split for the time being
*/
@Override
public String getContent() {
StringBuilder contentBuilder = new StringBuilder();
// Check Type.
if (EVENT.equals(getAlarmType())) {
contentBuilder
.append("[")
.append("告警状态 | ")
.append("0".equals(alarmStatus) ? "恢复" : "告警")
.append("]\n")
.append("[")
.append("告警对象信息 | ")
.append(getAlarmObjInfo().getRegion() == null ? "" : "region:" + getAlarmObjInfo().getRegion())
.append(";").append("appId:").append(getAlarmObjInfo().getAppId())
.append(";").append("uni:").append(getAlarmObjInfo().getUin())
.append(";").append("unInstanceId:").append(getAlarmObjInfo().getDimensions().getUnInstanceId())
.append("]\n")
.append("[")
.append("告警策略组信息 | ")
.append("名称:").append(getAlarmPolicyInfo().getPolicyName())
.append(";")
.append("策略类型展示名称:").append(getAlarmPolicyInfo().getConditions().getProductName())
.append(",").append(getAlarmPolicyInfo().getConditions().getProductShowName())
.append(";")
.append("事件告警名称:").append(getAlarmPolicyInfo().getConditions().getEventName())
.append(",").append(getAlarmPolicyInfo().getConditions().getEventShowName())
.append("]");
} else if (METRIC.equals(getAlarmType())) {
contentBuilder
.append("[")
.append("告警对象:")
.append(getAlarmObjInfo().getRegion() == null ? "" : getAlarmObjInfo().getRegion())
.append(getAlarmObjInfo().getRegion() == null ? "" : "|")
.append(getAlarmObjInfo().getNamespace())
.append("]")
.append("[")
.append("告警内容:")
.append(getAlarmPolicyInfo().getPolicyTypeCname()).append("|")
.append(getAlarmPolicyInfo().getConditions().getMetricShowName()).append("|")
.append(getAlarmPolicyInfo().getConditions().getMetricName())
.append(getAlarmPolicyInfo().getConditions().getCalcType())
.append(getAlarmPolicyInfo().getConditions().getCalcValue())
.append(getAlarmPolicyInfo().getConditions().getCalcUnit())
.append("]")
.append("[")
.append("当前数据")
.append(getAlarmPolicyInfo().getConditions().getCurrentValue())
.append(getAlarmPolicyInfo().getConditions().getCalcUnit())
.append("]");
}
return contentBuilder.toString();
}
}
@@ -0,0 +1,128 @@
/*
* 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.hertzbeat.alert.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
* Tencent cloud alarm entity class
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TencentCloudExternAlert {
@JsonProperty("sessionID")
private String sessionId;
private String alarmStatus;
private String alarmType;
private AlarmObjInfo alarmObjInfo;
private AlarmPolicyInfo alarmPolicyInfo;
private String firstOccurTime;
private int durationTime;
private String recoverTime;
/**
* Alarm Object information
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class AlarmObjInfo {
private String region;
private String namespace;
@JsonProperty("appID")
private String appId;
private String uin;
private Dimensions dimensions;
}
/**
* Uniform Resource ID information
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Dimensions {
@JsonProperty("unInstanceID")
private String unInstanceId;
@JsonProperty("objID")
private String objId;
}
/**
* Alarm policy information
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class AlarmPolicyInfo {
@JsonProperty("policyID")
private String policyId;
private String policyType;
private String policyName;
@JsonProperty("policyTypeCName")
private String policyTypeCname;
private Conditions conditions;
}
/**
* Parameters of indicator alarms
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Conditions {
// alarm metrics parameters
private String metricName;
private String metricShowName;
private String calcType;
private String calcValue;
private String calcUnit;
private String currentValue;
private String historyValue;
private String unit;
private String period;
private String periodNum;
private String alarmNotifyType;
private long alarmNotifyPeriod;
// alarm event parameters
private String productName;
private String productShowName;
private String eventName;
private String eventShowName;
}
/**
* Transaction alarm
*/
public static final String EVENT = "event";
/**
* Indicator alarm
*/
public static final String METRIC = "metric";
}
@@ -0,0 +1,133 @@
/*
* 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.hertzbeat.alert.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
/**
* uptime-kuma alert content entity
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UptimeKumaExternAlert {
private Heartbeat heartbeat;
private Monitor monitor;
private String msg;
/**
* Monitor information
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Heartbeat {
@JsonProperty("monitorID")
private int monitorId;
private int status;
private String time;
private String msg;
private boolean important;
private int duration;
private String timezone;
private String timezoneOffset;
private String localDateTime;
}
/**
* Monitor information
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Monitor {
private int id;
private String name;
private String description;
private String pathName;
private String parent;
@JsonProperty("childrenIDs")
private List<String> childrenIds;
private String url;
private String method;
private String hostname;
private String port;
@JsonProperty("maxretries")
private int maxRetries;
private int weight;
private boolean active;
private boolean forceInactive;
private String type;
private int timeout;
private int interval;
private int retryInterval;
private int resendInterval;
private String keyword;
private boolean invertKeyword;
private boolean expiryNotification;
private boolean ignoreTls;
private boolean upsideDown;
private int packetSize;
@JsonProperty("maxredirects")
private int maxRedirects;
@JsonProperty("accepted_statuscodes")
private List<String> acceptedStatusCodes;
private String dnsResolveType;
private String dnsResolveServer;
private String dnsLastResult;
private String dockerContainer;
private String dockerHost;
private String proxyId;
private Map<String, Object> notificationIDList;
private List<String> tags;
private boolean maintenance;
private String mqttTopic;
private String mqttSuccessMessage;
private String databaseQuery;
private String authMethod;
private String grpcUrl;
private String grpcProtobuf;
private String grpcMethod;
private String grpcServiceName;
private boolean grpcEnableTls;
private String radiusCalledStationId;
private String radiusCallingStationId;
private String game;
private boolean gamedigGivenPortOnly;
private String httpBodyEncoding;
private String jsonPath;
private String expectedValue;
private String kafkaProducerTopic;
private List<String> kafkaProducerBrokers;
private boolean kafkaProducerSsl;
private boolean kafkaProducerAllowAutoTopicCreation;
private String kafkaProducerMessage;
private String screenshot;
private boolean includeSensitiveData;
}
}
@@ -0,0 +1,121 @@
/*
* 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.hertzbeat.alert.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* volcengine event alert entity class
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class VolcEngineExternEventAlert {
@JsonProperty("Type")
private String type;
@JsonProperty("AccountId")
private String accountId;
@JsonProperty("Source")
private String source;
@JsonProperty("ProjectName")
private String projectName;
@JsonProperty("Id")
private String id;
@JsonProperty("EventType")
private String eventType;
@JsonProperty("DescriptionCN")
private String descriptionCn;
@JsonProperty("HappenedAt")
private Long happenedAt;
@JsonProperty("Region")
private String region;
@JsonProperty("Details")
private EventDetails details;
@JsonProperty("Rules")
private List<EventRule> rules;
/**
* event details
*/
@Data
public static class EventDetails {
@JsonProperty("specversion")
private String specVersion;
@JsonProperty("id")
private String id;
@JsonProperty("source")
private String source;
@JsonProperty("type")
private String type;
@JsonProperty("volcpublishtime")
private String volcPublishTime;
@JsonProperty("volcregion")
private String volcRegion;
@JsonProperty("volcaccountid")
private String volcAccountId;
@JsonProperty("volceventbusname")
private String volcEventBusName;
@JsonProperty("volcresourcename")
private String volcResourceName;
@JsonProperty("subject")
private String subject;
@JsonProperty("time")
private String time;
}
/**
* event rule
*/
@Data
public static class EventRule {
@JsonProperty("RuleId")
private String ruleId;
@JsonProperty("RuleName")
private String ruleName;
@JsonProperty("Level")
private String level;
}
}
@@ -0,0 +1,203 @@
/*
* 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.hertzbeat.alert.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* Volcengine alarm entity class
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class VolcEngineExternMetricAlert {
@JsonProperty("Type")
private String type;
@JsonProperty("AccountId")
private String accountId;
@JsonProperty("RuleName")
private String ruleName;
@JsonProperty("RuleId")
private String ruleId;
@JsonProperty("Namespace")
private String namespace;
@JsonProperty("SubNamespace")
private String subNamespace;
@JsonProperty("Level")
private String level;
@JsonProperty("HappenedAt")
private String happenedAt;
@JsonProperty("RuleCondition")
private String ruleCondition;
@JsonProperty("Resources")
private List<Resource> resources;
@JsonProperty("RecoveredResources")
private List<Resource> recoveredResources;
@JsonProperty("NoDataResources")
private List<NoDataResource> noDataResources;
@JsonProperty("NoDataRecoveredResources")
private List<NoDataRecoveredResource> noDataRecoveredResources;
/**
* alert resource entity class
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Resource {
@JsonProperty("Id")
private String id;
@JsonProperty("Name")
private String name;
@JsonProperty("Region")
private String region;
@JsonProperty("FirstAlertTime")
private Long firstAlertTime;
@JsonProperty("LastAlertTime")
private Long lastAlertTime;
@JsonProperty("Metrics")
private List<Metric> metrics;
@JsonProperty("AlertGroupId")
private String alertGroupId;
@JsonProperty("Dimensions")
private List<Dimension> dimensions;
}
/**
* alert no data resource entity class
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public static class NoDataResource extends Resource {
@JsonProperty("NoDataMetrics")
private List<Metric> noDataMetrics;
}
/**
* alert no data recovered resource entity class
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public static class NoDataRecoveredResource extends Resource {
@JsonProperty("DroppedMetrics")
private List<DroppedMetric> droppedMetrics;
}
/**
* alert metric entity class
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Metric {
@JsonProperty("Name")
private String name;
@JsonProperty("Unit")
private String unit;
@JsonProperty("Threshold")
private Double threshold;
@JsonProperty("CurrentValue")
private Object currentValue;
@JsonProperty("Description")
private String description;
@JsonProperty("Warning")
private Boolean warning;
}
/**
* alert dropped metric entity class
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public static class DroppedMetric extends Metric {
@JsonProperty("Reason")
private String reason;
}
/**
* resource dimension entity class
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Dimension {
@JsonProperty("Name")
private String name;
@JsonProperty("NameCN")
private String nameCn;
@JsonProperty("Value")
private String value;
@JsonProperty("Description")
private String description;
}
public static final String ALERT_TYPE_METRIC = "Metric";
public static final String ALERT_TYPE_EVENT = "Event";
public static final String ALERT_TYPE_METRIC_RECOVERED = "MetricRecovered";
public static final String ALERT_TYPE_METRICS_NODATA = "MetricsNoData";
public static final String ALERT_TYPE_NO_DATA_RECOVERED = "NoDataRecovered";
}
@@ -1,52 +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.hertzbeat.alert.enums;
import java.util.Arrays;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.hertzbeat.alert.dto.CloudAlertReportAbstract;
import org.apache.hertzbeat.alert.dto.TenCloudAlertReport;
/**
* Cloud server alarm enum
*/
@AllArgsConstructor
@Getter
public enum CloudServiceAlarmInformationEnum {
TencentCloud("tencloud", TenCloudAlertReport.class);
/**
* cloud service name
*/
private final String cloudServiceName;
/**
* cloud service body
*/
private final Class<? extends CloudAlertReportAbstract> cloudServiceAlarmInformationEntity;
public static CloudServiceAlarmInformationEnum getEnumFromCloudServiceName(String name) {
return Arrays.stream(CloudServiceAlarmInformationEnum.values())
.filter(cloudService -> cloudService.cloudServiceName.equals(name))
.findFirst()
.orElse(null);
}
}
@@ -0,0 +1,353 @@
/*
* 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.
*/
// Generated from AlertExpression.g4 by ANTLR 4.13.2
package org.apache.hertzbeat.alert.expr;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
/**
* This class provides an empty implementation of {@link AlertExpressionVisitor},
* which can be extended to create a visitor which only needs to handle a subset
* of the available methods.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
@SuppressWarnings("CheckReturnValue")
public class AlertExpressionBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements AlertExpressionVisitor<T> {
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExpression(AlertExpressionParser.ExpressionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAndExpr(AlertExpressionParser.AndExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitComparisonExpr(AlertExpressionParser.ComparisonExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitUnlessExpr(AlertExpressionParser.UnlessExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSqlExpr(AlertExpressionParser.SqlExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSqlCallExpr(AlertExpressionParser.SqlCallExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitLiteralExpr(AlertExpressionParser.LiteralExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParenExpr(AlertExpressionParser.ParenExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPromqlCallExpr(AlertExpressionParser.PromqlCallExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPromqlExpr(AlertExpressionParser.PromqlExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitOrExpr(AlertExpressionParser.OrExprContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFunctionCall(AlertExpressionParser.FunctionCallContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParameterList(AlertExpressionParser.ParameterListContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitParameter(AlertExpressionParser.ParameterContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitNumber(AlertExpressionParser.NumberContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitString(AlertExpressionParser.StringContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDuration(AlertExpressionParser.DurationContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFunctionName(AlertExpressionParser.FunctionNameContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSelectSql(AlertExpressionParser.SelectSqlContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSelectFieldList(AlertExpressionParser.SelectFieldListContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSelectField(AlertExpressionParser.SelectFieldContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitGroupByList(AlertExpressionParser.GroupByListContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitOrderByList(AlertExpressionParser.OrderByListContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitOrderByField(AlertExpressionParser.OrderByFieldContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitLimitClause(AlertExpressionParser.LimitClauseContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitRelList(AlertExpressionParser.RelListContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitRelation(AlertExpressionParser.RelationContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitConditionList(AlertExpressionParser.ConditionListContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitCompOp(AlertExpressionParser.CompOpContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitCondition(AlertExpressionParser.ConditionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitConditionUnit(AlertExpressionParser.ConditionUnitContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPromql(AlertExpressionParser.PromqlContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitMetricSelector(AlertExpressionParser.MetricSelectorContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitLabelMatcherList(AlertExpressionParser.LabelMatcherListContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitLabelMatcherItem(AlertExpressionParser.LabelMatcherItemContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitLabelMatcherOp(AlertExpressionParser.LabelMatcherOpContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitLabelList(AlertExpressionParser.LabelListContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitInstantVectorOp(AlertExpressionParser.InstantVectorOpContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAggregationOperator(AlertExpressionParser.AggregationOperatorContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitBinaryOperator(AlertExpressionParser.BinaryOperatorContext ctx) { return visitChildren(ctx); }
}
@@ -0,0 +1,293 @@
/*
* 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.hertzbeat.alert.expr;
import org.antlr.v4.runtime.CommonTokenStream;
import org.apache.hertzbeat.warehouse.db.QueryExecutor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Alert expression visitor implement
*/
public class AlertExpressionEvalVisitor extends AlertExpressionBaseVisitor<List<Map<String, Object>>> {
private static final String THRESHOLD = "__threshold__";
private static final String NAME = "__name__";
private static final String VALUE = "__value__";
private static final String TIMESTAMP = "__timestamp__";
private final QueryExecutor executor;
private final CommonTokenStream tokens;
public AlertExpressionEvalVisitor(QueryExecutor executor, CommonTokenStream tokens) {
this.executor = executor;
this.tokens = tokens;
}
@Override
public List<Map<String, Object>> visitExpression(AlertExpressionParser.ExpressionContext ctx) {
return visit(ctx.expr());
}
@Override
public List<Map<String, Object>> visitParenExpr(AlertExpressionParser.ParenExprContext ctx) {
return visit(ctx.expr());
}
@Override
public List<Map<String, Object>> visitComparisonExpr(AlertExpressionParser.ComparisonExprContext ctx) {
List<Map<String, Object>> leftResult = visit(ctx.left);
List<Map<String, Object>> rightResult = visit(ctx.right);
if (rightResult.size() == 1 && rightResult.get(0).containsKey(THRESHOLD)) {
double threshold = (double) rightResult.get(0).get(THRESHOLD);
String operator = ctx.op.getText();
List<Map<String, Object>> result = new ArrayList<>();
for (Map<String, Object> item : leftResult) {
Object queryValues = item.get(VALUE);
if (queryValues == null) {
// ignore the query result data is empty
continue;
}
// queryValues may be a list of values, or a single value
Object matchValue = evaluateCondition(queryValues, operator, threshold);
Map<String, Object> resultMap = new HashMap(item);
resultMap.put(VALUE, matchValue);
// if matchValue is null, mean not match the threshold
// if not null, mean match the threshold
result.add(resultMap);
}
return result;
}
return new LinkedList<>();
}
@Override
public List<Map<String, Object>> visitAndExpr(AlertExpressionParser.AndExprContext ctx) {
List<Map<String, Object>> leftOperand = visit(ctx.left);
List<Map<String, Object>> rightOperand = visit(ctx.right);
List<Map<String, Object>> results = new ArrayList<>();
// build a hash set of the right-side tag collection
Set<String> rightLabelsSet = rightOperand.stream()
.filter(item -> item.get(VALUE) != null)
.map(this::labelKey)
.collect(Collectors.toSet());
// iterate over the left side, O(1) match
for (Map<String, Object> leftItem : leftOperand) {
Object leftVal = leftItem.get(VALUE);
if (leftVal == null) {
continue;
}
String labelKey = labelKey(leftItem);
if (rightLabelsSet.contains(labelKey)) {
results.add(new HashMap<>(leftItem));
}
}
return results;
}
@Override
public List<Map<String, Object>> visitOrExpr(AlertExpressionParser.OrExprContext ctx) {
List<Map<String, Object>> leftOperand = visit(ctx.left);
List<Map<String, Object>> rightOperand = visit(ctx.right);
// build a hashMap of the left-hand label collection
Map<String, Map<String, Object>> leftLabelMap = leftOperand.stream()
.filter(item -> item.get(VALUE) != null)
.collect(Collectors.toMap(this::labelKey, HashMap::new, (k1, k2) -> k1));
// first add all the non-empty items on the left side
List<Map<String, Object>> results = new ArrayList<>(leftLabelMap.values());
// add the term that has a value on the right side and not on the left side
for (Map<String, Object> rightItem : rightOperand) {
Object rightVal = rightItem.get(VALUE);
if (rightVal == null) {
continue;
}
String key = labelKey(rightItem);
if (!leftLabelMap.containsKey(key)) {
results.add(new HashMap<>(rightItem));
}
}
return results;
}
@Override
public List<Map<String, Object>> visitUnlessExpr(AlertExpressionParser.UnlessExprContext ctx) {
List<Map<String, Object>> leftOperand = visit(ctx.left);
List<Map<String, Object>> rightOperand = visit(ctx.right);
List<Map<String, Object>> results = new ArrayList<>();
// build a hash set of the right-side tag collection
Set<String> rightLabelSet = rightOperand.stream()
.filter(item -> item.get(VALUE) != null)
.map(this::labelKey)
.collect(Collectors.toSet());
// iterate over the left side, O(1) match
for (Map<String, Object> leftItem : leftOperand) {
Object leftVal = leftItem.get(VALUE);
if (leftVal == null) {
continue;
}
if (!rightLabelSet.contains(labelKey(leftItem))) {
results.add(new HashMap<>(leftItem));
}
}
return results;
}
@Override
public List<Map<String, Object>> visitLiteralExpr(AlertExpressionParser.LiteralExprContext ctx) {
double value = Double.parseDouble(ctx.number().getText());
List<Map<String, Object>> numAsList = new ArrayList<>();
Map<String, Object> valueMap = new HashMap<>();
valueMap.put(THRESHOLD, value);
numAsList.add(valueMap);
return numAsList;
}
@Override
public List<Map<String, Object>> visitPromqlExpr(AlertExpressionParser.PromqlExprContext ctx) {
String rawPromql = tokens.getText(ctx.promql());
return executor.execute(rawPromql);
}
@Override
public List<Map<String, Object>> visitSqlExpr(AlertExpressionParser.SqlExprContext ctx) {
String rawSql = tokens.getText(ctx.selectSql());
return executor.execute(rawSql);
}
@Override
public List<Map<String, Object>> visitSqlCallExpr(AlertExpressionParser.SqlCallExprContext ctx) {
return callSqlOrPromql(tokens.getText(ctx.string()));
}
@Override
public List<Map<String, Object>> visitPromqlCallExpr(AlertExpressionParser.PromqlCallExprContext ctx) {
return callSqlOrPromql(tokens.getText(ctx.string()));
}
private Object evaluateCondition(Object value, String operator, Double threshold) {
// value may be a list of values, or a single value
switch (operator) {
case ">":
// if value is list, return the max value
if (value instanceof List<?> values) {
Double doubleValue = values.stream().map(v -> Double.valueOf(v.toString())).max(Double::compareTo).orElse(null);
if (doubleValue != null) {
return doubleValue > threshold ? doubleValue : null;
} else {
return null;
}
} else {
return Double.parseDouble(value.toString()) > threshold ? value : null;
}
case ">=":
if (value instanceof List<?> values) {
Double doubleValue = values.stream().map(v -> Double.valueOf(v.toString())).max(Double::compareTo).orElse(null);
if (doubleValue != null) {
return doubleValue >= threshold ? doubleValue : null;
} else {
return null;
}
} else {
return Double.parseDouble(value.toString()) >= threshold ? value : null;
}
case "<":
if (value instanceof List<?> values) {
Double doubleValue = values.stream().map(v -> Double.valueOf(v.toString())).min(Double::compareTo).orElse(null);
if (doubleValue != null) {
return doubleValue < threshold ? doubleValue : null;
} else {
return null;
}
} else {
return Double.parseDouble(value.toString()) < threshold ? value : null;
}
case "<=":
if (value instanceof List<?> values) {
Double doubleValue = values.stream().map(v -> Double.valueOf(v.toString())).min(Double::compareTo).orElse(null);
if (doubleValue != null) {
return doubleValue <= threshold ? doubleValue : null;
} else {
return null;
}
} else {
return Double.parseDouble(value.toString()) <= threshold ? value : null;
}
case "==":
if (value instanceof List<?> values) {
for (Object v : values) {
if (v.equals(threshold)) {
return v;
}
}
return null;
} else {
return value.equals(threshold) ? value : null;
}
case "!=":
if (value instanceof List<?> values) {
for (Object v : values) {
if (v.equals(threshold)) {
return null;
}
}
return value;
} else {
return value.equals(threshold) ? null : value;
}
default:
// unsupported operator todo add more operator
return null;
}
}
private List<Map<String, Object>> callSqlOrPromql(String text){
String script = text.substring(1, text.length() - 1);
return executor.execute(script);
}
/**
* Generate tag key (excluding `__name__` and `__value__` and `__timestamp__`)
*/
private String labelKey(Map<String, Object> labelsMap) {
if (null == labelsMap || labelsMap.isEmpty()) {
return "-";
}
String key = labelsMap.entrySet().stream()
.filter(e -> !e.getKey().equals(VALUE) && !e.getKey().equals(NAME) && !e.getKey().equals(TIMESTAMP))
.sorted(Map.Entry.comparingByKey())
.map(e -> e.getKey() + "=" + (e.getValue() == null ? "" : e.getValue()))
.collect(Collectors.joining(","));
return key.isEmpty() ? "-" : key;
}
}
@@ -0,0 +1,523 @@
/*
* 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.
*/
// Generated from AlertExpression.g4 by ANTLR 4.13.2
package org.apache.hertzbeat.alert.expr;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.RuntimeMetaData;
import org.antlr.v4.runtime.Vocabulary;
import org.antlr.v4.runtime.VocabularyImpl;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.ATNDeserializer;
import org.antlr.v4.runtime.atn.LexerATNSimulator;
import org.antlr.v4.runtime.atn.PredictionContextCache;
import org.antlr.v4.runtime.dfa.DFA;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"})
public class AlertExpressionLexer extends Lexer {
static { RuntimeMetaData.checkVersion("4.13.2", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
public static final int
AND=1, OR=2, UNLESS=3, NOT=4, SELECT=5, FROM=6, WHERE=7, GROUP=8, BY=9,
HAVING=10, ORDER=11, LIMIT=12, OFFSET=13, AS=14, ASC=15, DESC=16, IN=17,
IS=18, NULL=19, LIKE=20, BETWEEN=21, STAR=22, COUNT=23, SUM=24, AVG=25,
MIN=26, MAX=27, STDDEV=28, STDVAR=29, VARIANCE=30, RATE_FUNCTION=31, INCREASE_FUNCTION=32,
HISTOGRAM_QUANTILE_FUNCTION=33, TOPK=34, BOTTOMK=35, QUANTILE=36, BY_FUNCTION=37,
WITHOUT_FUNCTION=38, GROUP_LEFT_FUNCTION=39, GROUP_RIGHT_FUNCTION=40,
IGNORING_FUNCTION=41, ON_FUNCTION=42, SQL_FUNCTION=43, PROMQL_FUNCTION=44,
GT=45, GE=46, LT=47, LE=48, EQ=49, NE=50, LPAREN=51, RPAREN=52, LBRACE=53,
RBRACE=54, LBRACKET=55, RBRACKET=56, COMMA=57, DOT=58, COLON=59, SEMICOLON=60,
SCIENTIFIC_NUMBER=61, FLOAT=62, NUMBER=63, DURATION=64, STRING=65, IDENTIFIER=66,
WS=67, LINE_COMMENT=68, BLOCK_COMMENT=69;
public static String[] channelNames = {
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
};
public static String[] modeNames = {
"DEFAULT_MODE"
};
private static String[] makeRuleNames() {
return new String[] {
"AND", "OR", "UNLESS", "NOT", "SELECT", "FROM", "WHERE", "GROUP", "BY",
"HAVING", "ORDER", "LIMIT", "OFFSET", "AS", "ASC", "DESC", "IN", "IS",
"NULL", "LIKE", "BETWEEN", "STAR", "COUNT", "SUM", "AVG", "MIN", "MAX",
"STDDEV", "STDVAR", "VARIANCE", "RATE_FUNCTION", "INCREASE_FUNCTION",
"HISTOGRAM_QUANTILE_FUNCTION", "TOPK", "BOTTOMK", "QUANTILE", "BY_FUNCTION",
"WITHOUT_FUNCTION", "GROUP_LEFT_FUNCTION", "GROUP_RIGHT_FUNCTION", "IGNORING_FUNCTION",
"ON_FUNCTION", "SQL_FUNCTION", "PROMQL_FUNCTION", "GT", "GE", "LT", "LE",
"EQ", "NE", "LPAREN", "RPAREN", "LBRACE", "RBRACE", "LBRACKET", "RBRACKET",
"COMMA", "DOT", "COLON", "SEMICOLON", "SCIENTIFIC_NUMBER", "FLOAT", "NUMBER",
"DURATION", "STRING", "IDENTIFIER", "WS", "LINE_COMMENT", "BLOCK_COMMENT"
};
}
public static final String[] ruleNames = makeRuleNames();
private static String[] makeLiteralNames() {
return new String[] {
null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, "'*'", null,
null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, "'>'", "'>='",
"'<'", "'<='", null, "'!='", "'('", "')'", "'{'", "'}'", "'['", "']'",
"','", "'.'", "':'", "';'"
};
}
private static final String[] _LITERAL_NAMES = makeLiteralNames();
private static String[] makeSymbolicNames() {
return new String[] {
null, "AND", "OR", "UNLESS", "NOT", "SELECT", "FROM", "WHERE", "GROUP",
"BY", "HAVING", "ORDER", "LIMIT", "OFFSET", "AS", "ASC", "DESC", "IN",
"IS", "NULL", "LIKE", "BETWEEN", "STAR", "COUNT", "SUM", "AVG", "MIN",
"MAX", "STDDEV", "STDVAR", "VARIANCE", "RATE_FUNCTION", "INCREASE_FUNCTION",
"HISTOGRAM_QUANTILE_FUNCTION", "TOPK", "BOTTOMK", "QUANTILE", "BY_FUNCTION",
"WITHOUT_FUNCTION", "GROUP_LEFT_FUNCTION", "GROUP_RIGHT_FUNCTION", "IGNORING_FUNCTION",
"ON_FUNCTION", "SQL_FUNCTION", "PROMQL_FUNCTION", "GT", "GE", "LT", "LE",
"EQ", "NE", "LPAREN", "RPAREN", "LBRACE", "RBRACE", "LBRACKET", "RBRACKET",
"COMMA", "DOT", "COLON", "SEMICOLON", "SCIENTIFIC_NUMBER", "FLOAT", "NUMBER",
"DURATION", "STRING", "IDENTIFIER", "WS", "LINE_COMMENT", "BLOCK_COMMENT"
};
}
private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
@Deprecated
public static final String[] tokenNames;
static {
tokenNames = new String[_SYMBOLIC_NAMES.length];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = VOCABULARY.getLiteralName(i);
if (tokenNames[i] == null) {
tokenNames[i] = VOCABULARY.getSymbolicName(i);
}
if (tokenNames[i] == null) {
tokenNames[i] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
public AlertExpressionLexer(CharStream input) {
super(input);
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}
@Override
public String getGrammarFileName() { return "AlertExpression.g4"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@Override
public String[] getChannelNames() { return channelNames; }
@Override
public String[] getModeNames() { return modeNames; }
@Override
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
"\u0004\u0000E\u0228\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+
"\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+
"\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+
"\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+
"\u0007\u000b\u0002\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002"+
"\u000f\u0007\u000f\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002"+
"\u0012\u0007\u0012\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002"+
"\u0015\u0007\u0015\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002"+
"\u0018\u0007\u0018\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002"+
"\u001b\u0007\u001b\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002"+
"\u001e\u0007\u001e\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007"+
"!\u0002\"\u0007\"\u0002#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007"+
"&\u0002\'\u0007\'\u0002(\u0007(\u0002)\u0007)\u0002*\u0007*\u0002+\u0007"+
"+\u0002,\u0007,\u0002-\u0007-\u0002.\u0007.\u0002/\u0007/\u00020\u0007"+
"0\u00021\u00071\u00022\u00072\u00023\u00073\u00024\u00074\u00025\u0007"+
"5\u00026\u00076\u00027\u00077\u00028\u00078\u00029\u00079\u0002:\u0007"+
":\u0002;\u0007;\u0002<\u0007<\u0002=\u0007=\u0002>\u0007>\u0002?\u0007"+
"?\u0002@\u0007@\u0002A\u0007A\u0002B\u0007B\u0002C\u0007C\u0002D\u0007"+
"D\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001"+
"\u0001\u0001\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002"+
"\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+
"\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004"+
"\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+
"\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006"+
"\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+
"\u0001\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001"+
"\t\u0001\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\u000b"+
"\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001"+
"\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0001"+
"\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001"+
"\u000f\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+
"\u0011\u0001\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+
"\u0012\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+
"\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001"+
"\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0016\u0001"+
"\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001"+
"\u0017\u0001\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001"+
"\u0018\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u001a\u0001"+
"\u001a\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001"+
"\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001"+
"\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001d\u0001"+
"\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001"+
"\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001"+
"\u001e\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001"+
"\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001 \u0001"+
" \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001"+
" \u0001 \u0001 \u0001 \u0001 \u0001 \u0001!\u0001!\u0001!\u0001!\u0001"+
"!\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001"+
"#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001$\u0001"+
"$\u0001$\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001%\u0001"+
"&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001"+
"&\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001"+
"\'\u0001\'\u0001\'\u0001\'\u0001(\u0001(\u0001(\u0001(\u0001(\u0001(\u0001"+
"(\u0001(\u0001(\u0001)\u0001)\u0001)\u0001*\u0001*\u0001*\u0001*\u0001"+
"+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001+\u0001,\u0001,\u0001-\u0001"+
"-\u0001-\u0001.\u0001.\u0001/\u0001/\u0001/\u00010\u00010\u00010\u0003"+
"0\u01a3\b0\u00011\u00011\u00011\u00012\u00012\u00013\u00013\u00014\u0001"+
"4\u00015\u00015\u00016\u00016\u00017\u00017\u00018\u00018\u00019\u0001"+
"9\u0001:\u0001:\u0001;\u0001;\u0001<\u0004<\u01bd\b<\u000b<\f<\u01be\u0001"+
"<\u0001<\u0004<\u01c3\b<\u000b<\f<\u01c4\u0003<\u01c7\b<\u0001<\u0001"+
"<\u0003<\u01cb\b<\u0001<\u0004<\u01ce\b<\u000b<\f<\u01cf\u0001=\u0004"+
"=\u01d3\b=\u000b=\f=\u01d4\u0001=\u0001=\u0004=\u01d9\b=\u000b=\f=\u01da"+
"\u0001>\u0004>\u01de\b>\u000b>\f>\u01df\u0001?\u0004?\u01e3\b?\u000b?"+
"\f?\u01e4\u0001?\u0004?\u01e8\b?\u000b?\f?\u01e9\u0001@\u0001@\u0001@"+
"\u0001@\u0005@\u01f0\b@\n@\f@\u01f3\t@\u0001@\u0001@\u0001@\u0001@\u0001"+
"@\u0005@\u01fa\b@\n@\f@\u01fd\t@\u0001@\u0003@\u0200\b@\u0001A\u0001A"+
"\u0005A\u0204\bA\nA\fA\u0207\tA\u0001B\u0004B\u020a\bB\u000bB\fB\u020b"+
"\u0001B\u0001B\u0001C\u0001C\u0001C\u0001C\u0005C\u0214\bC\nC\fC\u0217"+
"\tC\u0001C\u0001C\u0001D\u0001D\u0001D\u0001D\u0005D\u021f\bD\nD\fD\u0222"+
"\tD\u0001D\u0001D\u0001D\u0001D\u0001D\u0001\u0220\u0000E\u0001\u0001"+
"\u0003\u0002\u0005\u0003\u0007\u0004\t\u0005\u000b\u0006\r\u0007\u000f"+
"\b\u0011\t\u0013\n\u0015\u000b\u0017\f\u0019\r\u001b\u000e\u001d\u000f"+
"\u001f\u0010!\u0011#\u0012%\u0013\'\u0014)\u0015+\u0016-\u0017/\u0018"+
"1\u00193\u001a5\u001b7\u001c9\u001d;\u001e=\u001f? A!C\"E#G$I%K&M\'O("+
"Q)S*U+W,Y-[.]/_0a1c2e3g4i5k6m7o8q9s:u;w<y={>}?\u007f@\u0081A\u0083B\u0085"+
"C\u0087D\u0089E\u0001\u0000!\u0002\u0000AAaa\u0002\u0000NNnn\u0002\u0000"+
"DDdd\u0002\u0000OOoo\u0002\u0000RRrr\u0002\u0000UUuu\u0002\u0000LLll\u0002"+
"\u0000EEee\u0002\u0000SSss\u0002\u0000TTtt\u0002\u0000CCcc\u0002\u0000"+
"FFff\u0002\u0000MMmm\u0002\u0000WWww\u0002\u0000HHhh\u0002\u0000GGgg\u0002"+
"\u0000PPpp\u0002\u0000BBbb\u0002\u0000YYyy\u0002\u0000VVvv\u0002\u0000"+
"IIii\u0002\u0000KKkk\u0002\u0000XXxx\u0002\u0000QQqq\u0001\u000009\u0002"+
"\u0000++--\u0002\u0000AZaz\u0004\u0000\n\n\r\r\"\"\\\\\u0004\u0000\n\n"+
"\r\r\'\'\\\\\u0003\u0000AZ__az\n\u0000\"\"-.09==A[]]__a{}~\u8000\uff5e"+
"\u8000\uff5e\u0003\u0000\t\n\r\r \u0002\u0000\n\n\r\r\u023b\u0000\u0001"+
"\u0001\u0000\u0000\u0000\u0000\u0003\u0001\u0000\u0000\u0000\u0000\u0005"+
"\u0001\u0000\u0000\u0000\u0000\u0007\u0001\u0000\u0000\u0000\u0000\t\u0001"+
"\u0000\u0000\u0000\u0000\u000b\u0001\u0000\u0000\u0000\u0000\r\u0001\u0000"+
"\u0000\u0000\u0000\u000f\u0001\u0000\u0000\u0000\u0000\u0011\u0001\u0000"+
"\u0000\u0000\u0000\u0013\u0001\u0000\u0000\u0000\u0000\u0015\u0001\u0000"+
"\u0000\u0000\u0000\u0017\u0001\u0000\u0000\u0000\u0000\u0019\u0001\u0000"+
"\u0000\u0000\u0000\u001b\u0001\u0000\u0000\u0000\u0000\u001d\u0001\u0000"+
"\u0000\u0000\u0000\u001f\u0001\u0000\u0000\u0000\u0000!\u0001\u0000\u0000"+
"\u0000\u0000#\u0001\u0000\u0000\u0000\u0000%\u0001\u0000\u0000\u0000\u0000"+
"\'\u0001\u0000\u0000\u0000\u0000)\u0001\u0000\u0000\u0000\u0000+\u0001"+
"\u0000\u0000\u0000\u0000-\u0001\u0000\u0000\u0000\u0000/\u0001\u0000\u0000"+
"\u0000\u00001\u0001\u0000\u0000\u0000\u00003\u0001\u0000\u0000\u0000\u0000"+
"5\u0001\u0000\u0000\u0000\u00007\u0001\u0000\u0000\u0000\u00009\u0001"+
"\u0000\u0000\u0000\u0000;\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000"+
"\u0000\u0000?\u0001\u0000\u0000\u0000\u0000A\u0001\u0000\u0000\u0000\u0000"+
"C\u0001\u0000\u0000\u0000\u0000E\u0001\u0000\u0000\u0000\u0000G\u0001"+
"\u0000\u0000\u0000\u0000I\u0001\u0000\u0000\u0000\u0000K\u0001\u0000\u0000"+
"\u0000\u0000M\u0001\u0000\u0000\u0000\u0000O\u0001\u0000\u0000\u0000\u0000"+
"Q\u0001\u0000\u0000\u0000\u0000S\u0001\u0000\u0000\u0000\u0000U\u0001"+
"\u0000\u0000\u0000\u0000W\u0001\u0000\u0000\u0000\u0000Y\u0001\u0000\u0000"+
"\u0000\u0000[\u0001\u0000\u0000\u0000\u0000]\u0001\u0000\u0000\u0000\u0000"+
"_\u0001\u0000\u0000\u0000\u0000a\u0001\u0000\u0000\u0000\u0000c\u0001"+
"\u0000\u0000\u0000\u0000e\u0001\u0000\u0000\u0000\u0000g\u0001\u0000\u0000"+
"\u0000\u0000i\u0001\u0000\u0000\u0000\u0000k\u0001\u0000\u0000\u0000\u0000"+
"m\u0001\u0000\u0000\u0000\u0000o\u0001\u0000\u0000\u0000\u0000q\u0001"+
"\u0000\u0000\u0000\u0000s\u0001\u0000\u0000\u0000\u0000u\u0001\u0000\u0000"+
"\u0000\u0000w\u0001\u0000\u0000\u0000\u0000y\u0001\u0000\u0000\u0000\u0000"+
"{\u0001\u0000\u0000\u0000\u0000}\u0001\u0000\u0000\u0000\u0000\u007f\u0001"+
"\u0000\u0000\u0000\u0000\u0081\u0001\u0000\u0000\u0000\u0000\u0083\u0001"+
"\u0000\u0000\u0000\u0000\u0085\u0001\u0000\u0000\u0000\u0000\u0087\u0001"+
"\u0000\u0000\u0000\u0000\u0089\u0001\u0000\u0000\u0000\u0001\u008b\u0001"+
"\u0000\u0000\u0000\u0003\u008f\u0001\u0000\u0000\u0000\u0005\u0092\u0001"+
"\u0000\u0000\u0000\u0007\u0099\u0001\u0000\u0000\u0000\t\u009d\u0001\u0000"+
"\u0000\u0000\u000b\u00a4\u0001\u0000\u0000\u0000\r\u00a9\u0001\u0000\u0000"+
"\u0000\u000f\u00af\u0001\u0000\u0000\u0000\u0011\u00b5\u0001\u0000\u0000"+
"\u0000\u0013\u00b8\u0001\u0000\u0000\u0000\u0015\u00bf\u0001\u0000\u0000"+
"\u0000\u0017\u00c5\u0001\u0000\u0000\u0000\u0019\u00cb\u0001\u0000\u0000"+
"\u0000\u001b\u00d2\u0001\u0000\u0000\u0000\u001d\u00d5\u0001\u0000\u0000"+
"\u0000\u001f\u00d9\u0001\u0000\u0000\u0000!\u00de\u0001\u0000\u0000\u0000"+
"#\u00e1\u0001\u0000\u0000\u0000%\u00e4\u0001\u0000\u0000\u0000\'\u00e9"+
"\u0001\u0000\u0000\u0000)\u00ee\u0001\u0000\u0000\u0000+\u00f6\u0001\u0000"+
"\u0000\u0000-\u00f8\u0001\u0000\u0000\u0000/\u00fe\u0001\u0000\u0000\u0000"+
"1\u0102\u0001\u0000\u0000\u00003\u0106\u0001\u0000\u0000\u00005\u010a"+
"\u0001\u0000\u0000\u00007\u010e\u0001\u0000\u0000\u00009\u0115\u0001\u0000"+
"\u0000\u0000;\u011c\u0001\u0000\u0000\u0000=\u0125\u0001\u0000\u0000\u0000"+
"?\u012a\u0001\u0000\u0000\u0000A\u0133\u0001\u0000\u0000\u0000C\u0146"+
"\u0001\u0000\u0000\u0000E\u014b\u0001\u0000\u0000\u0000G\u0153\u0001\u0000"+
"\u0000\u0000I\u015c\u0001\u0000\u0000\u0000K\u015f\u0001\u0000\u0000\u0000"+
"M\u0167\u0001\u0000\u0000\u0000O\u0172\u0001\u0000\u0000\u0000Q\u017e"+
"\u0001\u0000\u0000\u0000S\u0187\u0001\u0000\u0000\u0000U\u018a\u0001\u0000"+
"\u0000\u0000W\u018e\u0001\u0000\u0000\u0000Y\u0195\u0001\u0000\u0000\u0000"+
"[\u0197\u0001\u0000\u0000\u0000]\u019a\u0001\u0000\u0000\u0000_\u019c"+
"\u0001\u0000\u0000\u0000a\u01a2\u0001\u0000\u0000\u0000c\u01a4\u0001\u0000"+
"\u0000\u0000e\u01a7\u0001\u0000\u0000\u0000g\u01a9\u0001\u0000\u0000\u0000"+
"i\u01ab\u0001\u0000\u0000\u0000k\u01ad\u0001\u0000\u0000\u0000m\u01af"+
"\u0001\u0000\u0000\u0000o\u01b1\u0001\u0000\u0000\u0000q\u01b3\u0001\u0000"+
"\u0000\u0000s\u01b5\u0001\u0000\u0000\u0000u\u01b7\u0001\u0000\u0000\u0000"+
"w\u01b9\u0001\u0000\u0000\u0000y\u01bc\u0001\u0000\u0000\u0000{\u01d2"+
"\u0001\u0000\u0000\u0000}\u01dd\u0001\u0000\u0000\u0000\u007f\u01e2\u0001"+
"\u0000\u0000\u0000\u0081\u01ff\u0001\u0000\u0000\u0000\u0083\u0201\u0001"+
"\u0000\u0000\u0000\u0085\u0209\u0001\u0000\u0000\u0000\u0087\u020f\u0001"+
"\u0000\u0000\u0000\u0089\u021a\u0001\u0000\u0000\u0000\u008b\u008c\u0007"+
"\u0000\u0000\u0000\u008c\u008d\u0007\u0001\u0000\u0000\u008d\u008e\u0007"+
"\u0002\u0000\u0000\u008e\u0002\u0001\u0000\u0000\u0000\u008f\u0090\u0007"+
"\u0003\u0000\u0000\u0090\u0091\u0007\u0004\u0000\u0000\u0091\u0004\u0001"+
"\u0000\u0000\u0000\u0092\u0093\u0007\u0005\u0000\u0000\u0093\u0094\u0007"+
"\u0001\u0000\u0000\u0094\u0095\u0007\u0006\u0000\u0000\u0095\u0096\u0007"+
"\u0007\u0000\u0000\u0096\u0097\u0007\b\u0000\u0000\u0097\u0098\u0007\b"+
"\u0000\u0000\u0098\u0006\u0001\u0000\u0000\u0000\u0099\u009a\u0007\u0001"+
"\u0000\u0000\u009a\u009b\u0007\u0003\u0000\u0000\u009b\u009c\u0007\t\u0000"+
"\u0000\u009c\b\u0001\u0000\u0000\u0000\u009d\u009e\u0007\b\u0000\u0000"+
"\u009e\u009f\u0007\u0007\u0000\u0000\u009f\u00a0\u0007\u0006\u0000\u0000"+
"\u00a0\u00a1\u0007\u0007\u0000\u0000\u00a1\u00a2\u0007\n\u0000\u0000\u00a2"+
"\u00a3\u0007\t\u0000\u0000\u00a3\n\u0001\u0000\u0000\u0000\u00a4\u00a5"+
"\u0007\u000b\u0000\u0000\u00a5\u00a6\u0007\u0004\u0000\u0000\u00a6\u00a7"+
"\u0007\u0003\u0000\u0000\u00a7\u00a8\u0007\f\u0000\u0000\u00a8\f\u0001"+
"\u0000\u0000\u0000\u00a9\u00aa\u0007\r\u0000\u0000\u00aa\u00ab\u0007\u000e"+
"\u0000\u0000\u00ab\u00ac\u0007\u0007\u0000\u0000\u00ac\u00ad\u0007\u0004"+
"\u0000\u0000\u00ad\u00ae\u0007\u0007\u0000\u0000\u00ae\u000e\u0001\u0000"+
"\u0000\u0000\u00af\u00b0\u0007\u000f\u0000\u0000\u00b0\u00b1\u0007\u0004"+
"\u0000\u0000\u00b1\u00b2\u0007\u0003\u0000\u0000\u00b2\u00b3\u0007\u0005"+
"\u0000\u0000\u00b3\u00b4\u0007\u0010\u0000\u0000\u00b4\u0010\u0001\u0000"+
"\u0000\u0000\u00b5\u00b6\u0007\u0011\u0000\u0000\u00b6\u00b7\u0007\u0012"+
"\u0000\u0000\u00b7\u0012\u0001\u0000\u0000\u0000\u00b8\u00b9\u0007\u000e"+
"\u0000\u0000\u00b9\u00ba\u0007\u0000\u0000\u0000\u00ba\u00bb\u0007\u0013"+
"\u0000\u0000\u00bb\u00bc\u0007\u0014\u0000\u0000\u00bc\u00bd\u0007\u0001"+
"\u0000\u0000\u00bd\u00be\u0007\u000f\u0000\u0000\u00be\u0014\u0001\u0000"+
"\u0000\u0000\u00bf\u00c0\u0007\u0003\u0000\u0000\u00c0\u00c1\u0007\u0004"+
"\u0000\u0000\u00c1\u00c2\u0007\u0002\u0000\u0000\u00c2\u00c3\u0007\u0007"+
"\u0000\u0000\u00c3\u00c4\u0007\u0004\u0000\u0000\u00c4\u0016\u0001\u0000"+
"\u0000\u0000\u00c5\u00c6\u0007\u0006\u0000\u0000\u00c6\u00c7\u0007\u0014"+
"\u0000\u0000\u00c7\u00c8\u0007\f\u0000\u0000\u00c8\u00c9\u0007\u0014\u0000"+
"\u0000\u00c9\u00ca\u0007\t\u0000\u0000\u00ca\u0018\u0001\u0000\u0000\u0000"+
"\u00cb\u00cc\u0007\u0003\u0000\u0000\u00cc\u00cd\u0007\u000b\u0000\u0000"+
"\u00cd\u00ce\u0007\u000b\u0000\u0000\u00ce\u00cf\u0007\b\u0000\u0000\u00cf"+
"\u00d0\u0007\u0007\u0000\u0000\u00d0\u00d1\u0007\t\u0000\u0000\u00d1\u001a"+
"\u0001\u0000\u0000\u0000\u00d2\u00d3\u0007\u0000\u0000\u0000\u00d3\u00d4"+
"\u0007\b\u0000\u0000\u00d4\u001c\u0001\u0000\u0000\u0000\u00d5\u00d6\u0007"+
"\u0000\u0000\u0000\u00d6\u00d7\u0007\b\u0000\u0000\u00d7\u00d8\u0007\n"+
"\u0000\u0000\u00d8\u001e\u0001\u0000\u0000\u0000\u00d9\u00da\u0007\u0002"+
"\u0000\u0000\u00da\u00db\u0007\u0007\u0000\u0000\u00db\u00dc\u0007\b\u0000"+
"\u0000\u00dc\u00dd\u0007\n\u0000\u0000\u00dd \u0001\u0000\u0000\u0000"+
"\u00de\u00df\u0007\u0014\u0000\u0000\u00df\u00e0\u0007\u0001\u0000\u0000"+
"\u00e0\"\u0001\u0000\u0000\u0000\u00e1\u00e2\u0007\u0014\u0000\u0000\u00e2"+
"\u00e3\u0007\b\u0000\u0000\u00e3$\u0001\u0000\u0000\u0000\u00e4\u00e5"+
"\u0007\u0001\u0000\u0000\u00e5\u00e6\u0007\u0005\u0000\u0000\u00e6\u00e7"+
"\u0007\u0006\u0000\u0000\u00e7\u00e8\u0007\u0006\u0000\u0000\u00e8&\u0001"+
"\u0000\u0000\u0000\u00e9\u00ea\u0007\u0006\u0000\u0000\u00ea\u00eb\u0007"+
"\u0014\u0000\u0000\u00eb\u00ec\u0007\u0015\u0000\u0000\u00ec\u00ed\u0007"+
"\u0007\u0000\u0000\u00ed(\u0001\u0000\u0000\u0000\u00ee\u00ef\u0007\u0011"+
"\u0000\u0000\u00ef\u00f0\u0007\u0007\u0000\u0000\u00f0\u00f1\u0007\t\u0000"+
"\u0000\u00f1\u00f2\u0007\r\u0000\u0000\u00f2\u00f3\u0007\u0007\u0000\u0000"+
"\u00f3\u00f4\u0007\u0007\u0000\u0000\u00f4\u00f5\u0007\u0001\u0000\u0000"+
"\u00f5*\u0001\u0000\u0000\u0000\u00f6\u00f7\u0005*\u0000\u0000\u00f7,"+
"\u0001\u0000\u0000\u0000\u00f8\u00f9\u0007\n\u0000\u0000\u00f9\u00fa\u0007"+
"\u0003\u0000\u0000\u00fa\u00fb\u0007\u0005\u0000\u0000\u00fb\u00fc\u0007"+
"\u0001\u0000\u0000\u00fc\u00fd\u0007\t\u0000\u0000\u00fd.\u0001\u0000"+
"\u0000\u0000\u00fe\u00ff\u0007\b\u0000\u0000\u00ff\u0100\u0007\u0005\u0000"+
"\u0000\u0100\u0101\u0007\f\u0000\u0000\u01010\u0001\u0000\u0000\u0000"+
"\u0102\u0103\u0007\u0000\u0000\u0000\u0103\u0104\u0007\u0013\u0000\u0000"+
"\u0104\u0105\u0007\u000f\u0000\u0000\u01052\u0001\u0000\u0000\u0000\u0106"+
"\u0107\u0007\f\u0000\u0000\u0107\u0108\u0007\u0014\u0000\u0000\u0108\u0109"+
"\u0007\u0001\u0000\u0000\u01094\u0001\u0000\u0000\u0000\u010a\u010b\u0007"+
"\f\u0000\u0000\u010b\u010c\u0007\u0000\u0000\u0000\u010c\u010d\u0007\u0016"+
"\u0000\u0000\u010d6\u0001\u0000\u0000\u0000\u010e\u010f\u0007\b\u0000"+
"\u0000\u010f\u0110\u0007\t\u0000\u0000\u0110\u0111\u0007\u0002\u0000\u0000"+
"\u0111\u0112\u0007\u0002\u0000\u0000\u0112\u0113\u0007\u0007\u0000\u0000"+
"\u0113\u0114\u0007\u0013\u0000\u0000\u01148\u0001\u0000\u0000\u0000\u0115"+
"\u0116\u0007\b\u0000\u0000\u0116\u0117\u0007\t\u0000\u0000\u0117\u0118"+
"\u0007\u0002\u0000\u0000\u0118\u0119\u0007\u0013\u0000\u0000\u0119\u011a"+
"\u0007\u0000\u0000\u0000\u011a\u011b\u0007\u0004\u0000\u0000\u011b:\u0001"+
"\u0000\u0000\u0000\u011c\u011d\u0007\u0013\u0000\u0000\u011d\u011e\u0007"+
"\u0000\u0000\u0000\u011e\u011f\u0007\u0004\u0000\u0000\u011f\u0120\u0007"+
"\u0014\u0000\u0000\u0120\u0121\u0007\u0000\u0000\u0000\u0121\u0122\u0007"+
"\u0001\u0000\u0000\u0122\u0123\u0007\n\u0000\u0000\u0123\u0124\u0007\u0007"+
"\u0000\u0000\u0124<\u0001\u0000\u0000\u0000\u0125\u0126\u0007\u0004\u0000"+
"\u0000\u0126\u0127\u0007\u0000\u0000\u0000\u0127\u0128\u0007\t\u0000\u0000"+
"\u0128\u0129\u0007\u0007\u0000\u0000\u0129>\u0001\u0000\u0000\u0000\u012a"+
"\u012b\u0007\u0014\u0000\u0000\u012b\u012c\u0007\u0001\u0000\u0000\u012c"+
"\u012d\u0007\n\u0000\u0000\u012d\u012e\u0007\u0004\u0000\u0000\u012e\u012f"+
"\u0007\u0007\u0000\u0000\u012f\u0130\u0007\u0000\u0000\u0000\u0130\u0131"+
"\u0007\b\u0000\u0000\u0131\u0132\u0007\u0007\u0000\u0000\u0132@\u0001"+
"\u0000\u0000\u0000\u0133\u0134\u0007\u000e\u0000\u0000\u0134\u0135\u0007"+
"\u0014\u0000\u0000\u0135\u0136\u0007\b\u0000\u0000\u0136\u0137\u0007\t"+
"\u0000\u0000\u0137\u0138\u0007\u0003\u0000\u0000\u0138\u0139\u0007\u000f"+
"\u0000\u0000\u0139\u013a\u0007\u0004\u0000\u0000\u013a\u013b\u0007\u0000"+
"\u0000\u0000\u013b\u013c\u0007\f\u0000\u0000\u013c\u013d\u0005_\u0000"+
"\u0000\u013d\u013e\u0007\u0017\u0000\u0000\u013e\u013f\u0007\u0005\u0000"+
"\u0000\u013f\u0140\u0007\u0000\u0000\u0000\u0140\u0141\u0007\u0001\u0000"+
"\u0000\u0141\u0142\u0007\t\u0000\u0000\u0142\u0143\u0007\u0014\u0000\u0000"+
"\u0143\u0144\u0007\u0006\u0000\u0000\u0144\u0145\u0007\u0007\u0000\u0000"+
"\u0145B\u0001\u0000\u0000\u0000\u0146\u0147\u0007\t\u0000\u0000\u0147"+
"\u0148\u0007\u0003\u0000\u0000\u0148\u0149\u0007\u0010\u0000\u0000\u0149"+
"\u014a\u0007\u0015\u0000\u0000\u014aD\u0001\u0000\u0000\u0000\u014b\u014c"+
"\u0007\u0011\u0000\u0000\u014c\u014d\u0007\u0003\u0000\u0000\u014d\u014e"+
"\u0007\t\u0000\u0000\u014e\u014f\u0007\t\u0000\u0000\u014f\u0150\u0007"+
"\u0003\u0000\u0000\u0150\u0151\u0007\f\u0000\u0000\u0151\u0152\u0007\u0015"+
"\u0000\u0000\u0152F\u0001\u0000\u0000\u0000\u0153\u0154\u0007\u0017\u0000"+
"\u0000\u0154\u0155\u0007\u0005\u0000\u0000\u0155\u0156\u0007\u0000\u0000"+
"\u0000\u0156\u0157\u0007\u0001\u0000\u0000\u0157\u0158\u0007\t\u0000\u0000"+
"\u0158\u0159\u0007\u0014\u0000\u0000\u0159\u015a\u0007\u0006\u0000\u0000"+
"\u015a\u015b\u0007\u0007\u0000\u0000\u015bH\u0001\u0000\u0000\u0000\u015c"+
"\u015d\u0007\u0011\u0000\u0000\u015d\u015e\u0007\u0012\u0000\u0000\u015e"+
"J\u0001\u0000\u0000\u0000\u015f\u0160\u0007\r\u0000\u0000\u0160\u0161"+
"\u0007\u0014\u0000\u0000\u0161\u0162\u0007\t\u0000\u0000\u0162\u0163\u0007"+
"\u000e\u0000\u0000\u0163\u0164\u0007\u0003\u0000\u0000\u0164\u0165\u0007"+
"\u0005\u0000\u0000\u0165\u0166\u0007\t\u0000\u0000\u0166L\u0001\u0000"+
"\u0000\u0000\u0167\u0168\u0007\u000f\u0000\u0000\u0168\u0169\u0007\u0004"+
"\u0000\u0000\u0169\u016a\u0007\u0003\u0000\u0000\u016a\u016b\u0007\u0005"+
"\u0000\u0000\u016b\u016c\u0007\u0010\u0000\u0000\u016c\u016d\u0005_\u0000"+
"\u0000\u016d\u016e\u0007\u0006\u0000\u0000\u016e\u016f\u0007\u0007\u0000"+
"\u0000\u016f\u0170\u0007\u000b\u0000\u0000\u0170\u0171\u0007\t\u0000\u0000"+
"\u0171N\u0001\u0000\u0000\u0000\u0172\u0173\u0007\u000f\u0000\u0000\u0173"+
"\u0174\u0007\u0004\u0000\u0000\u0174\u0175\u0007\u0003\u0000\u0000\u0175"+
"\u0176\u0007\u0005\u0000\u0000\u0176\u0177\u0007\u0010\u0000\u0000\u0177"+
"\u0178\u0005_\u0000\u0000\u0178\u0179\u0007\u0004\u0000\u0000\u0179\u017a"+
"\u0007\u0014\u0000\u0000\u017a\u017b\u0007\u000f\u0000\u0000\u017b\u017c"+
"\u0007\u000e\u0000\u0000\u017c\u017d\u0007\t\u0000\u0000\u017dP\u0001"+
"\u0000\u0000\u0000\u017e\u017f\u0007\u0014\u0000\u0000\u017f\u0180\u0007"+
"\u000f\u0000\u0000\u0180\u0181\u0007\u0001\u0000\u0000\u0181\u0182\u0007"+
"\u0003\u0000\u0000\u0182\u0183\u0007\u0004\u0000\u0000\u0183\u0184\u0007"+
"\u0014\u0000\u0000\u0184\u0185\u0007\u0001\u0000\u0000\u0185\u0186\u0007"+
"\u000f\u0000\u0000\u0186R\u0001\u0000\u0000\u0000\u0187\u0188\u0007\u0003"+
"\u0000\u0000\u0188\u0189\u0007\u0001\u0000\u0000\u0189T\u0001\u0000\u0000"+
"\u0000\u018a\u018b\u0007\b\u0000\u0000\u018b\u018c\u0007\u0017\u0000\u0000"+
"\u018c\u018d\u0007\u0006\u0000\u0000\u018dV\u0001\u0000\u0000\u0000\u018e"+
"\u018f\u0007\u0010\u0000\u0000\u018f\u0190\u0007\u0004\u0000\u0000\u0190"+
"\u0191\u0007\u0003\u0000\u0000\u0191\u0192\u0007\f\u0000\u0000\u0192\u0193"+
"\u0007\u0017\u0000\u0000\u0193\u0194\u0007\u0006\u0000\u0000\u0194X\u0001"+
"\u0000\u0000\u0000\u0195\u0196\u0005>\u0000\u0000\u0196Z\u0001\u0000\u0000"+
"\u0000\u0197\u0198\u0005>\u0000\u0000\u0198\u0199\u0005=\u0000\u0000\u0199"+
"\\\u0001\u0000\u0000\u0000\u019a\u019b\u0005<\u0000\u0000\u019b^\u0001"+
"\u0000\u0000\u0000\u019c\u019d\u0005<\u0000\u0000\u019d\u019e\u0005=\u0000"+
"\u0000\u019e`\u0001\u0000\u0000\u0000\u019f\u01a0\u0005=\u0000\u0000\u01a0"+
"\u01a3\u0005=\u0000\u0000\u01a1\u01a3\u0005=\u0000\u0000\u01a2\u019f\u0001"+
"\u0000\u0000\u0000\u01a2\u01a1\u0001\u0000\u0000\u0000\u01a3b\u0001\u0000"+
"\u0000\u0000\u01a4\u01a5\u0005!\u0000\u0000\u01a5\u01a6\u0005=\u0000\u0000"+
"\u01a6d\u0001\u0000\u0000\u0000\u01a7\u01a8\u0005(\u0000\u0000\u01a8f"+
"\u0001\u0000\u0000\u0000\u01a9\u01aa\u0005)\u0000\u0000\u01aah\u0001\u0000"+
"\u0000\u0000\u01ab\u01ac\u0005{\u0000\u0000\u01acj\u0001\u0000\u0000\u0000"+
"\u01ad\u01ae\u0005}\u0000\u0000\u01ael\u0001\u0000\u0000\u0000\u01af\u01b0"+
"\u0005[\u0000\u0000\u01b0n\u0001\u0000\u0000\u0000\u01b1\u01b2\u0005]"+
"\u0000\u0000\u01b2p\u0001\u0000\u0000\u0000\u01b3\u01b4\u0005,\u0000\u0000"+
"\u01b4r\u0001\u0000\u0000\u0000\u01b5\u01b6\u0005.\u0000\u0000\u01b6t"+
"\u0001\u0000\u0000\u0000\u01b7\u01b8\u0005:\u0000\u0000\u01b8v\u0001\u0000"+
"\u0000\u0000\u01b9\u01ba\u0005;\u0000\u0000\u01bax\u0001\u0000\u0000\u0000"+
"\u01bb\u01bd\u0007\u0018\u0000\u0000\u01bc\u01bb\u0001\u0000\u0000\u0000"+
"\u01bd\u01be\u0001\u0000\u0000\u0000\u01be\u01bc\u0001\u0000\u0000\u0000"+
"\u01be\u01bf\u0001\u0000\u0000\u0000\u01bf\u01c6\u0001\u0000\u0000\u0000"+
"\u01c0\u01c2\u0005.\u0000\u0000\u01c1\u01c3\u0007\u0018\u0000\u0000\u01c2"+
"\u01c1\u0001\u0000\u0000\u0000\u01c3\u01c4\u0001\u0000\u0000\u0000\u01c4"+
"\u01c2\u0001\u0000\u0000\u0000\u01c4\u01c5\u0001\u0000\u0000\u0000\u01c5"+
"\u01c7\u0001\u0000\u0000\u0000\u01c6\u01c0\u0001\u0000\u0000\u0000\u01c6"+
"\u01c7\u0001\u0000\u0000\u0000\u01c7\u01c8\u0001\u0000\u0000\u0000\u01c8"+
"\u01ca\u0007\u0007\u0000\u0000\u01c9\u01cb\u0007\u0019\u0000\u0000\u01ca"+
"\u01c9\u0001\u0000\u0000\u0000\u01ca\u01cb\u0001\u0000\u0000\u0000\u01cb"+
"\u01cd\u0001\u0000\u0000\u0000\u01cc\u01ce\u0007\u0018\u0000\u0000\u01cd"+
"\u01cc\u0001\u0000\u0000\u0000\u01ce\u01cf\u0001\u0000\u0000\u0000\u01cf"+
"\u01cd\u0001\u0000\u0000\u0000\u01cf\u01d0\u0001\u0000\u0000\u0000\u01d0"+
"z\u0001\u0000\u0000\u0000\u01d1\u01d3\u0007\u0018\u0000\u0000\u01d2\u01d1"+
"\u0001\u0000\u0000\u0000\u01d3\u01d4\u0001\u0000\u0000\u0000\u01d4\u01d2"+
"\u0001\u0000\u0000\u0000\u01d4\u01d5\u0001\u0000\u0000\u0000\u01d5\u01d6"+
"\u0001\u0000\u0000\u0000\u01d6\u01d8\u0005.\u0000\u0000\u01d7\u01d9\u0007"+
"\u0018\u0000\u0000\u01d8\u01d7\u0001\u0000\u0000\u0000\u01d9\u01da\u0001"+
"\u0000\u0000\u0000\u01da\u01d8\u0001\u0000\u0000\u0000\u01da\u01db\u0001"+
"\u0000\u0000\u0000\u01db|\u0001\u0000\u0000\u0000\u01dc\u01de\u0007\u0018"+
"\u0000\u0000\u01dd\u01dc\u0001\u0000\u0000\u0000\u01de\u01df\u0001\u0000"+
"\u0000\u0000\u01df\u01dd\u0001\u0000\u0000\u0000\u01df\u01e0\u0001\u0000"+
"\u0000\u0000\u01e0~\u0001\u0000\u0000\u0000\u01e1\u01e3\u0007\u0018\u0000"+
"\u0000\u01e2\u01e1\u0001\u0000\u0000\u0000\u01e3\u01e4\u0001\u0000\u0000"+
"\u0000\u01e4\u01e2\u0001\u0000\u0000\u0000\u01e4\u01e5\u0001\u0000\u0000"+
"\u0000\u01e5\u01e7\u0001\u0000\u0000\u0000\u01e6\u01e8\u0007\u001a\u0000"+
"\u0000\u01e7\u01e6\u0001\u0000\u0000\u0000\u01e8\u01e9\u0001\u0000\u0000"+
"\u0000\u01e9\u01e7\u0001\u0000\u0000\u0000\u01e9\u01ea\u0001\u0000\u0000"+
"\u0000\u01ea\u0080\u0001\u0000\u0000\u0000\u01eb\u01f1\u0005\"\u0000\u0000"+
"\u01ec\u01f0\b\u001b\u0000\u0000\u01ed\u01ee\u0005\\\u0000\u0000\u01ee"+
"\u01f0\t\u0000\u0000\u0000\u01ef\u01ec\u0001\u0000\u0000\u0000\u01ef\u01ed"+
"\u0001\u0000\u0000\u0000\u01f0\u01f3\u0001\u0000\u0000\u0000\u01f1\u01ef"+
"\u0001\u0000\u0000\u0000\u01f1\u01f2\u0001\u0000\u0000\u0000\u01f2\u01f4"+
"\u0001\u0000\u0000\u0000\u01f3\u01f1\u0001\u0000\u0000\u0000\u01f4\u0200"+
"\u0005\"\u0000\u0000\u01f5\u01fb\u0005\'\u0000\u0000\u01f6\u01fa\b\u001c"+
"\u0000\u0000\u01f7\u01f8\u0005\\\u0000\u0000\u01f8\u01fa\t\u0000\u0000"+
"\u0000\u01f9\u01f6\u0001\u0000\u0000\u0000\u01f9\u01f7\u0001\u0000\u0000"+
"\u0000\u01fa\u01fd\u0001\u0000\u0000\u0000\u01fb\u01f9\u0001\u0000\u0000"+
"\u0000\u01fb\u01fc\u0001\u0000\u0000\u0000\u01fc\u01fe\u0001\u0000\u0000"+
"\u0000\u01fd\u01fb\u0001\u0000\u0000\u0000\u01fe\u0200\u0005\'\u0000\u0000"+
"\u01ff\u01eb\u0001\u0000\u0000\u0000\u01ff\u01f5\u0001\u0000\u0000\u0000"+
"\u0200\u0082\u0001\u0000\u0000\u0000\u0201\u0205\u0007\u001d\u0000\u0000"+
"\u0202\u0204\u0007\u001e\u0000\u0000\u0203\u0202\u0001\u0000\u0000\u0000"+
"\u0204\u0207\u0001\u0000\u0000\u0000\u0205\u0203\u0001\u0000\u0000\u0000"+
"\u0205\u0206\u0001\u0000\u0000\u0000\u0206\u0084\u0001\u0000\u0000\u0000"+
"\u0207\u0205\u0001\u0000\u0000\u0000\u0208\u020a\u0007\u001f\u0000\u0000"+
"\u0209\u0208\u0001\u0000\u0000\u0000\u020a\u020b\u0001\u0000\u0000\u0000"+
"\u020b\u0209\u0001\u0000\u0000\u0000\u020b\u020c\u0001\u0000\u0000\u0000"+
"\u020c\u020d\u0001\u0000\u0000\u0000\u020d\u020e\u0006B\u0000\u0000\u020e"+
"\u0086\u0001\u0000\u0000\u0000\u020f\u0210\u0005/\u0000\u0000\u0210\u0211"+
"\u0005/\u0000\u0000\u0211\u0215\u0001\u0000\u0000\u0000\u0212\u0214\b"+
" \u0000\u0000\u0213\u0212\u0001\u0000\u0000\u0000\u0214\u0217\u0001\u0000"+
"\u0000\u0000\u0215\u0213\u0001\u0000\u0000\u0000\u0215\u0216\u0001\u0000"+
"\u0000\u0000\u0216\u0218\u0001\u0000\u0000\u0000\u0217\u0215\u0001\u0000"+
"\u0000\u0000\u0218\u0219\u0006C\u0001\u0000\u0219\u0088\u0001\u0000\u0000"+
"\u0000\u021a\u021b\u0005/\u0000\u0000\u021b\u021c\u0005*\u0000\u0000\u021c"+
"\u0220\u0001\u0000\u0000\u0000\u021d\u021f\t\u0000\u0000\u0000\u021e\u021d"+
"\u0001\u0000\u0000\u0000\u021f\u0222\u0001\u0000\u0000\u0000\u0220\u0221"+
"\u0001\u0000\u0000\u0000\u0220\u021e\u0001\u0000\u0000\u0000\u0221\u0223"+
"\u0001\u0000\u0000\u0000\u0222\u0220\u0001\u0000\u0000\u0000\u0223\u0224"+
"\u0005*\u0000\u0000\u0224\u0225\u0005/\u0000\u0000\u0225\u0226\u0001\u0000"+
"\u0000\u0000\u0226\u0227\u0006D\u0001\u0000\u0227\u008a\u0001\u0000\u0000"+
"\u0000\u0015\u0000\u01a2\u01be\u01c4\u01c6\u01ca\u01cf\u01d4\u01da\u01df"+
"\u01e4\u01e9\u01ef\u01f1\u01f9\u01fb\u01ff\u0205\u020b\u0215\u0220\u0002"+
"\u0000\u0001\u0000\u0006\u0000\u0000";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
}
}
}
@@ -0,0 +1,322 @@
/*
* 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.
*/
// Generated from AlertExpression.g4 by ANTLR 4.13.2
package org.apache.hertzbeat.alert.expr;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
/**
* This interface defines a complete generic visitor for a parse tree produced
* by {@link AlertExpressionParser}.
*
* @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
public interface AlertExpressionVisitor<T> extends ParseTreeVisitor<T> {
/**
* Visit a parse tree produced by {@link AlertExpressionParser#expression}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitExpression(AlertExpressionParser.ExpressionContext ctx);
/**
* Visit a parse tree produced by the {@code AndExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAndExpr(AlertExpressionParser.AndExprContext ctx);
/**
* Visit a parse tree produced by the {@code ComparisonExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitComparisonExpr(AlertExpressionParser.ComparisonExprContext ctx);
/**
* Visit a parse tree produced by the {@code UnlessExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitUnlessExpr(AlertExpressionParser.UnlessExprContext ctx);
/**
* Visit a parse tree produced by the {@code SqlExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSqlExpr(AlertExpressionParser.SqlExprContext ctx);
/**
* Visit a parse tree produced by the {@code SqlCallExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSqlCallExpr(AlertExpressionParser.SqlCallExprContext ctx);
/**
* Visit a parse tree produced by the {@code LiteralExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitLiteralExpr(AlertExpressionParser.LiteralExprContext ctx);
/**
* Visit a parse tree produced by the {@code ParenExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitParenExpr(AlertExpressionParser.ParenExprContext ctx);
/**
* Visit a parse tree produced by the {@code PromqlCallExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitPromqlCallExpr(AlertExpressionParser.PromqlCallExprContext ctx);
/**
* Visit a parse tree produced by the {@code PromqlExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitPromqlExpr(AlertExpressionParser.PromqlExprContext ctx);
/**
* Visit a parse tree produced by the {@code OrExpr}
* labeled alternative in {@link AlertExpressionParser#expr}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitOrExpr(AlertExpressionParser.OrExprContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#functionCall}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFunctionCall(AlertExpressionParser.FunctionCallContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#parameterList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitParameterList(AlertExpressionParser.ParameterListContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#parameter}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitParameter(AlertExpressionParser.ParameterContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#number}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitNumber(AlertExpressionParser.NumberContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#string}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitString(AlertExpressionParser.StringContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#duration}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitDuration(AlertExpressionParser.DurationContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#functionName}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFunctionName(AlertExpressionParser.FunctionNameContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#selectSql}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSelectSql(AlertExpressionParser.SelectSqlContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#selectFieldList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSelectFieldList(AlertExpressionParser.SelectFieldListContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#selectField}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitSelectField(AlertExpressionParser.SelectFieldContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#groupByList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitGroupByList(AlertExpressionParser.GroupByListContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#orderByList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitOrderByList(AlertExpressionParser.OrderByListContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#orderByField}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitOrderByField(AlertExpressionParser.OrderByFieldContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#limitClause}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitLimitClause(AlertExpressionParser.LimitClauseContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#relList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitRelList(AlertExpressionParser.RelListContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#relation}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitRelation(AlertExpressionParser.RelationContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#conditionList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitConditionList(AlertExpressionParser.ConditionListContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#compOp}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitCompOp(AlertExpressionParser.CompOpContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#condition}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitCondition(AlertExpressionParser.ConditionContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#conditionUnit}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitConditionUnit(AlertExpressionParser.ConditionUnitContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#promql}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitPromql(AlertExpressionParser.PromqlContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#metricSelector}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitMetricSelector(AlertExpressionParser.MetricSelectorContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#labelMatcherList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitLabelMatcherList(AlertExpressionParser.LabelMatcherListContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#labelMatcherItem}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitLabelMatcherItem(AlertExpressionParser.LabelMatcherItemContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#labelMatcherOp}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitLabelMatcherOp(AlertExpressionParser.LabelMatcherOpContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#labelList}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitLabelList(AlertExpressionParser.LabelListContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#instantVectorOp}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitInstantVectorOp(AlertExpressionParser.InstantVectorOpContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#aggregationOperator}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAggregationOperator(AlertExpressionParser.AggregationOperatorContext ctx);
/**
* Visit a parse tree produced by {@link AlertExpressionParser#binaryOperator}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitBinaryOperator(AlertExpressionParser.BinaryOperatorContext ctx);
}
@@ -0,0 +1,134 @@
/*
* 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.hertzbeat.alert.notice;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.AlerterWorkerPool;
import org.apache.hertzbeat.alert.config.AlertSseManager;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeRule;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.alert.service.NoticeConfigService;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.hertzbeat.plugin.PostAlertPlugin;
import org.apache.hertzbeat.plugin.Plugin;
import org.apache.hertzbeat.plugin.runner.PluginRunner;
import org.springframework.stereotype.Component;
/**
* Alarm information storage and distribution
*/
@Component
@Slf4j
public class AlertNoticeDispatch {
private final AlerterWorkerPool workerPool;
private final NoticeConfigService noticeConfigService;
private final AlertStoreHandler alertStoreHandler;
private final Map<Byte, AlertNotifyHandler> alertNotifyHandlerMap;
private final PluginRunner pluginRunner;
private final AlertSseManager emitterManager;
public AlertNoticeDispatch(AlerterWorkerPool workerPool,
NoticeConfigService noticeConfigService,
AlertStoreHandler alertStoreHandler,
List<AlertNotifyHandler> alertNotifyHandlerList, PluginRunner pluginRunner, AlertSseManager emitterManager) {
this.workerPool = workerPool;
this.noticeConfigService = noticeConfigService;
this.alertStoreHandler = alertStoreHandler;
this.pluginRunner = pluginRunner;
alertNotifyHandlerMap = Maps.newHashMapWithExpectedSize(alertNotifyHandlerList.size());
this.emitterManager = emitterManager;
alertNotifyHandlerList.forEach(r -> alertNotifyHandlerMap.put(r.type(), r));
}
/**
* send alert msg to receiver
*
* @param receiver receiver
* @param alert alert msg
* @return send success or failed
*/
public boolean sendNoticeMsg(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
if (receiver == null || receiver.getType() == null) {
log.warn("DispatcherAlarm-sendNoticeMsg params is empty alert:[{}], receiver:[{}]", alert, receiver);
return false;
}
byte type = receiver.getType();
if (alertNotifyHandlerMap.containsKey(type)) {
AlertNotifyHandler alertNotifyHandler = alertNotifyHandlerMap.get(type);
if (noticeTemplate == null) {
noticeTemplate = noticeConfigService.getDefaultNoticeTemplateByType(alertNotifyHandler.type());
}
if (noticeTemplate == null && alertNotifyHandler.type() != 0) {
log.error("alert does not have mapping default notice template. type: {}.", alertNotifyHandler.type());
throw new NullPointerException(alertNotifyHandler.type() + " does not have mapping default notice template");
}
alertNotifyHandler.send(receiver, noticeTemplate, alert);
return true;
}
return false;
}
private NoticeReceiver getOneReceiverById(Long id) {
return noticeConfigService.getReceiverById(id);
}
private NoticeTemplate getOneTemplateById(Long id) {
if (id == null) {
return null;
}
return noticeConfigService.getOneTemplateById(id);
}
private Optional<List<NoticeRule>> matchNoticeRulesByAlert(GroupAlert alert) {
return Optional.ofNullable(noticeConfigService.getReceiverFilterRule(alert));
}
public void dispatchAlarm(GroupAlert groupAlert) {
if (groupAlert != null) {
// Determining alarm type storage
GroupAlert storedGroupAlert = alertStoreHandler.store(groupAlert);
// Notice distribution
sendNotify(storedGroupAlert);
// Execute the plugin if enable (Compatible with old version plugins, will be removed in later versions)
pluginRunner.pluginExecute(Plugin.class, plugin -> plugin.alert(storedGroupAlert));
// Execute the plugin if enable with params
pluginRunner.pluginExecute(PostAlertPlugin.class, (afterAlertPlugin, pluginContext) -> afterAlertPlugin.execute(storedGroupAlert, pluginContext));
// Send alert to the sse client
emitterManager.broadcast(JsonUtil.toJson(storedGroupAlert));
}
}
private void sendNotify(GroupAlert alert) {
matchNoticeRulesByAlert(alert).ifPresent(noticeRules -> noticeRules.forEach(rule -> workerPool.executeNotify(() -> rule.getReceiverId()
.forEach(receiverId -> {
try {
sendNoticeMsg(getOneReceiverById(receiverId),
getOneTemplateById(rule.getTemplateId()), alert);
} catch (AlertNoticeException e) {
log.warn("DispatchTask sendNoticeMsg error, message: {}", e.getMessage());
}
}))));
}
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.support.exception;
package org.apache.hertzbeat.alert.notice;
/**
* alert notice send failed
@@ -15,12 +15,11 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.alerter;
package org.apache.hertzbeat.alert.notice;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.manager.support.exception.AlertNoticeException;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
/**
* AlertNotifyHandler interface
@@ -34,7 +33,7 @@ public interface AlertNotifyHandler {
* @param alert Alarm information
* @throws AlertNoticeException when send receiver error
*/
void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, Alert alert) throws AlertNoticeException;
void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) throws AlertNoticeException;
/**
* notification type
@@ -15,9 +15,9 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.alerter;
package org.apache.hertzbeat.alert.notice;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
/**
* Alarm persistence
@@ -28,7 +28,9 @@ public interface AlertStoreHandler {
* Persistent alarm records
* It is necessary to associate and assign values
* to the alert tag information tags while persisting.
*
* @param alert alarm information
* @return groupAlert
*/
void store(Alert alert);
GroupAlert store(GroupAlert alert);
}
@@ -15,29 +15,25 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.alerter.impl;
package org.apache.hertzbeat.alert.notice.impl;
import freemarker.cache.StringTemplateLoader;
import freemarker.core.TemplateClassResolver;
import freemarker.template.Configuration;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.AlerterProperties;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
import org.apache.hertzbeat.common.util.ResourceBundleUtil;
import org.apache.hertzbeat.manager.component.alerter.AlertNotifyHandler;
import org.apache.hertzbeat.alert.notice.AlertNotifyHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;
@@ -49,15 +45,14 @@ import org.springframework.web.client.RestTemplate;
abstract class AbstractAlertNotifyHandlerImpl implements AlertNotifyHandler {
private static final String NUMBER_FORMAT = "0";
protected static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
protected ResourceBundle bundle = ResourceBundleUtil.getBundle("alerter");
@Resource
@Autowired
protected RestTemplate restTemplate;
@Resource
@Autowired
protected AlerterProperties alerterProperties;
protected String renderContent(NoticeTemplate noticeTemplate, Alert alert) throws TemplateException, IOException {
protected String renderContent(NoticeTemplate noticeTemplate, GroupAlert alert) throws TemplateException, IOException {
StringTemplateLoader stringLoader = new StringTemplateLoader();
freemarker.template.Template templateRes;
Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
@@ -65,51 +60,14 @@ abstract class AbstractAlertNotifyHandlerImpl implements AlertNotifyHandler {
cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
Map<String, Object> model = new HashMap<>(16);
model.put("title", bundle.getString("alerter.notify.title"));
if (alert.getTags() != null) {
String monitorId = alert.getTags().get(CommonConstants.TAG_MONITOR_ID);
if (monitorId != null) {
model.put("monitorId", monitorId);
}
String monitorName = alert.getTags().get(CommonConstants.TAG_MONITOR_NAME);
if (monitorName != null) {
model.put("monitorName", monitorName);
}
String monitorHost = alert.getTags().get(CommonConstants.TAG_MONITOR_HOST);
if (monitorHost != null) {
model.put("monitorHost", monitorHost);
}
String thresholdId = alert.getTags().get(CommonConstants.TAG_THRESHOLD_ID);
if (thresholdId != null) {
model.put("thresholdId", thresholdId);
}
}
model.put("alarmId", alert.getId());
model.put("status", alert.getStatus());
model.put("monitorIdLabel", bundle.getString("alerter.notify.monitorId"));
model.put("monitorNameLabel", bundle.getString("alerter.notify.monitorName"));
model.put("monitorHostLabel", bundle.getString("alerter.notify.monitorHost"));
model.put("target", alert.getTarget());
model.put("targetLabel", bundle.getString("alerter.notify.target"));
model.put("priorityLabel", bundle.getString("alerter.notify.priority"));
model.put("priority", bundle.getString("alerter.priority." + alert.getPriority()));
model.put("priorityValue", alert.getPriority());
model.put("triggerTimeLabel", bundle.getString("alerter.notify.triggerTime"));
model.put("triggerTime", DTF.format(Instant.ofEpochMilli(alert.getLastAlarmTime()).atZone(ZoneId.systemDefault()).toLocalDateTime()));
if (CommonConstants.ALERT_STATUS_CODE_RESTORED == alert.getStatus()) {
model.put("restoreTimeLabel", bundle.getString("alerter.notify.restoreTime"));
model.put("restoreTime", DTF.format(Instant.ofEpochMilli(alert.getFirstAlarmTime()).atZone(ZoneId.systemDefault()).toLocalDateTime()));
}
model.put("timesLabel", bundle.getString("alerter.notify.times"));
model.put("times", alert.getTimes());
model.put("contentLabel", bundle.getString("alerter.notify.content"));
model.put("content", alert.getContent());
model.put("tagsLabel", bundle.getString("alerter.notify.tags"));
model.put("tags", alert.getTags());
model.put("groupLabels", alert.getGroupLabels());
model.put("commonLabels", alert.getCommonLabels());
model.put("commonAnnotations", alert.getCommonAnnotations());
model.put("alerts", alert.getAlerts());
if (alerterProperties != null) {
model.put("consoleUrl", alerterProperties.getConsoleUrl());
}
model.put("consoleLabel", bundle.getString("alerter.notify.console"));
// TODO Single instance reuse cache considers multiple-threading issues
String templateName = "freeMakerTemplate";
stringLoader.putTemplate(templateName, noticeTemplate.getContent());
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.alerter.impl;
package org.apache.hertzbeat.alert.notice.impl;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
@@ -0,0 +1,135 @@
/*
* 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.hertzbeat.alert.notice.impl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.dao.GroupAlertDao;
import org.apache.hertzbeat.alert.dao.SingleAlertDao;
import org.apache.hertzbeat.alert.notice.AlertStoreHandler;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
import org.springframework.stereotype.Component;
/**
* Alarm data persistence - landing in the database
*/
@Component
@RequiredArgsConstructor
@Slf4j
final class DbAlertStoreHandlerImpl implements AlertStoreHandler {
private final GroupAlertDao groupAlertDao;
private final SingleAlertDao singleAlertDao;
@Override
public GroupAlert store(GroupAlert groupAlert) {
if (groupAlert == null || groupAlert.getAlerts() == null || groupAlert.getAlerts().isEmpty()) {
log.error("The Group Alerts is empty, ignore store");
return groupAlert;
}
// Process individual alerts
Set<String> alertFingerprints = new HashSet<>(8);
List<SingleAlert> originalAlerts = groupAlert.getAlerts();
List<SingleAlert> newAlerts = new ArrayList<>();
for (SingleAlert singleAlert : originalAlerts) {
synchronized (singleAlert.getFingerprint().intern()) {
SingleAlert existAlert = singleAlertDao.findByFingerprint(singleAlert.getFingerprint());
if (existAlert != null) {
// Update the existing alert with the ID and creation time from the database
singleAlert.setId(existAlert.getId());
singleAlert.setGmtCreate(existAlert.getGmtCreate());
// Status transition logic
if (CommonConstants.ALERT_STATUS_FIRING.equals(singleAlert.getStatus())) {
// If the alert is firing and the existing alert is not resolved, update the start time and trigger times
if (!CommonConstants.ALERT_STATUS_RESOLVED.equals(existAlert.getStatus())) {
singleAlert.setStartAt(existAlert.getStartAt());
int triggerTimes = Optional.ofNullable(existAlert.getTriggerTimes()).orElse(1)
+ Optional.ofNullable(singleAlert.getTriggerTimes()).orElse(1);
singleAlert.setTriggerTimes(triggerTimes);
}
} else if (CommonConstants.ALERT_STATUS_RESOLVED.equals(singleAlert.getStatus())) {
// If the alert is resolved, set the end time (if not already set) and copy other fields from the existing alert
if (singleAlert.getEndAt() == null) {
singleAlert.setEndAt(System.currentTimeMillis());
}
singleAlert.setStartAt(existAlert.getStartAt());
singleAlert.setActiveAt(existAlert.getActiveAt());
singleAlert.setTriggerTimes(existAlert.getTriggerTimes());
}
}
SingleAlert savedSingleAlert = singleAlertDao.save(singleAlert);
newAlerts.add(savedSingleAlert);
alertFingerprints.add(savedSingleAlert.getFingerprint());
}
}
groupAlert.setAlerts(newAlerts);
// Find existing alert group
synchronized (groupAlert.getGroupKey().intern()) {
GroupAlert existGroupAlert = groupAlertDao.findByGroupKey(groupAlert.getGroupKey());
// Process resolved alerts
if (existGroupAlert != null) {
List<String> existFingerprints = existGroupAlert.getAlertFingerprints();
if (existFingerprints != null) {
alertFingerprints.addAll(existFingerprints);
}
// Merge group information
groupAlert.setId(existGroupAlert.getId());
groupAlert.setGmtCreate(existGroupAlert.getGmtCreate());
// Merge other historical information to preserve
Map<String, String> existCommonLabels = existGroupAlert.getCommonLabels();
if (existCommonLabels != null) {
Map<String, String> commonLabels = groupAlert.getCommonLabels();
if (commonLabels != null) {
// filter common label in commonLabels and existCommonLabels
commonLabels = commonLabels.entrySet().stream()
.filter(entry -> existCommonLabels.containsKey(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
groupAlert.setCommonLabels(commonLabels);
}
}
Map<String, String> existCommonAnnotations = existGroupAlert.getCommonAnnotations();
if (existCommonAnnotations != null) {
Map<String, String> commonAnnotations = groupAlert.getCommonAnnotations();
if (commonAnnotations != null) {
// filter common annotation in commonAnnotations and existCommonAnnotations
commonAnnotations = commonAnnotations.entrySet().stream()
.filter(entry -> existCommonAnnotations.containsKey(entry.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
groupAlert.setCommonAnnotations(commonAnnotations);
}
}
}
// Save alert group
groupAlert.setAlertFingerprints(alertFingerprints.stream().toList());
GroupAlert savedGroupAlert = groupAlertDao.save(groupAlert);
savedGroupAlert.setAlerts(groupAlert.getAlerts());
return savedGroupAlert;
}
}
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.alerter.impl;
package org.apache.hertzbeat.alert.notice.impl;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
@@ -23,11 +23,11 @@ import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.alert.notice.AlertNoticeException;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.common.util.StrUtil;
import org.apache.hertzbeat.manager.support.exception.AlertNoticeException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -44,7 +44,7 @@ import org.springframework.stereotype.Component;
final class DingTalkRobotAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl {
@Override
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, Alert alert) {
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
try {
DingTalkWebHookDto dingTalkWebHookDto = new DingTalkWebHookDto();
DingTalkWebHookDto.MarkdownDTO markdownDTO = new DingTalkWebHookDto.MarkdownDTO();
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.alerter.impl;
package org.apache.hertzbeat.alert.notice.impl;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;
@@ -23,10 +23,10 @@ import lombok.Builder;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.manager.support.exception.AlertNoticeException;
import org.apache.hertzbeat.alert.notice.AlertNoticeException;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -42,7 +42,7 @@ import org.springframework.stereotype.Component;
final class DiscordBotAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl {
@Override
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, Alert alert) throws AlertNoticeException {
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) throws AlertNoticeException {
try {
var notifyBody = DiscordNotifyDTO.builder()
.embeds(List.of(EmbedDTO.builder()
@@ -93,7 +93,7 @@ final class DiscordBotAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerI
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
private static class DiscordResponseDTO {
public static class DiscordResponseDTO {
private String id;
private Integer type;
private String content;
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.alerter.impl;
package org.apache.hertzbeat.alert.notice.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.mail.internet.MimeMessage;
@@ -24,15 +24,15 @@ import java.util.Properties;
import java.util.ResourceBundle;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.alert.dto.MailServerConfig;
import org.apache.hertzbeat.alert.notice.AlertNoticeException;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
import org.apache.hertzbeat.common.util.ResourceBundleUtil;
import org.apache.hertzbeat.manager.dao.GeneralConfigDao;
import org.apache.hertzbeat.manager.pojo.dto.EmailNoticeSender;
import org.apache.hertzbeat.manager.support.exception.AlertNoticeException;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.mail.javamail.JavaMailSender;
@@ -77,7 +77,7 @@ public class EmailAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl
private ResourceBundle bundle = ResourceBundleUtil.getBundle("alerter");
@Override
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, Alert alert) throws AlertNoticeException {
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) throws AlertNoticeException {
try {
// get sender
JavaMailSenderImpl sender = (JavaMailSenderImpl) javaMailSender;
@@ -88,7 +88,7 @@ public class EmailAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl
if (emailConfig != null && emailConfig.getContent() != null) {
// enable database configuration
String content = emailConfig.getContent();
EmailNoticeSender emailNoticeSenderConfig = objectMapper.readValue(content, EmailNoticeSender.class);
MailServerConfig emailNoticeSenderConfig = objectMapper.readValue(content, MailServerConfig.class);
if (emailNoticeSenderConfig.isEnable()) {
sender.setHost(emailNoticeSenderConfig.getEmailHost());
sender.setPort(emailNoticeSenderConfig.getEmailPort());
@@ -0,0 +1,210 @@
/*
* 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.hertzbeat.alert.notice.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.alert.notice.AlertNoticeException;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* Send alert information through FeiShu
*/
@Component
@RequiredArgsConstructor
@Slf4j
final class FlyBookAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl {
/**
* Title color corresponding to the alarm priority
*/
private static final String[] TITLE_COLOR = {"red", "yellow", "orange"};
@Override
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
try {
String notificationContent = JsonUtil.toJson(renderContent(noticeTemplate, alert));
// todo priority custom the color
String cardMessage = createLarkMessage(receiver.getUserId(), notificationContent, (byte) 1);
String webHookUrl = alerterProperties.getFlyBookWebhookUrl() + receiver.getAccessToken();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> flyEntity = new HttpEntity<>(cardMessage, headers);
ResponseEntity<CommonRobotNotifyResp> entity = restTemplate.postForEntity(webHookUrl,
flyEntity, CommonRobotNotifyResp.class);
if (entity.getStatusCode() == HttpStatus.OK) {
assert entity.getBody() != null;
if (entity.getBody().getCode() == null || entity.getBody().getCode() == 0) {
log.debug("Send feiShu webHook: {} Success", webHookUrl);
} else {
log.warn("Send feiShu webHook: {} Failed: {}", webHookUrl, entity.getBody().getMsg());
throw new AlertNoticeException(entity.getBody().getMsg());
}
} else {
log.warn("Send feiShu webHook: {} Failed: {}", webHookUrl, entity.getBody());
throw new AlertNoticeException("Http StatusCode " + entity.getStatusCode());
}
} catch (Exception e) {
throw new AlertNoticeException("[FeiShu Notify Error] " + e.getMessage());
}
}
/**
* create a lark notification card message
*
* @param userId at user id
* @param notificationContent notification content
* @param priority priority for alert
* @return message
*/
private String createLarkMessage(String userId, String notificationContent, byte priority) {
String larkCardMessage = """
{
"msg_type": "interactive",
"card": {
"schema": "2.0",
"config": {
"update_multi": true,
"locales": [
"en_us",
"zh_cn"
],
"style": {
"text_size": {
"normal_v2": {
"default": "normal",
"pc": "normal",
"mobile": "heading"
}
}
}
},
"body": {
"direction": "vertical",
"padding": "12px 12px 12px 12px",
"elements": [
{
"tag": "markdown",
"content": "%s",
"i18n_content": {
"en_us": ""
},
"text_align": "left",
"text_size": "normal_v2",
"margin": "0px 0px 0px 0px"
},
{
"tag": "hr",
"margin": "0px 0px 0px 0px"
},
{
"tag": "column_set",
"horizontal_align": "left",
"columns": [
{
"tag": "column",
"width": "weighted",
"elements": [
{
"tag": "button",
"text": {
"tag": "plain_text",
"content": "登入控制台",
"i18n_content": {
"en_us": "Login In"
}
},
"type": "default",
"width": "default",
"size": "medium",
"behaviors": [
{
"type": "open_url",
"default_url": "%s",
"pc_url": "",
"ios_url": "",
"android_url": ""
}
]
}
],
"direction": "horizontal",
"vertical_spacing": "8px",
"horizontal_align": "left",
"vertical_align": "top",
"weight": 1
}
],
"margin": "0px 0px 0px 0px"
}
]
},
"header": {
"title": {
"tag": "plain_text",
"content": "HertzBeat 告警",
"i18n_content": {
"en_us": "HertzBeat Alarm"
}
},
"subtitle": {
"tag": "plain_text",
"content": ""
},
"template": "%s",
"padding": "12px 12px 12px 12px"
}
}
}
""";
String atUserElement = "";
if (StringUtils.isNotBlank(userId)) {
atUserElement = "\\n" + Arrays.stream(userId.split(","))
.map(id -> "<at id=" + id + "></at>")
.collect(Collectors.joining(" "));
}
if (notificationContent.startsWith("\"") && notificationContent.endsWith("\"")) {
notificationContent = StringUtils.removeStart(notificationContent, "\"");
notificationContent = StringUtils.removeEnd(notificationContent, "\"");
}
return String.format(larkCardMessage,
notificationContent.replace("\"", "\\\"") + atUserElement,
alerterProperties.getConsoleUrl(), TITLE_COLOR[priority]);
}
@Override
public byte type() {
return 6;
}
}
@@ -15,16 +15,16 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.alerter.impl;
package org.apache.hertzbeat.alert.notice.impl;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.manager.support.exception.AlertNoticeException;
import org.apache.hertzbeat.alert.notice.AlertNoticeException;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -49,7 +49,7 @@ public class GotifyAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl
* @throws AlertNoticeException when send receiver error
*/
@Override
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, Alert alert) throws AlertNoticeException {
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) throws AlertNoticeException {
try {
GotifyWebHookDto gotifyWebHookDto = new GotifyWebHookDto();
gotifyWebHookDto.setTitle(bundle.getString("alerter.notify.title"));
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.alerter.impl;
package org.apache.hertzbeat.alert.notice.impl;
import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.smn.v2.SmnClient;
@@ -27,11 +27,11 @@ import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.alert.notice.AlertNoticeException;
import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.common.util.ResourceBundleUtil;
import org.apache.hertzbeat.manager.support.exception.AlertNoticeException;
import org.springframework.stereotype.Component;
/**
@@ -40,13 +40,15 @@ import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
@Slf4j
@Deprecated
final class HuaweiCloudSmnAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl {
private final ResourceBundle bundle = ResourceBundleUtil.getBundle("alerter");
private final Map<String, SmnClient> smnClientMap = new ConcurrentHashMap<>();
@Override
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, Alert alert) {
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) {
// todo use rest api not sdk
try {
var smnClient = getSmnClient(receiver);
var request = new PublishMessageRequest()

Some files were not shown because too many files have changed in this diff Show More