Skip to content

Commit

Permalink
add service discovery for alertmanager
Browse files Browse the repository at this point in the history
Signed-off-by: liguozhong <[email protected]>
  • Loading branch information
liguozhong committed Oct 11, 2023
1 parent ffa74eb commit 5b09780
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 33 deletions.
67 changes: 63 additions & 4 deletions notifier/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"net/http"
"net/url"
"path"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -411,7 +412,6 @@ func (n *Manager) setMore() {
}
}

// Alertmanagers returns a slice of Alertmanager URLs.
func (n *Manager) Alertmanagers() []*url.URL {
n.mtx.RLock()
amSets := n.alertmanagers
Expand Down Expand Up @@ -610,7 +610,10 @@ type alertmanager interface {
url() *url.URL
}

type alertmanagerLabels struct{ labels.Labels }
type alertmanagerLabels struct {
labels.Labels
discoveredLabels labels.Labels
}

const pathLabel = "__alerts_path__"

Expand All @@ -622,6 +625,62 @@ func (a alertmanagerLabels) url() *url.URL {
}
}

type Target struct {
discoveredLabels labels.Labels
labels labels.Labels
}

func (a Target) Labels() labels.Labels {
lset := labels.Labels{}
for _, l := range a.labels {
if !strings.HasPrefix(l.Name, model.ReservedLabelPrefix) {
lset = append(lset, l)
}
}
url := url.URL{
Scheme: a.labels.Get(model.SchemeLabel),
Host: a.labels.Get(model.AddressLabel),
Path: a.labels.Get(pathLabel),
}
instance := url.String()
if instance != "" {
lset = append(lset, labels.Label{Name: model.InstanceLabel, Value: instance})
}
return lset
}

func (a Target) DiscoveredLabels() labels.Labels {
lset := labels.Labels{}
for _, l := range a.discoveredLabels {

Check failure on line 654 in notifier/notifier.go

View workflow job for this annotation

GitHub Actions / golangci-lint

S1011: should replace loop with `lset = append(lset, a.discoveredLabels...)` (gosimple)

Check failure on line 654 in notifier/notifier.go

View workflow job for this annotation

GitHub Actions / codeql / Analyze (go)

S1011: should replace loop with `lset = append(lset, a.discoveredLabels...)` (gosimple)
lset = append(lset, l)
}
return lset
}

func (n *Manager) TargetsAll() map[string][]Target {
n.mtx.Lock()
defer n.mtx.Unlock()
targets := make(map[string][]Target, len(n.alertmanagers))
for key, am := range n.alertmanagers {
if am.droppedAms == nil || len(am.droppedAms) == 0 {
tars := make([]Target, 0, len(am.ams))
for _, a := range am.ams {
alb := a.(alertmanagerLabels)
tars = append(tars, Target{labels: alb.Labels, discoveredLabels: alb.discoveredLabels})
}
targets[key] = tars
continue
}
tars := make([]Target, 0, len(am.droppedAms))
for _, a := range am.droppedAms {
alb := a.(alertmanagerLabels)
tars = append(tars, Target{labels: alb.Labels, discoveredLabels: alb.discoveredLabels})
}
targets[key] = tars
}
return targets
}

// alertmanagerSet contains a set of Alertmanagers discovered via a group of service
// discovery definitions that have a common configuration on how alerts should be sent.
type alertmanagerSet struct {
Expand Down Expand Up @@ -732,7 +791,7 @@ func AlertmanagerFromGroup(tg *targetgroup.Group, cfg *config.AlertmanagerConfig
preRelabel := lb.Labels()
keep := relabel.ProcessBuilder(lb, cfg.RelabelConfigs...)
if !keep {
droppedAlertManagers = append(droppedAlertManagers, alertmanagerLabels{preRelabel})
droppedAlertManagers = append(droppedAlertManagers, alertmanagerLabels{Labels: preRelabel, discoveredLabels: preRelabel})
continue
}

Expand All @@ -741,7 +800,7 @@ func AlertmanagerFromGroup(tg *targetgroup.Group, cfg *config.AlertmanagerConfig
return nil, nil, err
}

res = append(res, alertmanagerLabels{lb.Labels()})
res = append(res, alertmanagerLabels{Labels: lb.Labels(), discoveredLabels: preRelabel})
}
return res, droppedAlertManagers, nil
}
11 changes: 10 additions & 1 deletion notifier/notifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,8 @@ alerting:
}

n.reload(tgs)
res := n.DroppedAlertmanagers()[0].String()
drops := n.DroppedAlertmanagers()
res := drops[0].String()

require.Equal(t, res, tt.out)
}
Expand All @@ -569,6 +570,14 @@ func makeInputTargetGroup() *targetgroup.Group {
}
}

func TestTargetLabels(t *testing.T) {
label := labels.FromStrings("alertname", "test")
discoveredLabels := labels.FromStrings("alertname", "test", "a", "b")
target := Target{labels: label, discoveredLabels: discoveredLabels}
require.Equal(t, target.Labels(), label)
require.Equal(t, target.DiscoveredLabels(), discoveredLabels)
}

func TestLabelsToOpenAPILabelSet(t *testing.T) {
require.Equal(t, models.LabelSet{"aaa": "111", "bbb": "222"}, labelsToOpenAPILabelSet(labels.FromStrings("aaa", "111", "bbb", "222")))
}
Expand Down
66 changes: 66 additions & 0 deletions web/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/model/textparse"
"github.com/prometheus/prometheus/model/timestamp"
"github.com/prometheus/prometheus/notifier"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/promql/parser"
"github.com/prometheus/prometheus/rules"
Expand Down Expand Up @@ -108,6 +109,7 @@ type TargetRetriever interface {
type AlertmanagerRetriever interface {
Alertmanagers() []*url.URL
DroppedAlertmanagers() []*url.URL
TargetsAll() map[string][]notifier.Target
}

// RulesRetriever provides a list of active rules and alerts.
Expand Down Expand Up @@ -381,6 +383,7 @@ func (api *API) Register(r *route.Router) {
r.Get("/targets", wrap(api.targets))
r.Get("/targets/metadata", wrap(api.targetMetadata))
r.Get("/alertmanagers", wrapAgent(api.alertmanagers))
r.Get("/servicediscovery", wrapAgent(api.servicediscovery))

r.Get("/metadata", wrap(api.metricMetadata))

Expand Down Expand Up @@ -1134,6 +1137,69 @@ func (api *API) targetMetadata(r *http.Request) apiFuncResult {
return apiFuncResult{res, nil, nil, nil}
}

func (api *API) servicediscovery(r *http.Request) apiFuncResult {
scrapeData := func() TargetDiscovery {
var index []string
targets := api.targetRetriever(r.Context()).TargetsActive()
for job := range targets {
index = append(index, job)
}
sort.Strings(index)
res := TargetDiscovery{}
res.ActiveTargets = make([]*Target, 0)
res.DroppedTargets = make([]*DroppedTarget, 0)
for _, job := range index {
for _, target := range targets[job] {
if target.Labels().Len() == 0 {
res.DroppedTargets = append(res.DroppedTargets, &DroppedTarget{
DiscoveredLabels: target.DiscoveredLabels().Map(),
})
} else {
res.ActiveTargets = append(res.ActiveTargets, &Target{
DiscoveredLabels: target.DiscoveredLabels().Map(),
Labels: target.Labels().Map(),
ScrapePool: job,
})
}
}
}
return res
}

alertManagerData := func() TargetDiscovery {
var index []string
targets := api.alertmanagerRetriever(r.Context()).TargetsAll()
for job := range targets {
index = append(index, job)
}
sort.Strings(index)
res := TargetDiscovery{}
res.ActiveTargets = make([]*Target, 0)
res.DroppedTargets = make([]*DroppedTarget, 0)
for _, job := range index {
for _, target := range targets[job] {
if target.Labels().Len() == 0 {
res.DroppedTargets = append(res.DroppedTargets, &DroppedTarget{
DiscoveredLabels: target.DiscoveredLabels().Map(),
})
} else {
res.ActiveTargets = append(res.ActiveTargets, &Target{
DiscoveredLabels: target.DiscoveredLabels().Map(),
Labels: target.Labels().Map(),
ScrapePool: job,
})
}
}
}
return res
}
serviceDiscoveryData := map[string]TargetDiscovery{
"scrape": scrapeData(),
"alertManager": alertManagerData(),
}
return apiFuncResult{serviceDiscoveryData, nil, nil, nil}
}

type metricMetadata struct {
Target labels.Labels `json:"target"`
Metric string `json:"metric,omitempty"`
Expand Down
10 changes: 7 additions & 3 deletions web/api/v1/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ import (
"testing"
"time"

"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/util/stats"

"github.com/go-kit/log"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
Expand All @@ -46,13 +43,16 @@ import (
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/model/textparse"
"github.com/prometheus/prometheus/model/timestamp"
"github.com/prometheus/prometheus/notifier"
"github.com/prometheus/prometheus/prompb"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/promql/parser"
"github.com/prometheus/prometheus/rules"
"github.com/prometheus/prometheus/scrape"
"github.com/prometheus/prometheus/storage"
"github.com/prometheus/prometheus/storage/remote"
"github.com/prometheus/prometheus/tsdb"
"github.com/prometheus/prometheus/util/stats"
"github.com/prometheus/prometheus/util/teststorage"
)

Expand Down Expand Up @@ -204,6 +204,10 @@ func (t testAlertmanagerRetriever) DroppedAlertmanagers() []*url.URL {
}
}

func (t testAlertmanagerRetriever) TargetsAll() map[string][]notifier.Target {
return nil
}

func (t testAlertmanagerRetriever) toFactory() func(context.Context) AlertmanagerRetriever {
return func(context.Context) AlertmanagerRetriever { return t }
}
Expand Down
5 changes: 5 additions & 0 deletions web/api/v1/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (

"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/notifier"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/rules"
"github.com/prometheus/prometheus/scrape"
Expand Down Expand Up @@ -238,6 +239,10 @@ func (DummyTargetRetriever) TargetsDroppedCounts() map[string]int {
// DummyAlertmanagerRetriever implements AlertmanagerRetriever.
type DummyAlertmanagerRetriever struct{}

func (r DummyAlertmanagerRetriever) TargetsAll() map[string][]notifier.Target {
return nil
}

// Alertmanagers implements AlertmanagerRetriever.
func (DummyAlertmanagerRetriever) Alertmanagers() []*url.URL { return nil }

Expand Down
2 changes: 1 addition & 1 deletion web/ui/react-app/src/pages/graph/SeriesName.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, useContext } from 'react';
import React, { FC } from 'react';
import { useToastContext } from '../../contexts/ToastContext';
import { metricToSeriesName } from '../../utils';

Expand Down
Loading

0 comments on commit 5b09780

Please sign in to comment.