Add per-tenant alert generator URL template for customizable alert source links#7302
Add per-tenant alert generator URL template for customizable alert source links#7302CharlieTLe wants to merge 10 commits intocortexproject:masterfrom
Conversation
Add support for tenants to configure alert GeneratorURL to use Grafana Explore format instead of the default Prometheus /graph format. This is controlled by three new per-tenant settings: ruler_alert_generator_url_format, ruler_grafana_datasource_uid, and ruler_grafana_org_id. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
yeya24
left a comment
There was a problem hiding this comment.
@rajagopalanand Can you help take a look?
friedrichg
left a comment
There was a problem hiding this comment.
I gave a review, but I think we do not care what parameters are send to the url. We don't care about grafana org IDs
I think we should make this general enough to be used by any metrics explorer.
Maybe consider renaming the function as explore and not have any grafana
I am thinking of something that would support for example:
explore
what do you think?
pkg/util/validation/exporter_test.go
Outdated
| cortex_overrides{limit_name="reject_old_samples",user="tenant-a"} 0 | ||
| cortex_overrides{limit_name="reject_old_samples_max_age",user="tenant-a"} 1.2096e+06 | ||
| cortex_overrides{limit_name="ruler_evaluation_delay_duration",user="tenant-a"} 0 | ||
| cortex_overrides{limit_name="ruler_grafana_org_id",user="tenant-a"} 0 |
There was a problem hiding this comment.
I think this should never be 0. The default org id as zero should be rejected as invalid.
Consider putting
-
if l.RulerGrafanaOrgID < 1 { -
return errors.New("ruler_grafana_org_id must be greater than or equal to 1") -
}
in UnmarshalYaml and UnmarshallJSON in limits.go
pkg/ruler/compat.go
Outdated
| if orgID == 0 { | ||
| orgID = 1 | ||
| } |
There was a problem hiding this comment.
| if orgID == 0 { | |
| orgID = 1 | |
| } |
Should not be needed after my other comment
pkg/ruler/compat.go
Outdated
| if orgID == 0 { | ||
| orgID = 1 | ||
| } | ||
| return grafanaExploreLink(externalURL, expr, datasourceUID, orgID) |
There was a problem hiding this comment.
I think is better we make grafanaExploreLink return errors if the url cannot be generated. For example: empty datasource
and if get errors we should log the error and fallback to prometheus still
|
|
||
| # Grafana datasource UID for alert generator URLs when format is | ||
| # grafana-explore. | ||
| [ruler_grafana_datasource_uid: <string> | default = ""] |
There was a problem hiding this comment.
it's not clear looking at this configuration that empty is not valid.
pkg/ruler/ruler.go
Outdated
| }, | ||
| }, | ||
| "range": map[string]string{ | ||
| "from": "now-1h", |
There was a problem hiding this comment.
this looks like it should be configurable. Maybe there is a way to configure the whole pane as a configurable json. At the end of the day, we don't care for this
…nerator URLs Replace the 3 Grafana-specific per-tenant config fields (ruler_alert_generator_url_format, ruler_grafana_datasource_uid, ruler_grafana_org_id) with a single generic field: ruler_alert_generator_url_template. This field accepts a Go text/template string with .ExternalURL and .Expression variables, plus built-in functions like urlquery. Users can construct any URL format (Grafana, Perses, etc.) without Cortex needing to understand specific UI formats. The ruler_external_url per-tenant override and SendAlerts signature (func(expr string) string) are kept unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
Add per-tenant Alertmanager datasources (tenant-a, tenant-b) to Grafana provisioning so alerts are visible in Grafana's alerting UI. Add runtime-config.yaml with per-tenant overrides: - tenant-a: Grafana Explore URL template with full pane JSON - tenant-b: Perses explore URL template with PrometheusTimeSeriesQuery Update Perses from v0.49 to v0.53.1 and enable the explorer feature (frontend.explorer.enable: true). Rename project from "default" to "cortex" to match template URLs. Add Step 7 to the getting-started guide with instructions for: - Configuring per-tenant alert generator URL templates - Loading alertmanager configs and demo alert rules - Viewing alerts in Grafana at /alerting/groups?groupBy=alertname - Verifying generator URLs via the API Also configure ruler.alertmanager_url and ruler.external_url, and set an explicit UID on the Grafana Cortex datasource for use in templates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
Add support for tenants to configure alert GeneratorURL to use Grafana Explore format instead of the default Prometheus /graph format. This is controlled by three new per-tenant settings: ruler_alert_generator_url_format, ruler_grafana_datasource_uid, and ruler_grafana_org_id. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
…nerator URLs Replace the 3 Grafana-specific per-tenant config fields (ruler_alert_generator_url_format, ruler_grafana_datasource_uid, ruler_grafana_org_id) with a single generic field: ruler_alert_generator_url_template. This field accepts a Go text/template string with .ExternalURL and .Expression variables, plus built-in functions like urlquery. Users can construct any URL format (Grafana, Perses, etc.) without Cortex needing to understand specific UI formats. The ruler_external_url per-tenant override and SendAlerts signature (func(expr string) string) are kept unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
Add per-tenant Alertmanager datasources (tenant-a, tenant-b) to Grafana provisioning so alerts are visible in Grafana's alerting UI. Add runtime-config.yaml with per-tenant overrides: - tenant-a: Grafana Explore URL template with full pane JSON - tenant-b: Perses explore URL template with PrometheusTimeSeriesQuery Update Perses from v0.49 to v0.53.1 and enable the explorer feature (frontend.explorer.enable: true). Rename project from "default" to "cortex" to match template URLs. Add Step 7 to the getting-started guide with instructions for: - Configuring per-tenant alert generator URL templates - Loading alertmanager configs and demo alert rules - Viewing alerts in Grafana at /alerting/groups?groupBy=alertname - Verifying generator URLs via the API Also configure ruler.alertmanager_url and ruler.external_url, and set an explicit UID on the Grafana Cortex datasource for use in templates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
Resolve conflict in schemas/cortex-config-schema.json: keep both the upstream results_cache_ttl entry and our ruler_alert_generator_url_template. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
Resolve conflict in schemas/cortex-config-schema.json: keep both results_cache_ttl and ruler_alert_generator_url_template entries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Charlie Le <charlie_le@apple.com>
Summary
ruler_alert_generator_url_templatefield that accepts a Gotext/templatestringruler_external_urloverride so tenants can have different external URLs without changing the global ruler configWhen
ruler_alert_generator_url_templateis set, the ruler evaluates the template with.ExternalURLand.Expressionvariables to produce the alert'sGeneratorURL. Built-in Go template functions likeurlqueryare available for URL encoding. If the template is empty, the default Prometheus/graphformat is used.New per-tenant config options
ruler_external_url""(uses global)ruler_alert_generator_url_template""(Prometheus format)Example runtime config
Getting-started docker-compose example
The PR includes a working docker-compose example in
docs/getting-started/with:Test plan
executeGeneratorURLTemplatewith various expressions,urlquery, and invalid templatesuserExternalURLtracking per-tenant URL changesSendAlertswith custom generator URL function (default + template formats)Limits.Validate()catches invalid templates at config load time🤖 Generated with Claude Code