Skip to content

Commit

Permalink
Merge pull request prometheus#2234 from brancz/targets-api
Browse files Browse the repository at this point in the history
web/api: add targets endpoint
fabxc authored Dec 5, 2016
2 parents 63fe65b + 33b583d commit 0459dcd
Showing 7 changed files with 154 additions and 74 deletions.
18 changes: 9 additions & 9 deletions retrieval/target.go
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ const (
// Target refers to a singular HTTP or HTTPS endpoint.
type Target struct {
// Labels before any processing.
metaLabels model.LabelSet
discoveredLabels model.LabelSet
// Any labels that are added to this target and its metrics.
labels model.LabelSet
// Additional URL parmeters that are part of the target URL.
@@ -58,12 +58,12 @@ type Target struct {
}

// NewTarget creates a reasonably configured target for querying.
func NewTarget(labels, metaLabels model.LabelSet, params url.Values) *Target {
func NewTarget(labels, discoveredLabels model.LabelSet, params url.Values) *Target {
return &Target{
labels: labels,
metaLabels: metaLabels,
params: params,
health: HealthUnknown,
labels: labels,
discoveredLabels: discoveredLabels,
params: params,
health: HealthUnknown,
}
}

@@ -144,9 +144,9 @@ func (t *Target) Labels() model.LabelSet {
return lset
}

// MetaLabels returns a copy of the target's labels before any processing.
func (t *Target) MetaLabels() model.LabelSet {
return t.metaLabels.Clone()
// DiscoveredLabels returns a copy of the target's labels before any processing.
func (t *Target) DiscoveredLabels() model.LabelSet {
return t.discoveredLabels.Clone()
}

// URL returns a copy of the target's URL.
19 changes: 6 additions & 13 deletions retrieval/targetmanager.go
Original file line number Diff line number Diff line change
@@ -14,11 +14,9 @@
package retrieval

import (
"sort"
"sync"

"github.com/prometheus/common/log"
"github.com/prometheus/common/model"
"golang.org/x/net/context"

"github.com/prometheus/prometheus/config"
@@ -133,28 +131,23 @@ func (tm *TargetManager) reload() {
}
}

// Pools returns the targets currently being scraped bucketed by their job name.
func (tm *TargetManager) Pools() map[string]Targets {
// Targets returns the targets currently being scraped bucketed by their job name.
func (tm *TargetManager) Targets() []Target {
tm.mtx.RLock()
defer tm.mtx.RUnlock()

pools := map[string]Targets{}

// TODO(fabxc): this is just a hack to maintain compatibility for now.
targets := []Target{}
for _, ps := range tm.targetSets {
ps.sp.mtx.RLock()

for _, t := range ps.sp.targets {
job := string(t.Labels()[model.JobLabel])
pools[job] = append(pools[job], t)
targets = append(targets, *t)
}

ps.sp.mtx.RUnlock()
}
for _, targets := range pools {
sort.Sort(targets)
}
return pools

return targets
}

// ApplyConfig resets the manager's target providers and job configurations as defined
57 changes: 52 additions & 5 deletions web/api/v1/api.go
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ import (
"golang.org/x/net/context"

"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/retrieval"
"github.com/prometheus/prometheus/storage/local"
"github.com/prometheus/prometheus/storage/metric"
"github.com/prometheus/prometheus/util/httputil"
@@ -66,6 +67,10 @@ func (e *apiError) Error() string {
return fmt.Sprintf("%s: %s", e.typ, e.err)
}

type targetRetriever interface {
Targets() []retrieval.Target
}

type response struct {
Status status `json:"status"`
Data interface{} `json:"data,omitempty"`
@@ -88,17 +93,20 @@ type API struct {
Storage local.Storage
QueryEngine *promql.Engine

targetRetriever targetRetriever

context func(r *http.Request) context.Context
now func() model.Time
}

// NewAPI returns an initialized API type.
func NewAPI(qe *promql.Engine, st local.Storage) *API {
func NewAPI(qe *promql.Engine, st local.Storage, tr targetRetriever) *API {
return &API{
QueryEngine: qe,
Storage: st,
context: route.Context,
now: model.Now,
QueryEngine: qe,
Storage: st,
targetRetriever: tr,
context: route.Context,
now: model.Now,
}
}

@@ -129,6 +137,8 @@ func (api *API) Register(r *route.Router) {

r.Get("/series", instr("series", api.series))
r.Del("/series", instr("drop_series", api.dropSeries))

r.Get("/targets", instr("targets", api.targets))
}

type queryData struct {
@@ -328,6 +338,43 @@ func (api *API) dropSeries(r *http.Request) (interface{}, *apiError) {
return res, nil
}

type Target struct {
// Labels before any processing.
DiscoveredLabels model.LabelSet `json:"discoveredLabels"`
// Any labels that are added to this target and its metrics.
Labels model.LabelSet `json:"labels"`

ScrapeUrl string `json:"scrapeUrl"`

LastError string `json:"lastError"`
LastScrape time.Time `json:"lastScrape"`
Health retrieval.TargetHealth `json:"health"`
}

func (api *API) targets(r *http.Request) (interface{}, *apiError) {
targets := api.targetRetriever.Targets()
res := make([]*Target, len(targets))

for i, t := range targets {
lastErrStr := ""
lastErr := t.LastError()
if lastErr != nil {
lastErrStr = lastErr.Error()
}

res[i] = &Target{
DiscoveredLabels: t.DiscoveredLabels(),
Labels: t.Labels(),
ScrapeUrl: t.URL().String(),
LastError: lastErrStr,
LastScrape: t.LastScrape(),
Health: t.Health(),
}
}

return res, nil
}

func respond(w http.ResponseWriter, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
39 changes: 36 additions & 3 deletions web/api/v1/api_test.go
Original file line number Diff line number Diff line change
@@ -30,8 +30,15 @@ import (
"golang.org/x/net/context"

"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/retrieval"
)

type targetRetrieverFunc func() []retrieval.Target

func (f targetRetrieverFunc) Targets() []retrieval.Target {
return f()
}

func TestEndpoints(t *testing.T) {
suite, err := promql.NewTest(t, `
load 1m
@@ -49,10 +56,26 @@ func TestEndpoints(t *testing.T) {
}

now := model.Now()

tr := targetRetrieverFunc(func() []retrieval.Target {
return []retrieval.Target{
*retrieval.NewTarget(
model.LabelSet{
model.SchemeLabel: "http",
model.AddressLabel: "example.com:8080",
model.MetricsPathLabel: "/metrics",
},
model.LabelSet{},
url.Values{},
),
}
})

api := &API{
Storage: suite.Storage(),
QueryEngine: suite.QueryEngine(),
now: func() model.Time { return now },
Storage: suite.Storage(),
QueryEngine: suite.QueryEngine(),
targetRetriever: tr,
now: func() model.Time { return now },
}

start := model.Time(0)
@@ -404,6 +427,16 @@ func TestEndpoints(t *testing.T) {
response: struct {
NumDeleted int `json:"numDeleted"`
}{2},
}, {
endpoint: api.targets,
response: []*Target{
&Target{
DiscoveredLabels: model.LabelSet{},
Labels: model.LabelSet{},
ScrapeUrl: "http://example.com:8080/metrics",
Health: "unknown",
},
},
},
}

Loading

0 comments on commit 0459dcd

Please sign in to comment.