From de1637afe52cfa1eae9957d1f031516f6e1dffab Mon Sep 17 00:00:00 2001 From: Alexander Weaver Date: Tue, 28 Mar 2023 08:57:51 -0500 Subject: [PATCH] Alerting: Add alert instance labels to Loki log lines in addition to stream labels (#65403) Add instance labels to log line --- pkg/services/ngalert/state/historian/loki.go | 16 ++++++---- .../ngalert/state/historian/loki_test.go | 32 +++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/pkg/services/ngalert/state/historian/loki.go b/pkg/services/ngalert/state/historian/loki.go index 78c91e6325b..99b0645001f 100644 --- a/pkg/services/ngalert/state/historian/loki.go +++ b/pkg/services/ngalert/state/historian/loki.go @@ -262,12 +262,13 @@ func statesToStreams(rule history_model.RuleMeta, states []state.StateTransition repr := string(lblJsn) entry := lokiEntry{ - SchemaVersion: 1, - Previous: state.PreviousFormatted(), - Current: state.Formatted(), - Values: valuesAsDataBlob(state.State), - DashboardUID: rule.DashboardUID, - PanelID: rule.PanelID, + SchemaVersion: 1, + Previous: state.PreviousFormatted(), + Current: state.Formatted(), + Values: valuesAsDataBlob(state.State), + DashboardUID: rule.DashboardUID, + PanelID: rule.PanelID, + InstanceLabels: state.Labels, } if state.State.State == eval.Error { entry.Error = state.Error.Error() @@ -319,6 +320,9 @@ type lokiEntry struct { Values *simplejson.Json `json:"values"` DashboardUID string `json:"dashboardUID"` PanelID int64 `json:"panelID"` + // InstanceLabels is exactly the set of labels associated with the alert instance in Alertmanager. + // These should not be conflated with labels associated with log streams. + InstanceLabels map[string]string `json:"labels"` } func valuesAsDataBlob(state *state.State) *simplejson.Json { diff --git a/pkg/services/ngalert/state/historian/loki_test.go b/pkg/services/ngalert/state/historian/loki_test.go index 667e1cbbf3a..9c3652c7c90 100644 --- a/pkg/services/ngalert/state/historian/loki_test.go +++ b/pkg/services/ngalert/state/historian/loki_test.go @@ -130,6 +130,38 @@ func TestRemoteLokiBackend(t *testing.T) { require.NotContains(t, res[0].Stream, "__private__") }) + t.Run("includes instance labels in log line", func(t *testing.T) { + rule := createTestRule() + l := log.NewNopLogger() + states := singleFromNormal(&state.State{ + State: eval.Alerting, + Labels: data.Labels{"statelabel": "labelvalue"}, + }) + + res := statesToStreams(rule, states, nil, l) + + entry := requireSingleEntry(t, res) + require.Contains(t, entry.InstanceLabels, "statelabel") + }) + + t.Run("does not include labels other than instance labels in log line", func(t *testing.T) { + rule := createTestRule() + l := log.NewNopLogger() + states := singleFromNormal(&state.State{ + State: eval.Alerting, + Labels: data.Labels{ + "statelabel": "labelvalue", + "labeltwo": "labelvalue", + "labelthree": "labelvalue", + }, + }) + + res := statesToStreams(rule, states, nil, l) + + entry := requireSingleEntry(t, res) + require.Len(t, entry.InstanceLabels, 3) + }) + t.Run("serializes values when regular", func(t *testing.T) { rule := createTestRule() l := log.NewNopLogger()