[#886] Feature: 提供一种go plugin 告警通知方式 (#887)

* [#886] Feature: 提供一种go plugin 告警通知方式

* fix: 移除下层并发
This commit is contained in:
Jeyrce.Lu 2022-03-20 10:27:17 +08:00 committed by GitHub
parent 46c60a32fd
commit 302cebbbec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 143 additions and 3 deletions

View File

@ -0,0 +1,9 @@
.phony: all
all: plugin
.phony: plugin
plugin:
export GOPROXY=http://goproxy.cn,direct
go build -buildmode=plugin -o notify.so notify.go

View File

@ -0,0 +1,35 @@
通过go plugin模式处理告警通知
---
相比于调用py脚本方式该方式一般无需考虑依赖问题
### (1) 编写动态链接库逻辑
```go
package main
type inter interface {
Descript() string
Notify([]byte)
}
// 0、Descript 可用于该插件在 server 中的描述
// 1、在 Notify 方法中实现要处理的自定义逻辑
```
实现以上接口的 `struct` 实例即为合法 `plugin`
### (2) 构建链接库
参考 `notify.go` 实现方式,执行 `make` 后可以看到生成一个 `notify.so` 链接文件,放到 n9e 对应项目位置即可
### (3) 更新 n9e 配置
```text
[Alerting.CallPlugin]
Enable = false
PluginPath = "./etc/script/notify.so"
# 注意此处caller必须在notify.so中作为变量暴露
Caller = "n9eCaller"
```

View File

@ -0,0 +1,45 @@
package main
import (
"fmt"
"time"
"github.com/tidwall/gjson"
)
// the caller can be called for alerting notify by complete this interface
type inter interface {
Descript() string
Notify([]byte)
}
// N9E complete
type N9EPlugin struct {
Name string
Description string
BuildAt string
}
func (n *N9EPlugin) Descript() string {
return fmt.Sprintf("%s: %s", n.Name, n.Description)
}
func (n *N9EPlugin) Notify(bs []byte) {
var channels = []string{
"dingtalk_robot_token",
"wecom_robot_token",
"feishu_robot_token",
}
for _, ch := range channels {
if ret := gjson.GetBytes(bs, ch); ret.Exists() {
fmt.Printf("do something...")
}
}
}
// will be loaded for alertingCall
var n9eCaller = N9EPlugin{
Name: "n9e",
Description: "演示告警通过动态链接库方式通知",
BuildAt: time.Now().Local().Format("2006/01/02 15:04:05"),
}

View File

@ -75,6 +75,12 @@ NotifyBuiltinEnable = true
Enable = false
ScriptPath = "./etc/script/notify.py"
[Alerting.CallPlugin]
Enable = false
# use a plugin via `go build -buildmode=plugin -o notify.so`
PluginPath = "./etc/script/notify.so"
Caller = "n9eCaller"
[Alerting.RedisPub]
Enable = false
# complete redis key: ${ChannelPrefix} + ${Cluster}
@ -211,4 +217,4 @@ MaxIdleConnsPerHost = 100
# KeepAlive = 30000
# MaxConnsPerHost = 0
# MaxIdleConns = 100
# MaxIdleConnsPerHost = 100
# MaxIdleConnsPerHost = 100

4
go.mod
View File

@ -23,7 +23,7 @@ require (
github.com/prometheus/client_golang v1.11.0
github.com/prometheus/common v0.26.0
github.com/prometheus/prometheus v2.5.0+incompatible
github.com/tidwall/gjson v1.14.0 // indirect
github.com/tidwall/gjson v1.14.0
github.com/toolkits/pkg v1.2.9
github.com/urfave/cli/v2 v2.3.0
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
@ -31,7 +31,7 @@ require (
google.golang.org/genproto v0.0.0-20211007155348-82e027067bd4 // indirect
google.golang.org/grpc v1.41.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gorm.io/driver/mysql v1.1.2
gorm.io/driver/postgres v1.1.1
gorm.io/gorm v1.21.15

View File

@ -139,6 +139,7 @@ type Alerting struct {
NotifyConcurrency int
NotifyBuiltinEnable bool
CallScript CallScript
CallPlugin CallPlugin
RedisPub RedisPub
Webhook Webhook
}
@ -148,6 +149,12 @@ type CallScript struct {
ScriptPath string
}
type CallPlugin struct {
Enable bool
PluginPath string
Caller string
}
type RedisPub struct {
Enable bool
ChannelPrefix string

View File

@ -9,6 +9,8 @@ import (
"net/http"
"os/exec"
"path"
"plugin"
"runtime"
"strings"
"time"
@ -119,6 +121,8 @@ func alertingRedisPub(bs []byte) {
func handleNotice(notice Notice, bs []byte) {
alertingCallScript(bs)
alertingCallPlugin(bs)
if !config.C.Alerting.NotifyBuiltinEnable {
return
}
@ -396,3 +400,37 @@ func alertingCallScript(stdinBytes []byte) {
logger.Infof("event_notify: exec %s output: %s", fpath, buf.String())
}
type Notifier interface {
Descript() string
Notify([]byte)
}
// call notify.so via golang plugin build
// ig. etc/script/notify/notify.so
func alertingCallPlugin(stdinBytes []byte) {
if runtime.GOOS == "windows" {
logger.Errorf("call notify plugin on unsupported os: %s", runtime.GOOS)
return
}
if !config.C.Alerting.CallPlugin.Enable {
return
}
p, err := plugin.Open(config.C.Alerting.CallPlugin.PluginPath)
if err != nil {
logger.Errorf("failed to open notify plugin: %v", err)
return
}
caller, err := p.Lookup(config.C.Alerting.CallPlugin.Caller)
if err != nil {
logger.Errorf("failed to load caller: %v", err)
return
}
notifier, ok := caller.(Notifier)
if !ok {
logger.Errorf("notifier interface not implemented): %v", err)
return
}
notifier.Notify(stdinBytes)
logger.Debugf("alertingCallPlugin done. %s", notifier.Descript())
}