130 lines
3.5 KiB
Go
130 lines
3.5 KiB
Go
// Copyright 2022 Prometheus Team
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package telegram
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
commoncfg "github.com/prometheus/common/config"
|
|
"gopkg.in/telebot.v3"
|
|
|
|
"github.com/prometheus/alertmanager/config"
|
|
"github.com/prometheus/alertmanager/notify"
|
|
"github.com/prometheus/alertmanager/template"
|
|
"github.com/prometheus/alertmanager/types"
|
|
)
|
|
|
|
// Telegram supports 4096 chars max - from https://limits.tginfo.me/en.
|
|
const maxMessageLenRunes = 4096
|
|
|
|
// Notifier implements a Notifier for telegram notifications.
|
|
type Notifier struct {
|
|
conf *config.TelegramConfig
|
|
tmpl *template.Template
|
|
logger *slog.Logger
|
|
client *telebot.Bot
|
|
retrier *notify.Retrier
|
|
}
|
|
|
|
// New returns a new Telegram notification handler.
|
|
func New(conf *config.TelegramConfig, t *template.Template, l *slog.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
|
|
httpclient, err := commoncfg.NewClientFromConfig(*conf.HTTPConfig, "telegram", httpOpts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
client, err := createTelegramClient(conf.APIUrl.String(), conf.ParseMode, httpclient)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Notifier{
|
|
conf: conf,
|
|
tmpl: t,
|
|
logger: l,
|
|
client: client,
|
|
retrier: ¬ify.Retrier{},
|
|
}, nil
|
|
}
|
|
|
|
func (n *Notifier) Notify(ctx context.Context, alert ...*types.Alert) (bool, error) {
|
|
var (
|
|
err error
|
|
data = notify.GetTemplateData(ctx, n.tmpl, alert, n.logger)
|
|
tmpl = notify.TmplText(n.tmpl, data, &err)
|
|
)
|
|
|
|
if n.conf.ParseMode == "HTML" {
|
|
tmpl = notify.TmplHTML(n.tmpl, data, &err)
|
|
}
|
|
|
|
key, ok := notify.GroupKey(ctx)
|
|
if !ok {
|
|
return false, fmt.Errorf("group key missing")
|
|
}
|
|
|
|
messageText, truncated := notify.TruncateInRunes(tmpl(n.conf.Message), maxMessageLenRunes)
|
|
if truncated {
|
|
n.logger.Warn("Truncated message", "alert", key, "max_runes", maxMessageLenRunes)
|
|
}
|
|
|
|
n.client.Token, err = n.getBotToken()
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
|
|
message, err := n.client.Send(telebot.ChatID(n.conf.ChatID), messageText, &telebot.SendOptions{
|
|
DisableNotification: n.conf.DisableNotifications,
|
|
DisableWebPagePreview: true,
|
|
ThreadID: n.conf.MessageThreadID,
|
|
ParseMode: n.conf.ParseMode,
|
|
})
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
n.logger.Debug("Telegram message successfully published", "message_id", message.ID, "chat_id", message.Chat.ID)
|
|
|
|
return false, nil
|
|
}
|
|
|
|
func createTelegramClient(apiURL, parseMode string, httpClient *http.Client) (*telebot.Bot, error) {
|
|
bot, err := telebot.NewBot(telebot.Settings{
|
|
URL: apiURL,
|
|
ParseMode: parseMode,
|
|
Client: httpClient,
|
|
Offline: true,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return bot, nil
|
|
}
|
|
|
|
func (n *Notifier) getBotToken() (string, error) {
|
|
if len(n.conf.BotTokenFile) > 0 {
|
|
content, err := os.ReadFile(n.conf.BotTokenFile)
|
|
if err != nil {
|
|
return "", fmt.Errorf("could not read %s: %w", n.conf.BotTokenFile, err)
|
|
}
|
|
return strings.TrimSpace(string(content)), nil
|
|
}
|
|
return string(n.conf.BotToken), nil
|
|
}
|