Skip to content

Commit dc98078

Browse files
committed
feat: support loki alerts GeneratorURL
1 parent 4bf6409 commit dc98078

File tree

2 files changed

+53
-20
lines changed

2 files changed

+53
-20
lines changed

pkg/alertmanager/alertmanager_template.go

+40-17
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
tmplhtml "html/template"
99
"net/url"
10+
"strings"
1011
tmpltext "text/template"
1112

1213
"github.com/prometheus/alertmanager/template"
@@ -37,29 +38,51 @@ type grafanaExploreParams struct {
3738

3839
// grafanaExploreURL is a template helper function to generate Grafana range query explore URL in the alert template.
3940
func grafanaExploreURL(grafanaURL, datasource, from, to, expr string) (string, error) {
40-
res, err := json.Marshal(&grafanaExploreParams{
41-
Range: grafanaExploreRange{
42-
From: from,
43-
To: to,
44-
},
45-
Queries: []grafanaExploreQuery{
46-
{
47-
Datasource: grafanaDatasource{
48-
Type: "prometheus",
49-
UID: datasource,
41+
grafanaExploreQueryPrefix := "/explore?left="
42+
var res []byte
43+
var err error
44+
var grafanaExplore grafanaExploreParams
45+
46+
if strings.HasPrefix(expr, grafanaExploreQueryPrefix) {
47+
// remove begging to get queries params
48+
expr = strings.ReplaceAll(expr, grafanaExploreQueryPrefix, "")
49+
if err = json.Unmarshal([]byte(expr), &grafanaExplore); err != nil {
50+
return "", err
51+
}
52+
grafanaExplore.Queries[0].Range = true
53+
grafanaExplore.Queries[0].RefID = "A"
54+
grafanaExplore.Range.From = from
55+
grafanaExplore.Range.To = to
56+
} else {
57+
grafanaExplore = grafanaExploreParams{
58+
Range: grafanaExploreRange{
59+
From: from,
60+
To: to,
61+
},
62+
Queries: []grafanaExploreQuery{
63+
{
64+
Datasource: grafanaDatasource{
65+
Type: "prometheus",
66+
UID: datasource,
67+
},
68+
Expr: expr,
69+
Instant: false,
70+
Range: true,
71+
RefID: "A",
5072
},
51-
Expr: expr,
52-
Instant: false,
53-
Range: true,
54-
RefID: "A",
5573
},
56-
},
57-
})
58-
return grafanaURL + "/explore?left=" + url.QueryEscape(string(res)), err
74+
}
75+
}
76+
res, err = json.Marshal(grafanaExplore)
77+
return grafanaURL + grafanaExploreQueryPrefix + url.QueryEscape(string(res)), err
5978
}
6079

6180
// queryFromGeneratorURL returns a PromQL expression parsed out from a GeneratorURL in Prometheus alert
6281
func queryFromGeneratorURL(generatorURL string) (string, error) {
82+
// if generator url source is a grafana product
83+
if strings.HasPrefix(generatorURL, "/explore?left=") {
84+
return generatorURL, nil
85+
}
6386
u, err := url.Parse(generatorURL)
6487
if err != nil {
6588
return "", fmt.Errorf("failed to parse generator URL: %w", err)

pkg/alertmanager/alertmanager_template_test.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,17 @@ func Test_withCustomFunctions(t *testing.T) {
4444
GeneratorURL: "http://localhost:9090?foo=bar",
4545
},
4646
},
47-
template: `{{ queryFormGeneratorURL (index .Alerts 0).GeneratorURL }}`,
47+
template: `{{ queryFromGeneratorURL (index .Alerts 0).GeneratorURL }}`,
4848
expectError: true,
4949
},
5050
{
5151
name: "error on URL decoding query in GeneratorURL",
5252
alerts: template.Alerts{
5353
template.Alert{
54-
GeneratorURL: "http://localhost:9090?g0.expr=up{foo=bar}",
54+
GeneratorURL: "http://localhost:9090?expr=up{foo=bar}",
5555
},
5656
},
57-
template: `{{ queryFormGeneratorURL (index .Alerts 0).GeneratorURL }}`,
57+
template: `{{ queryFromGeneratorURL (index .Alerts 0).GeneratorURL }}`,
5858
expectError: true,
5959
},
6060
{
@@ -77,6 +77,16 @@ func Test_withCustomFunctions(t *testing.T) {
7777
template: `{{ grafanaExploreURL "https://foo.bar" "test_datasoruce" "now-12h" "now" (queryFromGeneratorURL (index .Alerts 0).GeneratorURL) }}`,
7878
result: `https://foo.bar/explore?left=` + url.QueryEscape(`{"range":{"from":"now-12h","to":"now"},"queries":[{"datasource":{"type":"prometheus","uid":"test_datasoruce"},"expr":"up{foo!=\"bar\"}","instant":false,"range":true,"refId":"A"}]}`),
7979
},
80+
{
81+
name: "Generate Grafana Explore URL from GeneratorURL query from loki",
82+
alerts: template.Alerts{
83+
template.Alert{
84+
GeneratorURL: `/explore?left={"queries":[{"datasource":{"type":"loki","uid":"loki"},"expr":"up{foo!=\"bar\"}","queryType":"range"}]}`,
85+
},
86+
},
87+
template: `{{ grafanaExploreURL "http://localhost:9090" "test_datasource" "now-12h" "now" (queryFromGeneratorURL (index .Alerts 0).GeneratorURL) }}`,
88+
result: `http://localhost:9090/explore?left=%7B%22range%22%3A%7B%22from%22%3A%22now-12h%22%2C%22to%22%3A%22now%22%7D%2C%22queries%22%3A%5B%7B%22datasource%22%3A%7B%22type%22%3A%22loki%22%2C%22uid%22%3A%22loki%22%7D%2C%22expr%22%3A%22up%7Bfoo%21%3D%5C%22bar%5C%22%7D%22%2C%22instant%22%3Afalse%2C%22range%22%3Atrue%2C%22refId%22%3A%22A%22%7D%5D%7D`,
89+
},
8090
}
8191
for _, c := range cases {
8292
t.Run(c.name, func(t *testing.T) {

0 commit comments

Comments
 (0)