Skip to content

Commit f7c08f1

Browse files
committed
feat: add feishu notice
1 parent 755d245 commit f7c08f1

File tree

1 file changed

+153
-21
lines changed

1 file changed

+153
-21
lines changed

python/supervisor_healthCheck.py

+153-21
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import platform
2222
import threading
2323
import subprocess
24+
import hmac
25+
from hashlib import sha256
2426
from email.header import Header
2527
from email.mime.text import MIMEText
2628
from collections import namedtuple
@@ -69,15 +71,16 @@ def shell(cmd):
6971
proc.wait()
7072
return (proc.returncode,) + proc.communicate()
7173

74+
7275
def drop_cache():
7376
"""
7477
清除缓存, 1: pagecache, 2: dentries and inodes, 3: 1+2
7578
"""
7679
cmd = "sync && echo 1 > /proc/sys/vm/drop_caches"
7780
exitcode, _, _ = shell(cmd)
78-
7981
return exitcode
8082

83+
8184
def get_proc_cpu(pid):
8285
"""
8386
获取进程CPU使用率
@@ -98,6 +101,7 @@ def get_proc_cpu(pid):
98101
return None
99102
return cpu_utilization
100103

104+
101105
def get_proc_mem(pid, type="rss"):
102106
"""
103107
获取进程内存使用
@@ -170,12 +174,14 @@ def __init__(self, config):
170174
self.mail_config = None
171175
self.wechat_config = None
172176
self.dingding_config = None
177+
self.feishu_config = None
173178
self.supervisord_url = 'unix:///var/run/supervisor.sock'
174179

175180
if 'config' in config:
176181
self.mail_config = config['config'].get('mail')
177182
self.wechat_config = config['config'].get('wechat')
178183
self.dingding_config = config['config'].get('dingding')
184+
self.feishu_config = config['config'].get('feishu')
179185
self.supervisord_url = config['config'].get('supervisordUrl', self.supervisord_url)
180186
self.supervisord_user = config['config'].get('supervisordUser', None)
181187
self.supervisord_pass = config['config'].get('supervisordPass', None)
@@ -184,7 +190,7 @@ def __init__(self, config):
184190
self.program_config = config
185191

186192
# 只保留通知action
187-
self.notice_action = ['email', 'wechat', 'dingding']
193+
self.notice_action = ['email', 'wechat', 'dingding', 'feishu']
188194

189195
self.periodSeconds = 5
190196
self.failureThreshold = 3
@@ -516,24 +522,26 @@ def action(self, program, **args):
516522

517523
if 'restart' in action_list:
518524
restart_result = self.action_supervisor_restart(program)
519-
msg += '\r\n Restart:%s' % restart_result
525+
msg += '\r\n**Restart**:%s' % restart_result
520526
elif 'exec' in action_list:
521527
action_exec_cmd = config.get('action_exec_cmd')
522528
exec_result = self.action_exec(program, action_exec_cmd)
523-
msg += '\r\n Exec:%s' % exec_result
529+
msg += '\r\n**Exec**:%s' % exec_result
524530
elif 'kill' in action_list:
525531
pid_get = config.get('pidGet', 'supervisor')
526532
pid_file = config.get('pidFile', )
527533
pid, err = self.get_pid(program, pid_get, pid_file)
528534
kill_result = self.action_kill(program, pid)
529-
msg += '\r\n Kill:%s' % kill_result
535+
msg += '\r\n**Kill**:%s' % kill_result
530536

531537
if 'email' in action_list and self.mail_config:
532538
self.action_email(program, action_type, msg, check_status)
533539
if 'wechat' in action_list and self.wechat_config:
534540
self.action_wechat(program, action_type, msg, check_status)
535541
if 'dingding' in action_list and self.dingding_config:
536542
self.action_dingding(program, action_type, msg, check_status)
543+
if 'feishu' in action_list and self.feishu_config:
544+
self.action_feishu(program, action_type, msg, check_status)
537545

538546
def action_supervisor_restart(self, program):
539547
"""
@@ -710,6 +718,7 @@ def action_wechat(self, program, action_type, msg, check_status):
710718
}
711719

712720
access_token_url = '/cgi-bin/gettoken?corpid={id}&corpsecret={crt}'.format(id=corpid, crt=secret)
721+
713722
try:
714723
httpClient = httplib.HTTPSConnection(host, timeout=10)
715724
httpClient.request("GET", access_token_url, headers=headers)
@@ -806,13 +815,14 @@ def action_dingding(self, program, action_type, msg, check_status):
806815
else:
807816
title = "[%s] Health check failed" % program
808817

809-
data = {"msgtype": "markdown",
810-
"markdown": {
811-
"title": title,
812-
"text": "#### 详情信息: \n> Program:%s \n\n> DataTime: %s \n\n> Hostname: %s \n\n> Platfrom: %s \n\n> Msg:%s" % (
813-
program, curr_dt, hostname, system_platform, msg)
814-
}
815-
}
818+
data = {
819+
"msgtype": "markdown",
820+
"markdown": {
821+
"title": title,
822+
"text": "#### 详情信息: \n> Program:%s \n\n> DataTime: %s \n\n> Hostname: %s \n\n> Platfrom: %s \n\n> Msg:%s" % (
823+
program, curr_dt, hostname, system_platform, msg)
824+
}
825+
}
816826

817827
try:
818828
httpClient = httplib.HTTPSConnection(host, timeout=10)
@@ -832,6 +842,125 @@ def action_dingding(self, program, action_type, msg, check_status):
832842
self.log(program, '[Action: dingding] send success')
833843
return True
834844

845+
def action_feishu(self, program, action_type, msg, check_status):
846+
"""
847+
飞书通知
848+
:param program:
849+
:param action_type:
850+
:param msg:
851+
:param check_status:
852+
:return:
853+
"""
854+
host = "open.feishu.cn"
855+
856+
secret = self.feishu_config.get('secret')
857+
webhook = self.feishu_config.get('webhook')
858+
859+
headers = {
860+
'Content-Type': 'application/json'
861+
}
862+
send_url = "/open-apis/bot/v2/hook/{webhook}".format(webhook=webhook)
863+
864+
ip = ""
865+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
866+
try:
867+
s.connect(('8.8.8.8', 80))
868+
ip = s.getsockname()[0]
869+
except Exception as e:
870+
self.log(program, '[Action: feishu] get ip error %s' % e)
871+
finally:
872+
s.close()
873+
874+
hostname = platform.node().split('.')[0]
875+
system_platform = platform.platform()
876+
877+
curr_dt = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
878+
879+
if check_status == 'success':
880+
title = "[Supervisor] %s Health check successful" % program
881+
title_color = "green"
882+
else:
883+
title = "[Supervisor] %s Health check failed" % program
884+
title_color = "red"
885+
886+
content = "**DataTime**: {curr_dt}\n**Program**: {program}\n**IP**: {ip}\n**Hostname**: {hostname}\n**Platfrom**: {platfrom}\n**Action**: {action}\n**Msg**: {msg}".format(
887+
curr_dt=curr_dt, program=program, ip=ip, hostname=hostname,
888+
platfrom=system_platform, action=action_type, msg=msg)
889+
890+
data = {
891+
"msg_type": "interactive",
892+
"card": {
893+
"config": {
894+
"wide_screen_mode": True,
895+
"enable_forward": True
896+
},
897+
"header": {
898+
"title": {
899+
"content": title,
900+
"tag": "plain_text"
901+
},
902+
"template": title_color
903+
},
904+
"elements": [{
905+
"tag": "div",
906+
"text": {
907+
"content": "详细信息:",
908+
"tag": "lark_md"
909+
},
910+
"fields": [
911+
{
912+
"is_short": False,
913+
"text": {
914+
"tag": "lark_md",
915+
"content": content
916+
}
917+
}]
918+
919+
}]
920+
921+
}
922+
}
923+
924+
if secret != "":
925+
926+
msg = ""
927+
timestamp = ""
928+
if PY3:
929+
timestamp = str(round(time.time()))
930+
key = '{}\n{}'.format(timestamp, secret)
931+
key_enc = key.encode('utf-8')
932+
msg_enc = msg.encode('utf-8')
933+
else:
934+
print("python2")
935+
timestamp = long(round(time.time()))
936+
key = '{}\n{}'.format(timestamp, secret)
937+
key_enc = bytes(key).encode('utf-8')
938+
msg_enc = bytes(msg).encode('utf-8')
939+
940+
hmac_code = hmac.new(key_enc, msg_enc, digestmod=sha256).digest()
941+
sign = base64.b64encode(hmac_code).decode('utf-8')
942+
data['timestamp'] = timestamp
943+
data['sign'] = sign
944+
print(data)
945+
946+
httpClient = httplib.HTTPSConnection(host, timeout=10)
947+
try:
948+
httpClient.request("POST", send_url, json.dumps(data), headers=headers)
949+
response = httpClient.getresponse()
950+
result = json.loads(response.read())
951+
if result.get('StatusCode', 1) != 0:
952+
self.log(program, '[Action: feishu] send faild %s' % result)
953+
return False
954+
except Exception as e:
955+
self.log(program, '[Action: feishu] send error [%s] %s' % (result, e))
956+
return False
957+
finally:
958+
if httpClient:
959+
httpClient.close()
960+
961+
self.log(program, '[Action: feishu] send success')
962+
return True
963+
835964
def start(self):
836965
"""
837966
启动检测
@@ -900,7 +1029,10 @@ def sig_handler(signum, frame):
9001029
# totag:
9011030
# dingding: # 钉钉通知配置
9021031
access_token:
903-
1032+
# feishu: # 飞书通知配置
1033+
webhook:
1034+
secret:
1035+
9041036
# 内存方式监控
9051037
cat1: # supervisor中配置的program名称
9061038
type: mem # 检查类型: http,tcp,mem,cpu 默认: http
@@ -912,9 +1044,9 @@ def sig_handler(signum, frame):
9121044
initialDelaySeconds: 10 # 首次检查等待的时间(以秒为单位), 默认: 1
9131045
failureThreshold: 3 # 检查成功后,最少连续检查失败多少次才被认定为失败, 默认: 3
9141046
successThreshold: 2 # 失败后检查成功的最小连续成功次数, 默认:1
915-
action: restart,email # 触发的动作: restart,exec,kill,email,wechat (restart和exec互斥,同时设置时restart生效) 默认: restart
1047+
action: restart,email # 触发的动作: restart,exec,kill,email,wechat,dingding,feishu (restart,exec,kill互斥,同时设置时restart生效) 默认: restart
9161048
execCmd: command # action exec 的执行命令
917-
sendResolved: True # 是否发送恢复通知,仅用作于email,wechat. 默认: False
1049+
sendResolved: True # 是否发送恢复通知 默认: False
9181050
9191051
# cpu方式监控
9201052
cat2: # supervisor中配置的program名称
@@ -926,9 +1058,9 @@ def sig_handler(signum, frame):
9261058
initialDelaySeconds: 10 # 首次检查等待的时间(以秒为单位), 默认: 1
9271059
failureThreshold: 3 # 检查成功后,最少连续检查失败多少次才被认定为失败, 默认: 3
9281060
successThreshold: 2 # 失败后检查成功的最小连续成功次数, 默认:1
929-
action: restart,email # 触发的动作: restart,exec,kill,email,wechat (restart和exec互斥,同时设置时restart生效) 默认: restart
1061+
action: restart,email # 触发的动作: restart,exec,kill,email,wechat,dingding,feishu (restart,exec,kill互斥,同时设置时restart生效) 默认: restart
9301062
execCmd: command # action exec 的执行命令
931-
sendResolved: True # 是否发送恢复通知,仅用作于email,wechat. 默认: False
1063+
sendResolved: True # 是否发送恢复通知 默认: False
9321064
9331065
# HTTP方式监控
9341066
cat3:
@@ -946,9 +1078,9 @@ def sig_handler(signum, frame):
9461078
timeoutSeconds: 5 # 检查超时的秒数, 默认: 3
9471079
failureThreshold: 3 # 检查成功后,最少连续检查失败多少次才被认定为失败, 默认: 3
9481080
successThreshold: 2 # 失败后检查成功的最小连续成功次数, 默认:1
949-
action: restart,email # 触发的动作: restart,exec,kill,email,wechat (restart和exec互斥,同时设置时restart生效) 默认: restart
1081+
action: restart,email # 触发的动作: restart,exec,kill,email,wechat,dingding,feishu (restart,exec,kill互斥,同时设置时restart生效) 默认: restart
9501082
execCmd: command # action exec 的执行命令
951-
sendResolved: True # 是否发送恢复通知,仅用作于email,wechat. 默认: False
1083+
sendResolved: True # 是否发送恢复通知 默认: False
9521084
9531085
# TCP方式监控
9541086
cat4:
@@ -960,9 +1092,9 @@ def sig_handler(signum, frame):
9601092
timeoutSeconds: 5 # 检查超时的秒数, 默认: 3
9611093
failureThreshold: 3 # 检查成功后,最少连续检查失败多少次才被认定为失败, 默认: 3
9621094
successThreshold: 2 # 失败后检查成功的最小连续成功次数, 默认:1
963-
action: restart,email # 触发的动作: restart,exec,kill,email,wechat (restart和exec互斥,同时设置时restart生效) 默认: restart
1095+
action: restart,email # 触发的动作: restart,exec,kill,email,wechat,dingding,feishu (restart,exec,kill互斥,同时设置时restart生效) 默认: restart
9641096
execCmd: command # action exec 的执行命令
965-
sendResolved: True # 是否发送恢复通知,仅用作于email,wechat. 默认: False
1097+
sendResolved: True # 是否发送恢复通知 默认: False
9661098
"""
9671099
with open(config_file, 'w') as f:
9681100
f.write(example_config)

0 commit comments

Comments
 (0)