Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change GeneratorURL to use configurable Grafana explore URL #8500

Merged
merged 8 commits into from
Apr 21, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/sources/configuration/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -746,10 +746,14 @@ results_cache:
The `ruler` block configures the Loki ruler.

```yaml
# URL of alerts return path.
# URL of the Grafana dashboard.
dannykopping marked this conversation as resolved.
Show resolved Hide resolved
# CLI flag: -ruler.external.url
[external_url: <url>]

# Datasource UID for the dashboard.
# CLI flag: -ruler.datasource-uid
[datasource_uid: <url>]

# Labels to add to all alerts.
[external_labels: <list of Labels>]

Expand Down
2 changes: 1 addition & 1 deletion pkg/ruler/base/compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ func DefaultTenantManagerFactory(cfg Config, p Pusher, q storage.Queryable, engi
QueryFunc: RecordAndReportRuleQueryMetrics(MetricsQueryFunc(EngineQueryFunc(engine, q, overrides, userID), totalQueries, failedQueries), queryTime, logger),
Context: user.InjectOrgID(ctx, userID),
ExternalURL: cfg.ExternalURL.URL,
NotifyFunc: SendAlerts(notifier, cfg.ExternalURL.URL.String()),
NotifyFunc: SendAlerts(notifier, cfg.ExternalURL.URL.String(), cfg.DatasourceUID),
Logger: log.With(logger, "user", userID),
Registerer: reg,
OutageTolerance: cfg.OutageTolerance,
Expand Down
41 changes: 37 additions & 4 deletions pkg/ruler/base/ruler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package base

import (
"context"
"encoding/json"
"flag"
"fmt"
"hash/fnv"
Expand All @@ -28,7 +29,6 @@ import (
"github.com/prometheus/prometheus/model/rulefmt"
"github.com/prometheus/prometheus/notifier"
promRules "github.com/prometheus/prometheus/rules"
"github.com/prometheus/prometheus/util/strutil"
"github.com/weaveworks/common/user"
"golang.org/x/sync/errgroup"

Expand Down Expand Up @@ -80,6 +80,8 @@ const (
type Config struct {
// This is used for template expansion in alerts; must be a valid URL.
ExternalURL flagext.URLValue `yaml:"external_url"`
// This is used for template expansion in alerts, and represents the corresponding Grafana datasource UID.
DatasourceUID string `yaml:"datasource_uid"`
// Labels to add to all alerts
ExternalLabels labels.Labels `yaml:"external_labels,omitempty" doc:"description=Labels to add to all alerts."`
// GRPC Client configuration.
Expand Down Expand Up @@ -162,7 +164,8 @@ func (cfg *Config) RegisterFlags(f *flag.FlagSet) {
flagext.DeprecatedFlag(f, "ruler.num-workers", "This flag is no longer functional. For increased concurrency horizontal sharding is recommended", util_log.Logger)

cfg.ExternalURL.URL, _ = url.Parse("") // Must be non-nil
f.Var(&cfg.ExternalURL, "ruler.external.url", "URL of alerts return path.")
f.Var(&cfg.ExternalURL, "ruler.external.url", "URL of the Grafana dashboard.")
f.StringVar(&cfg.DatasourceUID, "ruler.datasource-uid", "", "Datasource UID for the dashboard.")
f.DurationVar(&cfg.EvaluationInterval, "ruler.evaluation-interval", 1*time.Minute, "How frequently to evaluate rules.")
f.DurationVar(&cfg.PollInterval, "ruler.poll-interval", 1*time.Minute, "How frequently to poll for rule changes.")

Expand Down Expand Up @@ -378,11 +381,41 @@ type sender interface {
Send(alerts ...*notifier.Alert)
}

type query struct {
Expr string `json:"expr"`
QueryType string `json:"queryType"`
Datasource *datasource `json:"datasource,omitempty"`
}

type datasource struct {
Type string `json:"type"`
UID string `json:"uid"`
}

func grafanaLinkForExpression(expr, datasourceUID string) string {
exprStruct := query{
Expr: expr,
QueryType: "range",
}

if datasourceUID != "" {
exprStruct.Datasource = &datasource{
Type: "loki",
UID: datasourceUID,
}
}

marshaledExpression, _ := json.Marshal(exprStruct)
escapedExpression := url.QueryEscape(string(marshaledExpression))
str := `/explore?left={"queries":[%s]}`
return fmt.Sprintf(str, escapedExpression)
}

// SendAlerts implements a rules.NotifyFunc for a Notifier.
// It filters any non-firing alerts from the input.
//
// Copied from Prometheus's main.go.
func SendAlerts(n sender, externalURL string) promRules.NotifyFunc {
func SendAlerts(n sender, externalURL, datasourceUID string) promRules.NotifyFunc {
return func(ctx context.Context, expr string, alerts ...*promRules.Alert) {
var res []*notifier.Alert

Expand All @@ -391,7 +424,7 @@ func SendAlerts(n sender, externalURL string) promRules.NotifyFunc {
StartsAt: alert.FiredAt,
Labels: alert.Labels,
Annotations: alert.Annotations,
GeneratorURL: externalURL + strutil.TableLinkForExpression(expr),
GeneratorURL: externalURL + grafanaLinkForExpression(expr, datasourceUID),
}
if !alert.ResolvedAt.IsZero() {
a.EndsAt = alert.ResolvedAt
Expand Down
8 changes: 5 additions & 3 deletions pkg/ruler/base/ruler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math/rand"
"net/http"
"net/http/httptest"
"net/url"
"os"
"reflect"
"sort"
Expand Down Expand Up @@ -1645,6 +1646,7 @@ func (s senderFunc) Send(alerts ...*notifier.Alert) {
}

func TestSendAlerts(t *testing.T) {
escapedExpression := url.QueryEscape("{\"expr\":\"up\",\"queryType\":\"range\",\"datasource\":{\"type\":\"loki\",\"uid\":\"uid\"}}")
testCases := []struct {
in []*promRules.Alert
exp []*notifier.Alert
Expand All @@ -1665,7 +1667,7 @@ func TestSendAlerts(t *testing.T) {
Annotations: []labels.Label{{Name: "a2", Value: "v2"}},
StartsAt: time.Unix(2, 0),
EndsAt: time.Unix(3, 0),
GeneratorURL: "http://localhost:9090/graph?g0.expr=up&g0.tab=1",
GeneratorURL: fmt.Sprintf("http://localhost:9090/explore?left={\"queries\":[%s]}", escapedExpression),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiny nit: it's mildly confusing here to keep using :9090 since that's the Prometheus port

},
},
},
Expand All @@ -1685,7 +1687,7 @@ func TestSendAlerts(t *testing.T) {
Annotations: []labels.Label{{Name: "a2", Value: "v2"}},
StartsAt: time.Unix(2, 0),
EndsAt: time.Unix(4, 0),
GeneratorURL: "http://localhost:9090/graph?g0.expr=up&g0.tab=1",
GeneratorURL: fmt.Sprintf("http://localhost:9090/explore?left={\"queries\":[%s]}", escapedExpression),
},
},
},
Expand All @@ -1703,7 +1705,7 @@ func TestSendAlerts(t *testing.T) {
}
require.Equal(t, tc.exp, alerts)
})
SendAlerts(senderFunc, "http://localhost:9090")(context.TODO(), "up", tc.in...)
SendAlerts(senderFunc, "http://localhost:9090", "uid")(context.TODO(), "up", tc.in...)
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/ruler/compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func MultiTenantRuleManager(cfg Config, engine *logql.Engine, overrides RulesLim
QueryFunc: queryFunc,
Context: user.InjectOrgID(ctx, userID),
ExternalURL: cfg.ExternalURL.URL,
NotifyFunc: ruler.SendAlerts(notifier, cfg.ExternalURL.URL.String()),
NotifyFunc: ruler.SendAlerts(notifier, cfg.ExternalURL.URL.String(), cfg.DatasourceUID),
Logger: logger,
Registerer: reg,
OutageTolerance: cfg.OutageTolerance,
Expand Down