diff --git a/senders/slack/slack.go b/senders/slack/slack.go index 203f46c2f..94dd69a14 100644 --- a/senders/slack/slack.go +++ b/senders/slack/slack.go @@ -18,6 +18,9 @@ const ( nodataEmoji = ":moira-state-nodata:" exceptionEmoji = ":moira-state-exception:" testEmoji = ":moira-state-test:" + + messageMaxCharacters = 40000 + additionalInfoCharactersCount = 400 ) var stateEmoji = map[moira.State]string{ @@ -93,13 +96,30 @@ func (sender *Sender) buildMessage(events moira.NotificationEvents, trigger moir message.WriteString("\n```") + var printEventsCount int + messageCharsCount := len([]rune(message.String())) + messageLimitReached := false + for _, event := range events { - message.WriteString(fmt.Sprintf("\n%s: %s = %s (%s to %s)", event.FormatTimestamp(sender.location), event.Metric, event.GetMetricValue(), event.OldState, event.State)) + line := fmt.Sprintf("\n%s: %s = %s (%s to %s)", event.FormatTimestamp(sender.location), event.Metric, event.GetMetricValue(), event.OldState, event.State) if len(moira.UseString(event.Message)) > 0 { - message.WriteString(fmt.Sprintf(". %s", moira.UseString(event.Message))) + line += fmt.Sprintf(". %s", moira.UseString(event.Message)) + } + lineCharsCount := len([]rune(line)) + if messageCharsCount+lineCharsCount > messageMaxCharacters-additionalInfoCharactersCount { + messageLimitReached = true + break } + message.WriteString(line) + messageCharsCount += lineCharsCount + printEventsCount++ } message.WriteString("```") + + if messageLimitReached { + message.WriteString(fmt.Sprintf("\n\n...and %d more events.", len(events)-printEventsCount)) + } + if throttled { message.WriteString("\nPlease, *fix your system or tune this trigger* to generate less events.") } diff --git a/senders/slack/slack_test.go b/senders/slack/slack_test.go index 9fbd18ea8..45f728d8f 100644 --- a/senders/slack/slack_test.go +++ b/senders/slack/slack_test.go @@ -2,6 +2,7 @@ package slack import ( "fmt" + "strings" "testing" "time" @@ -136,6 +137,17 @@ func TestBuildMessage(t *testing.T) { So(actual, ShouldResemble, expected) }) + events := make([]moira.NotificationEvent, 0) + Convey("Print moira message with 1129 events and cutoff", func() { + for i := 0; i < 1200; i++ { + events = append(events, event) + } + lines := strings.Repeat("\n02:40: Metric = 123 (OK to NODATA)", 1129) + actual := sender.buildMessage(events, trigger, false) + expected := fmt.Sprintf("*NODATA* [tag1][tag2] \n```%s```\n\n...and 71 more events.", lines) + So(actual, ShouldResemble, expected) + }) + Convey("Print moira message with empty triggerID, but with trigger name", func() { actual := sender.buildMessage([]moira.NotificationEvent{event}, moira.TriggerData{Name: "Name"}, false) expected := "*NODATA* Name\n```\n02:40: Metric = 123 (OK to NODATA)```"