Skip to content

Commit 91f4565

Browse files
committed
增加邮件、Slack、WebHook通知
1 parent 5d1c717 commit 91f4565

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+6848
-1
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@
1212

1313
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
1414
.glide/
15+
.idear

Diff for: README.md

+79-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,80 @@
1-
# supervisor-listener
1+
# supervisor-event-listener
22
Supervisor事件通知, 支持邮件, Slack, WebHook
3+
4+
## 简介
5+
Supervisor是*nix环境下的进程管理工具, 可以把前台进程转换为守护进程, 当进程异常退出时自动重启.
6+
supervisor-event-listener监听进程异常退出事件, 并发送通知.
7+
8+
## 下载
9+
* [Linux-64位](http://opns468ov.bkt.clouddn.com/supervisor/supervisor-event-listener-linux-amd64.tar.gz)
10+
* [Mac OS-64位](http://opns468ov.bkt.clouddn.com/supervisor/supervisor-event-listener-darwin-amd64.tar.gz)
11+
12+
### 源码安装
13+
* `go get -u github.com/ouqiang/supervisor-event-listener`
14+
15+
## Supervisor配置
16+
```ini
17+
[eventlistener:supervisor-event-listener]
18+
; 默认读取配置文件/etc/supervisor-event-listener.ini
19+
command=/path/to/supervisor-event-listener
20+
; 指定配置文件路径
21+
;command=/path/to/supervisor-event-listener -c /path/to/supervisor-event-listener.ini
22+
events=PROCESS_STATE_EXITED
23+
......
24+
```
25+
26+
## 配置文件, 默认读取`/etc/supervisor-event-listener.ini`
27+
28+
```ini
29+
[default]
30+
# 通知类型 mail,slack,webhook 只能选择一种
31+
notify_type = mail
32+
33+
# 邮件服务器配置
34+
mail.server.user = [email protected]
35+
mail.server.password = 123456
36+
mail.server.host = smtp.163.com
37+
mail.server.port = 25
38+
39+
# 邮件收件人配置, 多个收件人, 逗号分隔
40+
mail.user = [email protected]
41+
42+
# Slack配置
43+
slack.webhook_url = https://hooks.slack.com/services/xxxx/xxx/xxxx
44+
slack.channel = exception
45+
46+
# WebHook通知URL配置
47+
webhook_url = http://my.webhook.com
48+
49+
```
50+
51+
## 通知内容
52+
邮件、Slack
53+
```shell
54+
Host: ip(hostname)
55+
Process: process-name
56+
PID: 6152
57+
EXITED FROM state: RUNNING
58+
```
59+
WebHook, Post请求, 字段含义查看Supervisor文档
60+
```json
61+
{
62+
"Header": {
63+
"Ver": "3.0",
64+
"Server": "supervisor",
65+
"Serial": 11,
66+
"Pool": "supervisor-listener",
67+
"PoolSerial": 11,
68+
"EventName": "PROCESS_STATE_EXITED",
69+
"Len": 84
70+
},
71+
"Payload": {
72+
"Ip": "ip(hostname)",
73+
"ProcessName": "process-name",
74+
"GroupName": "group-name",
75+
"FromState": "RUNNING",
76+
"Expected": 0,
77+
"Pid": 6371
78+
}
79+
}
80+
```

Diff for: build.sh

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/env bash
2+
3+
# set -x -u
4+
# 构建应用, supervisor-event-listener.tar.gz
5+
# ./build.sh -p linux -a amd64
6+
# 参数含义
7+
# -p 指定平台(linux|darwin)
8+
# -a 指定体系架构(amd64|386), 默认amd64
9+
10+
11+
TEMP_DIR=`date +%s`-temp-`echo $RANDOM`
12+
13+
# 目标平台 linux,darwin
14+
OS=''
15+
# 目标平台架构
16+
ARCH=''
17+
# 应用名称
18+
APP_NAME='supervisor-event-listener'
19+
# 可执行文件名
20+
EXEC_NAME=''
21+
# 压缩包名称
22+
COMPRESS_FILE=''
23+
24+
25+
# -p 平台 -a 架构
26+
while getopts "p:a:" OPT;
27+
do
28+
case $OPT in
29+
p) OS=$OPTARG
30+
;;
31+
a) ARCH=$OPTARG
32+
;;
33+
esac
34+
done
35+
36+
if [[ -z $OS ]];then
37+
echo "平台不能为空"
38+
exit 1
39+
fi
40+
41+
if [[ $OS && $OS != 'linux' && $OS != 'darwin' ]];then
42+
echo '平台错误,支持的平台 linux darmin(osx)'
43+
exit 1
44+
fi
45+
46+
if [[ -z $ARCH ]];then
47+
ARCH='amd64'
48+
fi
49+
50+
if [[ $ARCH != '386' && $ARCH != 'amd64' ]];then
51+
echo 'arch错误,仅支持 386 amd64'
52+
exit 1
53+
fi
54+
55+
echo '开始编译'
56+
57+
GOOS=$OS GOARCH=$ARCH go build -ldflags '-w'
58+
59+
if [[ $? != 0 ]];then
60+
exit 1
61+
fi
62+
echo '编译完成'
63+
64+
65+
EXEC_NAME=${APP_NAME}
66+
COMPRESS_FILE=${APP_NAME}-${OS}-${ARCH}.tar.gz
67+
68+
mkdir -p $TEMP_DIR/$APP_NAME
69+
if [[ $? != 0 ]]; then
70+
exit 1
71+
fi
72+
73+
# 需要打包的文件
74+
PACKAGE_FILENAME=(supervisor-event-listener.ini ${EXEC_NAME})
75+
76+
echo '复制文件到临时目录'
77+
# 复制文件到临时目录
78+
for i in ${PACKAGE_FILENAME[*]}
79+
do
80+
cp -r $i $TEMP_DIR/$APP_NAME
81+
done
82+
83+
84+
echo '压缩文件'
85+
# 压缩文件
86+
cd $TEMP_DIR
87+
88+
tar czf $COMPRESS_FILE *
89+
mv $COMPRESS_FILE ../
90+
cd ../
91+
92+
rm $EXEC_NAME
93+
rm -rf $TEMP_DIR
94+
95+
echo '打包完成'
96+
echo '生成压缩文件--' $COMPRESS_FILE

Diff for: config/config.go

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package config
2+
3+
import (
4+
"flag"
5+
"strings"
6+
"fmt"
7+
"os"
8+
"gopkg.in/ini.v1"
9+
"github.com/ouqiang/supervisor-event-listener/utils"
10+
)
11+
12+
type Config struct {
13+
NotifyType string
14+
WebHook WebHook
15+
MailServer MailServer
16+
MailUser MailUser
17+
Slack Slack
18+
}
19+
20+
type WebHook struct {
21+
Url string
22+
}
23+
24+
type Slack struct {
25+
WebHookUrl string
26+
Channel string
27+
}
28+
29+
// 邮件服务器
30+
type MailServer struct {
31+
User string
32+
Password string
33+
Host string
34+
Port int
35+
}
36+
37+
// 接收邮件的用户
38+
type MailUser struct {
39+
Email []string
40+
}
41+
42+
func ParseConfig() *Config {
43+
var configFile string
44+
flag.StringVar(&configFile, "c", "/etc/supervisor-event-listener.ini", "config file")
45+
flag.Parse()
46+
configFile = strings.TrimSpace(configFile)
47+
if configFile == "" {
48+
Exit("请指定配置文件路径")
49+
}
50+
file, err := ini.Load(configFile)
51+
if err != nil {
52+
Exit("读取配置文件失败#" + err.Error())
53+
}
54+
section := file.Section("default")
55+
notifyType := section.Key("notify_type").String()
56+
notifyType = strings.TrimSpace(notifyType)
57+
if !utils.InStringSlice([]string{"mail", "slack", "webhook"}, notifyType) {
58+
Exit("不支持的通知类型-" + notifyType)
59+
}
60+
61+
config := &Config{}
62+
config.NotifyType = notifyType
63+
switch notifyType {
64+
case "mail":
65+
config.MailServer = parseMailServer(section)
66+
config.MailUser = parseMailUser(section)
67+
case "slack":
68+
config.Slack = parseSlack(section)
69+
case "webhook":
70+
config.WebHook = parseWebHook(section)
71+
}
72+
73+
return config
74+
}
75+
76+
func parseMailServer(section *ini.Section) MailServer {
77+
user := section.Key("mail.server.user").String()
78+
user = strings.TrimSpace(user)
79+
password := section.Key("mail.server.password").String()
80+
password = strings.TrimSpace(password)
81+
host := section.Key("mail.server.host").String()
82+
host = strings.TrimSpace(host)
83+
port, portErr := section.Key("mail.server.port").Int()
84+
if user == "" || password == "" || host == "" || portErr != nil {
85+
Exit("邮件服务器配置错误")
86+
}
87+
88+
mailServer := MailServer{}
89+
mailServer.User = user
90+
mailServer.Password = password
91+
mailServer.Host = host
92+
mailServer.Port = port
93+
94+
return mailServer
95+
}
96+
97+
func parseMailUser(section *ini.Section) MailUser {
98+
user := section.Key("mail.user").String()
99+
user = strings.TrimSpace(user)
100+
if user == "" {
101+
Exit("邮件收件人配置错误")
102+
}
103+
mailUser := MailUser{}
104+
mailUser.Email = strings.Split(user, ",")
105+
106+
return mailUser
107+
}
108+
109+
110+
func parseSlack(section *ini.Section) Slack {
111+
webHookUrl := section.Key("slack.webhook_url").String()
112+
webHookUrl = strings.TrimSpace(webHookUrl)
113+
channel := section.Key("slack.channel").String()
114+
channel = strings.TrimSpace(channel)
115+
if webHookUrl == "" || channel == "" {
116+
Exit("Slack配置错误")
117+
}
118+
119+
slack := Slack{}
120+
slack.WebHookUrl = webHookUrl
121+
slack.Channel = channel
122+
123+
return slack
124+
}
125+
126+
func parseWebHook(section *ini.Section) WebHook {
127+
url := section.Key("webhook_url").String()
128+
url = strings.TrimSpace(url)
129+
if url == "" {
130+
Exit("WebHookUrl配置错误")
131+
}
132+
webHook := WebHook{}
133+
webHook.Url = url
134+
135+
136+
return webHook
137+
}
138+
139+
func Exit(msg string) {
140+
fmt.Fprintln(os.Stderr, msg)
141+
os.Exit(1)
142+
}

0 commit comments

Comments
 (0)