Skip to content

feat(api): add receiver labels and receiver_matchers filter#5152

Open
cxdy wants to merge 1 commit intoprometheus:mainfrom
cxdy:feat/receiver-labels
Open

feat(api): add receiver labels and receiver_matchers filter#5152
cxdy wants to merge 1 commit intoprometheus:mainfrom
cxdy:feat/receiver-labels

Conversation

@cxdy
Copy link
Copy Markdown
Contributor

@cxdy cxdy commented Apr 3, 2026

Add support for arbitrary key-value labels on receivers, enabling structured identification for querying and filtering. The receiver name is auto-injected as the "name" label for uniform matcher access.

Expose labels in all API receiver responses (GET /receivers, GET /alerts, GET /alerts/groups) and add a receiver_matchers query parameter to all three endpoints for filtering by receiver labels using PromQL-style matchers.

Pull Request Checklist

Which user-facing changes does this PR introduce?

  • Adds labels to receivers
  • Returns receiver.labels in /api/v2/alerts, /api/v2/alerts/groups, and /api/v2/receivers

Good config + response

receivers:
- name: this-is-my-receiver-name
  labels:
    owning-team: team-foo-bar
    kind: webhook
    name: this-is-my-receiver-name
  webhook_configs:
  - send_resolved: true
    url: http://127.0.0.1:9014/alerts
root@prometheus:~# curl -s 'localhost:9093/api/v2/receivers' | jq '.[] | {name: .name, labels: .labels}'
{
  "name": "this-is-my-receiver-name",
  "labels": {
    "kind": "webhook",
    "name": "this-is-my-receiver-name",
    "owning-team": "team-foo-bar"
  }
}
{
  "name": "slack-alert-dev",
  "labels": {
    "name": "slack-alert-dev"
  }
}

Bad config + error

receivers:
- name: this-is-my-receiver-name
  labels:
    owning-team: team-foo-bar
    kind: webhook
    name: this-is-not-my-receiver-name
  webhook_configs:
  - send_resolved: true
    url: http://127.0.0.1:9014/alerts
time=2026-04-03T12:59:36.559Z level=ERROR source=coordinator.go:116 msg="Loading configuration file failed" component=configuration file=/path/to/alertmanager.yml err="receiver label \"name\" must match receiver name \"this-is-my-receiver\", got \"this-is-not-my-receiver-name\""

I'm sort of torn on the error handling though, I currently have it failing hard (seems like that's the general convention in Alertmanager for this sort of thing) if receiver[i].name != receiver[i].labels.name, but that seems a little dramatic for what this is. Open to feedback on that one, happy to change it if you agree with me or leave it if you don't!

Summary by CodeRabbit

  • New Features

    • Added receiver_matchers query param to filter receivers, alerts, and alert groups by receiver labels; alerts/alert-groups now respect receiver-label gating.
  • API Changes

    • Receiver objects include a labels field (auto-injected name label).
    • GET /receivers documents 400/500 responses for invalid matcher input.
    • Client libs and URL builders support multi-valued receiver_matchers.
  • Config

    • Receiver configs auto-populate/validate the name label.
  • Tests

    • Added coverage for matcher logic, label propagation, and config label handling.
  • UI

    • Frontend model encodes/decodes receiver.labels.

@cxdy cxdy requested a review from a team as a code owner April 3, 2026 13:04
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 3, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds receiver labels to config and API models; surfaces labels in API responses; supports a multi-valued receiver_matchers query parameter on GET /receivers, /alerts, and /alerts/groups to filter results by receiver-label match expressions; updates SDKs, URL builders, handlers, tests, and UI types.

Changes

Cohort / File(s) Summary
Core API handlers
api/v2/api.go
Parse receiver_matchers in getReceivers/getAlerts/getAlertGroups; validate matchers; gate results by receiver-label matching; add helpers receiversMatchLabels, configReceiverToAPIReceiver, receiverLabelsMap.
API models & compat
api/v2/models/receiver.go, api/v2/compat.go
Add Receiver.Labels with validation/context-validation; update AlertToOpenAPIAlert signature to accept receiverLabels and populate per-receiver Labels.
OpenAPI / embedded spec
api/v2/openapi.yaml, api/v2/restapi/embedded_spec.go
Add receiver_matchers (array, collectionFormat: multi) to GET /receivers, /alerts, /alerts/groups; add labels to receiver schema; document 400/500 responses for GET /receivers.
REST param binding & URL builders
api/v2/restapi/operations/.../get_*_parameters.go, api/v2/restapi/operations/.../get_*_urlbuilder.go
Add ReceiverMatchers []string to parameter structs; implement bindReceiverMatchers/BindRequest logic; serialize multi-valued receiver_matchers in URL builders.
Client SDK
api/v2/client/.../get_*_parameters.go, api/v2/client/receiver/get_receivers_responses.go
Expose ReceiverMatchers fields with With/Set methods; serialize multi-valued query params in client requests; add GetReceivers 400/500 response types and reader handling.
Config layer & tests
config/config.go, config/config_test.go
Add Labels map[string]string to config Receiver; ensure labels["name"] is injected and validated (error on conflict); update and add tests for injection, preservation, conflicts, and edge cases.
API tests
api/v2/api_test.go
Update tests for new AlertToOpenAPIAlert signature; add tests verifying receiver labels in responses, matcher filtering behavior, and invalid matcher handling.
UI types & views
ui/app/src/Data/Receiver.elm, ui/app/src/Views/AlertList/Updates.elm
Extend Elm Receiver with labels : Maybe (Dict String String); update decoder/encoder and change group metadata construction to use Receiver "unknown" Nothing.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as API Handler
    participant Config as Config Store
    participant Matcher as Matcher Engine
    participant Encoder as JSON Encoder

    Client->>API: GET /api/v2/receivers?receiver_matchers=owner="team-a"
    activate API
    API->>API: parseFilter(receiver_matchers)
    API->>Config: read receivers (includes Labels)
    Config-->>API: receivers + labels
    API->>Matcher: receiversMatchLabels(matchers, receiverLabels)
    Matcher-->>API: matched receiver names
    API->>API: map matched via configReceiverToAPIReceiver
    API->>Encoder: encode matched receivers (include labels)
    Encoder-->>Client: 200 OK JSON
    deactivate API
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(api): add receiver labels and receiver_matchers filter' clearly and concisely describes the main changes: adding receiver label support and a filtering mechanism.
Linked Issues check ✅ Passed The PR implementation fulfills all coding objectives from issue #4963: adds receiver labels configuration support, enforces name label validation, exposes labels in API responses (GET /receivers, /alerts, /alerts/groups), and implements receiver_matchers filtering using PromQL-style matchers.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing receiver labels and filtering: config parsing, API handler/model updates, client parameter handling, OpenAPI/swagger specifications, Elm UI models, and related tests—all directly supporting the stated objectives.
Description check ✅ Passed PR description covers objectives, includes required checklist items, references issue #4963, provides config examples, and lists user-facing changes in release notes format.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cxdy cxdy force-pushed the feat/receiver-labels branch from c64c08e to e713404 Compare April 3, 2026 13:11
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
config/config_test.go (1)

249-269: Test name slightly misleading - only tests hyphens, not UTF-8.

The test TestReceiverLabelsAllowsHyphensAndUTF8 only tests hyphen characters in label keys/values. Consider either renaming to TestReceiverLabelsAllowsHyphens or adding actual UTF-8 test cases (e.g., "owner": "équipe-α").

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/config_test.go` around lines 249 - 269, The test named
TestReceiverLabelsAllowsHyphensAndUTF8 only verifies hyphens; either rename the
test to TestReceiverLabelsAllowsHyphens or extend it to include a UTF‑8 case:
update TestReceiverLabelsAllowsHyphensAndUTF8 to add a receiver label and/or
value with UTF‑8 characters (e.g., "owner": "équipe-α") and assert via cfg :=
Load(in) and rcv := cfg.Receivers[0] that rcv.Labels contains the expected UTF‑8
key/value, or simply rename the function to TestReceiverLabelsAllowsHyphens if
you prefer not to add UTF‑8 content.
api/v2/api_test.go (2)

685-714: Add a matcher case for the injected name label.

This table only exercises user-defined labels. A receiverMatchers: []string{name="team-X"} case would lock the filter path to the same invariant the response assertions rely on.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v2/api_test.go` around lines 685 - 714, Add a test row to the
table-driven test (the slice of structs iterated as tc with fields
receiverMatchers and expectedNames) that exercises the injected name label by
setting receiverMatchers: []string{`name="team-X"`} and expectedNames:
[]string{"team-X"}; this ensures the filter path that handles the injected
`name` label is exercised alongside the existing owner/kind cases (look for the
receiverMatchers / expectedNames entries in the test table).

658-916: Please cover the other two receiver_matchers handlers end-to-end.

This file now exercises /api/v2/receivers plus helper functions, but the new request-parsing and filtering branches in getAlertsHandler and getAlertGroupsHandler still are not hit here. A minimal happy-path and bad-matcher case for each endpoint would catch wiring regressions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v2/api_test.go` around lines 658 - 916, Add end-to-end tests that
exercise the new request-parsing and filtering branches for getAlertsHandler and
getAlertGroupsHandler: create minimal config and alerts/alert-groups fixtures,
then call api.getAlertsHandler and api.getAlertGroupsHandler with valid
ReceiverMatchers (e.g. owner="team-x") and assert the filtered results match
expected names/IDs, and add companion tests that pass an invalid matcher string
(like "not-a-valid-matcher!!!") and assert a 400 response; reference the handler
functions getAlertsHandler and getAlertGroupsHandler and reuse the pattern from
TestGetReceiversHandlerWithReceiverMatchers and
TestGetReceiversHandlerBadReceiverMatchers to wire HTTP request creation,
responder.WriteResponse, and response assertions.
api/v2/api.go (1)

250-256: Derive receiver labels once and reuse them.

getReceiversHandler filters on raw rcv.Labels, while the response and alert/group paths build separate label copies. A single normalization helper keeps receiver_matchers aligned with the payload you serialize and gives you one place to preserve the injected name label contract.

♻️ Possible consolidation
+func normalizedReceiverLabels(rcv *config.Receiver) open_api_models.LabelSet {
+	apiLabels := make(open_api_models.LabelSet, len(rcv.Labels)+1)
+	maps.Copy(apiLabels, rcv.Labels)
+	if _, ok := apiLabels["name"]; !ok {
+		apiLabels["name"] = rcv.Name
+	}
+	return apiLabels
+}
+
 func (api *API) getReceiversHandler(params receiver_ops.GetReceiversParams) middleware.Responder {
 	// ...
 	receivers := make([]*open_api_models.Receiver, 0, len(api.alertmanagerConfig.Receivers))
 	for i := range api.alertmanagerConfig.Receivers {
 		rcv := &api.alertmanagerConfig.Receivers[i]
-		if len(receiverMatchers) > 0 && !matchFilterLabels(receiverMatchers, rcv.Labels) {
+		apiRcv := configReceiverToAPIReceiver(rcv)
+		if len(receiverMatchers) > 0 && !matchFilterLabels(receiverMatchers, apiRcv.Labels) {
 			continue
 		}
-		receivers = append(receivers, configReceiverToAPIReceiver(rcv))
+		receivers = append(receivers, apiRcv)
 	}
 }
 
 func configReceiverToAPIReceiver(rcv *config.Receiver) *open_api_models.Receiver {
-	apiLabels := make(open_api_models.LabelSet, len(rcv.Labels))
-	maps.Copy(apiLabels, rcv.Labels)
 	return &open_api_models.Receiver{
 		Name:   &rcv.Name,
-		Labels: apiLabels,
+		Labels: normalizedReceiverLabels(rcv),
 	}
 }
 
 func (api *API) receiverLabelsMap() map[string]open_api_models.LabelSet {
 	m := make(map[string]open_api_models.LabelSet, len(api.alertmanagerConfig.Receivers))
 	for i := range api.alertmanagerConfig.Receivers {
 		rcv := &api.alertmanagerConfig.Receivers[i]
-		apiLabels := make(open_api_models.LabelSet, len(rcv.Labels))
-		maps.Copy(apiLabels, rcv.Labels)
-		m[rcv.Name] = apiLabels
+		m[rcv.Name] = normalizedReceiverLabels(rcv)
 	}
 	return m
 }

Also applies to: 601-621

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v2/api.go` around lines 250 - 256, getReceiversHandler currently filters
using raw rcv.Labels but later builds separate label copies for response and
alert/group paths, causing inconsistency; introduce a single normalization
helper (e.g., normalizeReceiverLabels) and call it once per receiver to produce
the canonical label map (including the injected "name" label) and then use that
same map for matchFilterLabels(receiverMatchers, ...), for passing into
configReceiverToAPIReceiver, and anywhere else receiver labels are constructed
(also apply same change to the similar block at lines ~601-621) so all code
reuses the derived labels rather than duplicating raw rcv.Labels.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@api/v2/api_test.go`:
- Around line 685-714: Add a test row to the table-driven test (the slice of
structs iterated as tc with fields receiverMatchers and expectedNames) that
exercises the injected name label by setting receiverMatchers:
[]string{`name="team-X"`} and expectedNames: []string{"team-X"}; this ensures
the filter path that handles the injected `name` label is exercised alongside
the existing owner/kind cases (look for the receiverMatchers / expectedNames
entries in the test table).
- Around line 658-916: Add end-to-end tests that exercise the new
request-parsing and filtering branches for getAlertsHandler and
getAlertGroupsHandler: create minimal config and alerts/alert-groups fixtures,
then call api.getAlertsHandler and api.getAlertGroupsHandler with valid
ReceiverMatchers (e.g. owner="team-x") and assert the filtered results match
expected names/IDs, and add companion tests that pass an invalid matcher string
(like "not-a-valid-matcher!!!") and assert a 400 response; reference the handler
functions getAlertsHandler and getAlertGroupsHandler and reuse the pattern from
TestGetReceiversHandlerWithReceiverMatchers and
TestGetReceiversHandlerBadReceiverMatchers to wire HTTP request creation,
responder.WriteResponse, and response assertions.

In `@api/v2/api.go`:
- Around line 250-256: getReceiversHandler currently filters using raw
rcv.Labels but later builds separate label copies for response and alert/group
paths, causing inconsistency; introduce a single normalization helper (e.g.,
normalizeReceiverLabels) and call it once per receiver to produce the canonical
label map (including the injected "name" label) and then use that same map for
matchFilterLabels(receiverMatchers, ...), for passing into
configReceiverToAPIReceiver, and anywhere else receiver labels are constructed
(also apply same change to the similar block at lines ~601-621) so all code
reuses the derived labels rather than duplicating raw rcv.Labels.

In `@config/config_test.go`:
- Around line 249-269: The test named TestReceiverLabelsAllowsHyphensAndUTF8
only verifies hyphens; either rename the test to TestReceiverLabelsAllowsHyphens
or extend it to include a UTF‑8 case: update
TestReceiverLabelsAllowsHyphensAndUTF8 to add a receiver label and/or value with
UTF‑8 characters (e.g., "owner": "équipe-α") and assert via cfg := Load(in) and
rcv := cfg.Receivers[0] that rcv.Labels contains the expected UTF‑8 key/value,
or simply rename the function to TestReceiverLabelsAllowsHyphens if you prefer
not to add UTF‑8 content.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 274c1e3d-c599-4f0a-922b-db5d40e6aba4

📥 Commits

Reviewing files that changed from the base of the PR and between 50708ff and c64c08e.

📒 Files selected for processing (19)
  • api/v2/api.go
  • api/v2/api_test.go
  • api/v2/client/alert/get_alerts_parameters.go
  • api/v2/client/alertgroup/get_alert_groups_parameters.go
  • api/v2/client/receiver/get_receivers_parameters.go
  • api/v2/client/receiver/get_receivers_responses.go
  • api/v2/compat.go
  • api/v2/models/receiver.go
  • api/v2/openapi.yaml
  • api/v2/restapi/embedded_spec.go
  • api/v2/restapi/operations/alert/get_alerts_parameters.go
  • api/v2/restapi/operations/alert/get_alerts_urlbuilder.go
  • api/v2/restapi/operations/alertgroup/get_alert_groups_parameters.go
  • api/v2/restapi/operations/alertgroup/get_alert_groups_urlbuilder.go
  • api/v2/restapi/operations/receiver/get_receivers_parameters.go
  • api/v2/restapi/operations/receiver/get_receivers_responses.go
  • api/v2/restapi/operations/receiver/get_receivers_urlbuilder.go
  • config/config.go
  • config/config_test.go

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
config/config_test.go (1)

249-269: Test name is misleading - no UTF-8 characters are actually tested.

The test name TestReceiverLabelsAllowsHyphensAndUTF8 implies UTF-8 character validation, but the test only verifies hyphens in label keys and values. Consider either renaming the test or adding actual UTF-8 test cases.

📝 Option 1: Rename to reflect actual behavior
-func TestReceiverLabelsAllowsHyphensAndUTF8(t *testing.T) {
+func TestReceiverLabelsAllowsHyphens(t *testing.T) {
📝 Option 2: Add actual UTF-8 test cases
 func TestReceiverLabelsAllowsHyphensAndUTF8(t *testing.T) {
 	in := `
 route:
-    receiver: team-X-slack
+    receiver: team-X-日本語

 receivers:
-- name: 'team-X-slack'
+- name: 'team-X-日本語'
   labels:
-    owning-team: team-X-slack
+    owning-team: équipe-α
     kind: heartbeat
 `
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/config_test.go` around lines 249 - 269, The test
TestReceiverLabelsAllowsHyphensAndUTF8 is misleading because it only asserts
hyphens; either rename the test to TestReceiverLabelsAllowsHyphens (update the
function name) or extend the YAML input string `in` and assertions to include
real UTF-8 label keys/values (e.g., add a receiver label like `团队: "团队-slack"`
or an emoji key/value) and add assertions on cfg.Receivers[0].Labels for those
UTF-8 entries so the test actually verifies UTF-8 handling; update the test
function name and assertions accordingly (referencing the
TestReceiverLabelsAllowsHyphensAndUTF8 function and the `in` variable and
cfg.Receivers[0].Labels lookup).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@config/config_test.go`:
- Around line 249-269: The test TestReceiverLabelsAllowsHyphensAndUTF8 is
misleading because it only asserts hyphens; either rename the test to
TestReceiverLabelsAllowsHyphens (update the function name) or extend the YAML
input string `in` and assertions to include real UTF-8 label keys/values (e.g.,
add a receiver label like `团队: "团队-slack"` or an emoji key/value) and add
assertions on cfg.Receivers[0].Labels for those UTF-8 entries so the test
actually verifies UTF-8 handling; update the test function name and assertions
accordingly (referencing the TestReceiverLabelsAllowsHyphensAndUTF8 function and
the `in` variable and cfg.Receivers[0].Labels lookup).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a3a886ef-46e8-44d5-acc5-800cce3178b3

📥 Commits

Reviewing files that changed from the base of the PR and between c64c08e and e713404.

📒 Files selected for processing (21)
  • api/v2/api.go
  • api/v2/api_test.go
  • api/v2/client/alert/get_alerts_parameters.go
  • api/v2/client/alertgroup/get_alert_groups_parameters.go
  • api/v2/client/receiver/get_receivers_parameters.go
  • api/v2/client/receiver/get_receivers_responses.go
  • api/v2/compat.go
  • api/v2/models/receiver.go
  • api/v2/openapi.yaml
  • api/v2/restapi/embedded_spec.go
  • api/v2/restapi/operations/alert/get_alerts_parameters.go
  • api/v2/restapi/operations/alert/get_alerts_urlbuilder.go
  • api/v2/restapi/operations/alertgroup/get_alert_groups_parameters.go
  • api/v2/restapi/operations/alertgroup/get_alert_groups_urlbuilder.go
  • api/v2/restapi/operations/receiver/get_receivers_parameters.go
  • api/v2/restapi/operations/receiver/get_receivers_responses.go
  • api/v2/restapi/operations/receiver/get_receivers_urlbuilder.go
  • config/config.go
  • config/config_test.go
  • ui/app/src/Data/Receiver.elm
  • ui/app/src/Views/AlertList/Updates.elm
✅ Files skipped from review due to trivial changes (2)
  • api/v2/restapi/operations/receiver/get_receivers_urlbuilder.go
  • api/v2/restapi/operations/receiver/get_receivers_responses.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • api/v2/restapi/operations/receiver/get_receivers_parameters.go
  • api/v2/restapi/operations/alertgroup/get_alert_groups_parameters.go
  • api/v2/client/alert/get_alerts_parameters.go
  • api/v2/compat.go
  • api/v2/models/receiver.go
  • api/v2/api_test.go
  • api/v2/api.go

@Spaceman1701
Copy link
Copy Markdown
Contributor

This looks awesome, thanks for the contribution!

I am away for a little while, but I will do a code review as soon as I'm able. Perhaps the other maintainers will get to to first 🙂

Copy link
Copy Markdown
Contributor

@siavashs siavashs left a comment

Choose a reason for hiding this comment

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

LGTM, Thank you for your contribution.

Copy link
Copy Markdown
Contributor

@siavashs siavashs left a comment

Choose a reason for hiding this comment

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

There is a frontend test error:

Compiling (80)-- TYPE MISMATCH ------------------------------- src/Views/AlertList/Updates.elm

The 2nd argument to `AlertGroup` is not what I expect:

47|                                                 AlertGroup (Dict.fromList labels) { name = "unknown", labels = Dict.empty } alerts_
                                                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This argument is a record of type:

    { labels : Dict.Dict k v, name : String }

But `AlertGroup` needs the 2nd argument to be:

    Data.Receiver.Receiver

See the CI job for details.

@cxdy cxdy force-pushed the feat/receiver-labels branch 3 times, most recently from e20d804 to 03caa8a Compare April 3, 2026 16:34
Add support for arbitrary key-value labels on receivers, enabling
structured identification for querying and filtering. The receiver
name is auto-injected as the "name" label for uniform matcher access.

Expose labels in all API receiver responses (GET /receivers,
GET /alerts, GET /alerts/groups) and add a receiver_matchers query
parameter to all three endpoints for filtering by receiver labels
using PromQL-style matchers.

Ref: prometheus#4963

Signed-off-by: Cody Kaczynski <ckaczyns@akamai.com>
@cxdy cxdy force-pushed the feat/receiver-labels branch from 03caa8a to 1f1073f Compare April 3, 2026 16:40
@cxdy
Copy link
Copy Markdown
Contributor Author

cxdy commented Apr 3, 2026

Ah thanks @siavashs! I got it passing, just rebased and letting it run again.

@cxdy cxdy requested a review from siavashs April 3, 2026 16:41
Copy link
Copy Markdown
Contributor

@SoloJacobs SoloJacobs left a comment

Choose a reason for hiding this comment

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

Two issues we should discuss:

  1. The name auto-injection makes every user opt into this feature silently on upgrade. Since receiver names are already unique identifiers, re-expressing them as a label feels like a category error. I'd like to discuss whether this is the right default before it ships.

  2. Returning labels on every GettableAlert duplicates static receiver configuration across every alert in the response. There are also an open proposal to remove the receiver field from /alerts altogether #4727 . Expanding it now moves in the opposite direction. The right place for receiver metadata is GET /receivers. Callers who need the mapping can join on receiver.name client-side.

Suggested direction: keep labels and receiver_matchers on GET /receivers only, and drop them from the alert/alert-group responses.

'400':
$ref: '#/responses/BadRequest'
'500':
$ref: '#/responses/InternalServerError'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is there a 500 error code here? Does this implemenation make it so the receiver endpoint no longer works correctly in all circumstances?

Comment on lines 37 to +38
description: Get list of all receivers (name of notification integrations)
parameters:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems like receiver_matchers should not be duplicated? Can't we use a $ref here?

Comment on lines +929 to +930
// Labels attached to this receiver for querying and filtering.
Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This needs to be documented in docs/configuration.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add receiver labels

4 participants