in notify/wechat/wechat.go [84:197]
func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
key, err := notify.ExtractGroupKey(ctx)
if err != nil {
return false, err
}
level.Debug(n.logger).Log("incident", key)
data := notify.GetTemplateData(ctx, n.tmpl, as, n.logger)
tmpl := notify.TmplText(n.tmpl, data, &err)
if err != nil {
return false, err
}
// Refresh AccessToken over 2 hours
if n.accessToken == "" || time.Since(n.accessTokenAt) > 2*time.Hour {
parameters := url.Values{}
parameters.Add("corpsecret", tmpl(string(n.conf.APISecret)))
parameters.Add("corpid", tmpl(string(n.conf.CorpID)))
if err != nil {
return false, fmt.Errorf("templating error: %w", err)
}
u := n.conf.APIURL.Copy()
u.Path += "gettoken"
u.RawQuery = parameters.Encode()
resp, err := notify.Get(ctx, n.client, u.String())
if err != nil {
return true, notify.RedactURL(err)
}
defer notify.Drain(resp)
var wechatToken token
if err := json.NewDecoder(resp.Body).Decode(&wechatToken); err != nil {
return false, err
}
if wechatToken.AccessToken == "" {
return false, fmt.Errorf("invalid APISecret for CorpID: %s", n.conf.CorpID)
}
// Cache accessToken
n.accessToken = wechatToken.AccessToken
n.accessTokenAt = time.Now()
}
msg := &weChatMessage{
ToUser: tmpl(n.conf.ToUser),
ToParty: tmpl(n.conf.ToParty),
Totag: tmpl(n.conf.ToTag),
AgentID: tmpl(n.conf.AgentID),
Type: n.conf.MessageType,
Safe: "0",
}
if msg.Type == "markdown" {
msg.Markdown = weChatMessageContent{
Content: tmpl(n.conf.Message),
}
} else {
msg.Text = weChatMessageContent{
Content: tmpl(n.conf.Message),
}
}
if err != nil {
return false, fmt.Errorf("templating error: %w", err)
}
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(msg); err != nil {
return false, err
}
postMessageURL := n.conf.APIURL.Copy()
postMessageURL.Path += "message/send"
q := postMessageURL.Query()
q.Set("access_token", n.accessToken)
postMessageURL.RawQuery = q.Encode()
resp, err := notify.PostJSON(ctx, n.client, postMessageURL.String(), &buf)
if err != nil {
return true, notify.RedactURL(err)
}
defer notify.Drain(resp)
if resp.StatusCode != 200 {
return true, notify.NewErrorWithReason(notify.GetFailureReasonFromStatusCode(resp.StatusCode), fmt.Errorf("unexpected status code %v", resp.StatusCode))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return true, err
}
level.Debug(n.logger).Log("response", string(body), "incident", key)
var weResp weChatResponse
if err := json.Unmarshal(body, &weResp); err != nil {
return true, err
}
// https://work.weixin.qq.com/api/doc#10649
if weResp.Code == 0 {
return false, nil
}
// AccessToken is expired
if weResp.Code == 42001 {
n.accessToken = ""
return true, errors.New(weResp.Error)
}
return false, errors.New(weResp.Error)
}