Browse Source

Move feishucard (#1563)

* Fix an exception situation where the prod and cate fields cannot be updated.

* add feishucard.tpl

* move feishucard to v6

---------

Co-authored-by: shardingHe <wangzihe@flashcat.cloud>
tags/v6.0.0-ga12
shardingHe GitHub 3 years ago
parent
commit
c730eaa860
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 180 additions and 8 deletions
  1. +7
    -6
      alert/dispatch/dispatch.go
  2. +151
    -0
      alert/sender/feishucard.go
  3. +2
    -0
      alert/sender/sender.go
  4. +17
    -0
      etc/template/feishucard.tpl
  5. +1
    -1
      models/notify_tpl.go
  6. +2
    -1
      models/user.go

+ 7
- 6
alert/dispatch/dispatch.go View File

@@ -83,12 +83,13 @@ func (e *Dispatch) relaodTpls() error {
smtp := e.notifyConfigCache.GetSMTP()

senders := map[string]sender.Sender{
models.Email: sender.NewSender(models.Email, tmpTpls, smtp),
models.Dingtalk: sender.NewSender(models.Dingtalk, tmpTpls, smtp),
models.Wecom: sender.NewSender(models.Wecom, tmpTpls, smtp),
models.Feishu: sender.NewSender(models.Feishu, tmpTpls, smtp),
models.Mm: sender.NewSender(models.Mm, tmpTpls, smtp),
models.Telegram: sender.NewSender(models.Telegram, tmpTpls, smtp),
models.Email: sender.NewSender(models.Email, tmpTpls, smtp),
models.Dingtalk: sender.NewSender(models.Dingtalk, tmpTpls, smtp),
models.Wecom: sender.NewSender(models.Wecom, tmpTpls, smtp),
models.Feishu: sender.NewSender(models.Feishu, tmpTpls, smtp),
models.Mm: sender.NewSender(models.Mm, tmpTpls, smtp),
models.Telegram: sender.NewSender(models.Telegram, tmpTpls, smtp),
models.Feishucard: sender.NewSender(models.Feishucard, tmpTpls, smtp),
}

e.RwLock.RLock()


+ 151
- 0
alert/sender/feishucard.go View File

@@ -0,0 +1,151 @@
package sender

import (
"fmt"
"html/template"
"strings"
"time"

"github.com/ccfos/nightingale/v6/models"
"github.com/ccfos/nightingale/v6/pkg/poster"

"github.com/toolkits/pkg/logger"
)

type Conf struct {
WideScreenMode bool `json:"wide_screen_mode"`
EnableForward bool `json:"enable_forward"`
}

type Te struct {
Content string `json:"content"`
Tag string `json:"tag"`
}

type Element struct {
Tag string `json:"tag"`
Text Te `json:"text"`
Content string `json:"content"`
Elements []Element `json:"elements"`
}

type Titles struct {
Content string `json:"content"`
Tag string `json:"tag"`
}

type Headers struct {
Title Titles `json:"title"`
Template string `json:"template"`
}

type Cards struct {
Config Conf `json:"config"`
Elements []Element `json:"elements"`
Header Headers `json:"header"`
}

type feishuCard struct {
feishu
Card Cards `json:"card"`
}

type FeishucardSender struct {
tpl *template.Template
}

const (
Recovered = "recovered"
Triggered = "triggered"
)

var (
//regRecovered ,regTriggered = regexp.MustCompile(Recovered) regexp.MustCompile(Triggered)
body = feishuCard{
feishu: feishu{Msgtype: "interactive"},
Card: Cards{
Config: Conf{
WideScreenMode: true,
EnableForward: true,
},
Header: Headers{
Title: Titles{
//Content: SendTitle,
Tag: "plain_text",
},
//Template: color,
},
Elements: []Element{
Element{
Tag: "div",
Text: Te{
//Content: message,
Tag: "lark_md",
},
},
{
Tag: "hr",
},
{
Tag: "note",
Elements: []Element{
{
//Content: SendTitle,
Tag: "lark_md",
},
},
},
},
},
}
)

func (fs *FeishucardSender) Send(ctx MessageContext) {
if len(ctx.Users) == 0 || ctx.Rule == nil || ctx.Event == nil {
return
}
urls, _ := fs.extract(ctx.Users)
message := BuildTplMessage(fs.tpl, ctx.Event)
color := "red"
lowerUnicode := strings.ToLower(message)
switch {
case strings.Count(lowerUnicode, Recovered) > 0 && strings.Count(lowerUnicode, Triggered) > 0:
//case len(regRecovered.FindAllStringIndex(lowerUnicode, -1))>0 && len(regTriggered.FindAllStringIndex(lowerUnicode, -1)) > 0:
color = "orange"
case strings.Count(lowerUnicode, Recovered) > 0:
color = "green"
default:
}
SendTitle := fmt.Sprintf("🔔 [告警提醒] - %s", ctx.Event.RuleName)
body.Card.Header.Title.Content = SendTitle
body.Card.Header.Template = color
body.Card.Elements[0].Text.Content = message
body.Card.Elements[2].Elements[0].Content = SendTitle
for _, url := range urls {
fs.doSend(url, body)
}
}

func (fs *FeishucardSender) extract(users []*models.User) ([]string, []string) {
urls := make([]string, 0, len(users))
ats := make([]string, 0)
for i := range users {
if token, has := users[i].ExtractToken(models.Feishucard); has {
url := token
if !strings.HasPrefix(token, "https://") {
url = "https://open.feishu.cn/open-apis/bot/v2/hook/" + strings.TrimSpace(token)
}
urls = append(urls, url)
}
}
return urls, ats
}

func (fs *FeishucardSender) doSend(url string, body feishuCard) {
res, code, err := poster.PostJSON(url, time.Second*5, body, 3)
if err != nil {
logger.Errorf("feishucard_sender: result=fail url=%s code=%d error=%v response=%s", url, code, err, string(res))
} else {
logger.Debugf("feishucard_sender: result=succ url=%s code=%d response=%s", url, code, string(res))
}
}

+ 2
- 0
alert/sender/sender.go View File

@@ -31,6 +31,8 @@ func NewSender(key string, tpls map[string]*template.Template, smtp aconf.SMTPCo
return &WecomSender{tpl: tpls[models.Wecom]}
case models.Feishu:
return &FeishuSender{tpl: tpls[models.Feishu]}
case models.Feishucard:
return &FeishucardSender{tpl: tpls[models.Feishucard]}
case models.Email:
return &EmailSender{subjectTpl: tpls["mailsubject"], contentTpl: tpls[models.Email], smtp: smtp}
case models.Mm:


+ 17
- 0
etc/template/feishucard.tpl View File

@@ -0,0 +1,17 @@
{{ if .IsRecovered }}
{{- if ne .Cate "host"}}
**告警集群:** {{.Cluster}}{{end}}
**级别状态:** S{{.Severity}} Recovered
**告警名称:** {{.RuleName}}
**恢复时间:** {{timeformat .LastEvalTime}}
**告警描述:** **服务已恢复**
{{- else }}
{{- if ne .Cate "host"}}
**告警集群:** {{.Cluster}}{{end}}
**级别状态:** S{{.Severity}} Triggered
**告警名称:** {{.RuleName}}
**触发时间:** {{timeformat .TriggerTime}}
**发送时间:** {{timestamp}}
**触发时值:** {{.TriggerValue}}
{{if .RuleNote }}**告警描述:** **{{.RuleNote}}**{{end}}
{{- end -}}

+ 1
- 1
models/notify_tpl.go View File

@@ -107,7 +107,7 @@ func InitNotifyConfig(c *ctx.Context, tplDir string) {

if cval == "" {
var notifyChannels []NotifyChannel
channels := []string{Dingtalk, Wecom, Feishu, Mm, Telegram, Email}
channels := []string{Dingtalk, Wecom, Feishu, Mm, Telegram, Email, Feishucard}
for _, channel := range channels {
notifyChannels = append(notifyChannels, NotifyChannel{Ident: channel, Name: channel, BuiltIn: true})
}


+ 2
- 1
models/user.go View File

@@ -23,6 +23,7 @@ const (
Dingtalk = "dingtalk"
Wecom = "wecom"
Feishu = "feishu"
Feishucard = "feishucard"
Mm = "mm"
Telegram = "telegram"
Email = "email"
@@ -607,7 +608,7 @@ func (u *User) ExtractToken(key string) (string, bool) {
case Wecom:
ret := gjson.GetBytes(bs, WecomKey)
return ret.String(), ret.Exists()
case Feishu:
case Feishu, Feishucard:
ret := gjson.GetBytes(bs, FeishuKey)
return ret.String(), ret.Exists()
case Mm:


Loading…
Cancel
Save