diff --git a/notify/telegram/telegram.go b/notify/telegram/telegram.go
index 645f12dcb5..b8335e4564 100644
--- a/notify/telegram/telegram.go
+++ b/notify/telegram/telegram.go
@@ -22,8 +22,10 @@ import (
"os"
"strconv"
"strings"
+ "unicode/utf8"
commoncfg "github.com/prometheus/common/config"
+ "golang.org/x/net/html"
"gopkg.in/telebot.v3"
"github.com/prometheus/alertmanager/notify"
@@ -31,7 +33,8 @@ import (
"github.com/prometheus/alertmanager/types"
)
-// Telegram supports 4096 chars max - from https://limits.tginfo.me/en.
+// Telegram supports up to 4096 characters after entity parsing.
+// See https://core.telegram.org/bots/api#sendmessage.
const maxMessageLenRunes = 4096
// Notifier implements a Notifier for telegram notifications.
@@ -92,7 +95,7 @@ func (n *Notifier) Notify(ctx context.Context, alert ...*types.Alert) (bool, err
if err != nil {
return false, err
}
- if len([]rune(messageText)) > maxMessageLenRunes {
+ if htmlTextRuneCount(messageText) > maxMessageLenRunes {
messageText = `Alertmanager notification could not be sent: message length exceeds Telegram limits.
Please check the template used for producing the message content.`
}
@@ -147,6 +150,26 @@ func wrapWithFailureReason(err error) error {
return err
}
+// htmlTextRuneCount excludes HTML markup and attribute values such as link targets.
+func htmlTextRuneCount(message string) int {
+ tokenizer := html.NewTokenizer(strings.NewReader(message))
+ count := 0
+
+ for {
+ switch tokenizer.Next() {
+ case html.ErrorToken:
+ if len(tokenizer.Raw()) > 0 {
+ return utf8.RuneCountInString(message)
+ }
+ return count
+ case html.CommentToken, html.DoctypeToken:
+ return utf8.RuneCountInString(message)
+ case html.TextToken:
+ count += utf8.RuneCount(tokenizer.Text())
+ }
+ }
+}
+
func createTelegramClient(apiURL, parseMode string, httpClient *http.Client) (*telebot.Bot, error) {
bot, err := telebot.NewBot(telebot.Settings{
URL: apiURL,
diff --git a/notify/telegram/telegram_test.go b/notify/telegram/telegram_test.go
index 316d8ddab5..a95c3bd8ba 100644
--- a/notify/telegram/telegram_test.go
+++ b/notify/telegram/telegram_test.go
@@ -83,6 +83,13 @@ func TestTelegramRetry(t *testing.T) {
func TestTelegramNotify(t *testing.T) {
token := "secret"
+ longHTMLLink := `Open`
+ longMalformedHTML := `