1 介绍
上文 监控告警02–夜莺飞书告警-v4版本 中,笔者通过更改夜莺 v4 源码 src/modules/server/dingtalk/dingtalk.go 使其发送告警到飞书群。基于上文思路,现在可以在源码中新增 src/modules/server/feishu/ 模块,是夜莺server同时可以按需要使用钉钉和飞书告警模块。
2 方法
2.1 源码变动
-
新建 src/modules/server/feishu/feishu.go 文件,
参考src/modules/server/dingtalk/dingtalk.go 模块,将相关数据结构和函数参数调整即可。vim src/modules/server/feishu/feishu.go package feishu import ( "bytes" "encoding/json" "fmt" "io/ioutil" "net/http" ) type Result struct { ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` } type feishuReqData struct { Msgtype string `json:"msg_type"` Content *textContent `json:"content"` } type textContent struct { Text string `json:"text"` } // RobotSend robot发送信息 func RobotSend(tokenUser, sendContent string) error { url := "https://open.feishu.cn/open-apis/bot/v2/hook/" + tokenUser feishuReqData := new(feishuReqData) feishuReqData.Msgtype = "text" reqContent := new(textContent) reqContent.Text = sendContent feishuReqData.Content = reqContent content, err := json.Marshal(feishuReqData) if err != nil { return fmt.Errorf("feishu marshal req data err: %v", err) } data := bytes.NewReader(content) req, err := http.NewRequest("POST", url, data) if err != nil { return fmt.Errorf("feishu create new req err: %v", err) } req.Header.Set("Content-Type", "application/json") r, err := http.DefaultClient.Do(req) if err != nil { return fmt.Errorf("feishu do req err: %v", err) } defer r.Body.Close() resp, err := ioutil.ReadAll(r.Body) if err != nil { return fmt.Errorf("feishu read req body err: %v", err) } result := Result{} err = json.Unmarshal(resp, &result) if err != nil { return fmt.Errorf("feishu unmarshal req content err: %v", err) } if result.ErrCode != 0 { err = fmt.Errorf("feishu req return ErrCode = %d ErrMsg = %s", result.ErrCode, result.ErrMsg) } return err } //func main() { // ret := RobotSend("xxx-xxxx-xxxx-xxx-xxx", "This is a test") // fmt.Println(ret) //}
也可以直接添加package main,然后通过该文件测试飞书告警模块。
-
同步修改 src/modules/server/cron/sender_im.go
1 在该文件中导入package feishu
2 在 func sendIm(message *dataobj.Message) 的switch 中新增 case “feishu_robot”
3 新增 func sendImByFeishuRobot(message *dataobj.Message) 函数此处只copy修改部分内容
vim src/modules/server/cron/sender_im.go import ( "github.com/didi/nightingale/v4/src/modules/server/feishu" ...... ) func sendIm(message *dataobj.Message) { defer func() { <-ImWorkerChan }() switch Sender["im"].Way { case "api": sendImByAPI(message) case "shell": sendImByShell(message) case "wechat": sendImByWeChat(message) case "wechat_robot": sendImByWeChatRobot(message) case "dingtalk_robot": sendImByDingTalkRobot(message) case "feishu_robot": sendImByFeishuRobot(message) default: logger.Errorf("not support %s to send im, im: %+v", Sender["im"].Way, message) } } func sendImByFeishuRobot(message *dataobj.Message) { cnt := len(message.Tos) if cnt == 0 { logger.Warningf("im send feishu_robot fail, empty tos, message: %+v", message) return } set := make(map[string]struct{}, cnt) for i := 0; i < cnt; i++ { toUser := strings.TrimSpace(message.Tos[i]) if toUser == "" { continue } if _, ok := set[toUser]; !ok { set[toUser] = struct{}{} } } req := regexp.MustCompile("^1[0-9]{10}$") var atUser []string var tokenUser []string for user := range set { if req.MatchString(user) { atUser = append(atUser, user) } else { tokenUser = append(tokenUser, user) } } for _, u := range tokenUser { err := feishu.RobotSend(u, message.Content) if err != nil { logger.Warningf("im feishu_robot send to %s fail: %v", u, err) } else { logger.Infof("im feishu_robot send to %s succ", u) } } }
2.2 测试效果
- 编译二进制文件
在 src/modules/server 目录, go build server.go ,生成可执行文件 server - 覆盖已有的n9e-server 并更改im为 feishu_robot
替换原有的server,将 etc/server.yml 中的im 的way更改为feishu_robot ,然后重启server即可;cat server.yml |grep feishu -C 2 im: # five choice: shell|api|wechat|wechat_robot|dingtalk_robot way: feishu_robot worker: 10 api: http://127.0.0.1:2008/im
- 测试
临时配置一个 内存利用率大于40% 的告警,发现很快就触发告警了,即该模块生效了。