(webhook *models.Webhook, event interface{}, stats *astats.Stats)
| 61 | } |
| 62 | |
| 63 | func sendWebhook(webhook *models.Webhook, event interface{}, stats *astats.Stats) (bool, string, error) { |
| 64 | channel := "webhook" |
| 65 | if webhook.Type == models.RuleCallback { |
| 66 | channel = "callback" |
| 67 | } |
| 68 | |
| 69 | conf := webhook |
| 70 | if conf.Url == "" || !conf.Enable { |
| 71 | return false, "", nil |
| 72 | } |
| 73 | bs, err := json.Marshal(event) |
| 74 | if err != nil { |
| 75 | logger.Errorf("%s alertingWebhook failed to marshal event:%+v err:%v", channel, event, err) |
| 76 | return false, "", err |
| 77 | } |
| 78 | |
| 79 | bf := bytes.NewBuffer(bs) |
| 80 | |
| 81 | req, err := http.NewRequest("POST", conf.Url, bf) |
| 82 | if err != nil { |
| 83 | logger.Warningf("%s alertingWebhook failed to new request event:%s err:%v", channel, string(bs), err) |
| 84 | return true, "", err |
| 85 | } |
| 86 | |
| 87 | req.Header.Set("Content-Type", "application/json") |
| 88 | if conf.BasicAuthUser != "" && conf.BasicAuthPass != "" { |
| 89 | req.SetBasicAuth(conf.BasicAuthUser, conf.BasicAuthPass) |
| 90 | } |
| 91 | |
| 92 | if len(conf.Headers) > 0 && len(conf.Headers)%2 == 0 { |
| 93 | for i := 0; i < len(conf.Headers); i += 2 { |
| 94 | if conf.Headers[i] == "host" || conf.Headers[i] == "Host" { |
| 95 | req.Host = conf.Headers[i+1] |
| 96 | continue |
| 97 | } |
| 98 | req.Header.Set(conf.Headers[i], conf.Headers[i+1]) |
| 99 | } |
| 100 | } |
| 101 | // 使用全局 Client 缓存,避免每次请求都创建新的 Client 导致连接泄露 |
| 102 | client := getWebhookClient(conf) |
| 103 | |
| 104 | stats.AlertNotifyTotal.WithLabelValues(channel).Inc() |
| 105 | var resp *http.Response |
| 106 | var body []byte |
| 107 | resp, err = client.Do(req) |
| 108 | |
| 109 | if err != nil { |
| 110 | stats.AlertNotifyErrorTotal.WithLabelValues(channel).Inc() |
| 111 | logger.Errorf("event_%s_fail, event:%s, url: [%s], error: [%s]", channel, string(bs), conf.Url, err) |
| 112 | return true, "", err |
| 113 | } |
| 114 | |
| 115 | if resp.Body != nil { |
| 116 | defer resp.Body.Close() |
| 117 | body, _ = io.ReadAll(resp.Body) |
| 118 | } |
| 119 | |
| 120 | if resp.StatusCode == 429 { |
no test coverage detected