Skip to content

Commit

Permalink
Move servergroup label filtering
Browse files Browse the repository at this point in the history
Now that we have nice layer-able promclients it makes more sense to
consolidate this logic into the promclient instead of into the
servergroup.

In addition to the simplification in code, this has the added benefit of
allowing the user to have a lot more control over the merge behavior.
Before this patch if there was a difference in value between the
relabel_config output it would be ignored and a warning would be
printed. Now if there is a difference it will still be applied-- which
means you can effectively control merging behavior.
  • Loading branch information
jacksontj committed Mar 27, 2019
1 parent e995f16 commit b5c4dd3
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 167 deletions.
145 changes: 145 additions & 0 deletions promclient/label.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package promclient

import (
"context"
"time"

v1 "github.com/prometheus/client_golang/api/prometheus/v1"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/promql"

"github.com/jacksontj/promxy/promhttputil"
)

func MergeLabelValues(a, b []model.LabelValue) []model.LabelValue {
Expand Down Expand Up @@ -35,3 +43,140 @@ func MergeLabelSets(a, b []model.LabelSet) []model.LabelSet {

return a
}

// AddLabelClient proxies a client and adds the given labels to all results
type AddLabelClient struct {
API
Labels model.LabelSet
}

// LabelValues performs a query for the values of the given label.
func (c *AddLabelClient) LabelValues(ctx context.Context, label string) (model.LabelValues, error) {
val, err := c.API.LabelValues(ctx, label)
if err != nil {
return nil, err
}

// do we have labels that match in our state
if value, ok := c.Labels[model.LabelName(label)]; ok {
return MergeLabelValues(val, model.LabelValues{value}), nil
}
return val, nil
}

// Query performs a query for the given time.
func (c *AddLabelClient) Query(ctx context.Context, query string, ts time.Time) (model.Value, error) {
// Parse out the promql query into expressions etc.
e, err := promql.ParseExpr(query)
if err != nil {
return nil, err
}

// Walk the expression, to filter out any LabelMatchers that match etc.
filterVisitor := &LabelFilterVisitor{c.Labels, true}
if _, err := promql.Walk(ctx, filterVisitor, &promql.EvalStmt{Expr: e}, e, nil, nil); err != nil {
return nil, err
}
if !filterVisitor.filterMatch {
return nil, nil
}

val, err := c.API.Query(ctx, e.String(), ts)
if err != nil {
return nil, err
}
if err := promhttputil.ValueAddLabelSet(val, c.Labels); err != nil {
return nil, err
}
return val, nil
}

// QueryRange performs a query for the given range.
func (c *AddLabelClient) QueryRange(ctx context.Context, query string, r v1.Range) (model.Value, error) {
// Parse out the promql query into expressions etc.
e, err := promql.ParseExpr(query)
if err != nil {
return nil, err
}

// Walk the expression, to filter out any LabelMatchers that match etc.
filterVisitor := &LabelFilterVisitor{c.Labels, true}
if _, err := promql.Walk(ctx, filterVisitor, &promql.EvalStmt{Expr: e}, e, nil, nil); err != nil {
return nil, err
}
if !filterVisitor.filterMatch {
return nil, nil
}

val, err := c.API.QueryRange(ctx, e.String(), r)
if err != nil {
return nil, err
}
if err := promhttputil.ValueAddLabelSet(val, c.Labels); err != nil {
return nil, err
}
return val, nil
}

// Series finds series by label matchers.
func (c *AddLabelClient) Series(ctx context.Context, matches []string, startTime time.Time, endTime time.Time) ([]model.LabelSet, error) {
// Now we need to filter the matches sent to us for the labels associated with this
// servergroup
filteredMatches := make([]string, 0, len(matches))
for _, matcher := range matches {
// Parse out the promql query into expressions etc.
e, err := promql.ParseExpr(matcher)
if err != nil {
return nil, err
}

// Walk the expression, to filter out any LabelMatchers that match etc.
filterVisitor := &LabelFilterVisitor{c.Labels, true}
if _, err := promql.Walk(ctx, filterVisitor, &promql.EvalStmt{Expr: e}, e, nil, nil); err != nil {
return nil, err
}
// If we didn't match, lets skip
if !filterVisitor.filterMatch {
continue
}
// if we did match, lets assign the filtered version of the matcher
filteredMatches = append(filteredMatches, e.String())
}

// If no matchers remain, then we don't have anything -- so skip
if len(filteredMatches) == 0 {
return nil, nil
}

v, err := c.API.Series(ctx, filteredMatches, startTime, endTime)
if err != nil {
return nil, err
}

// add our state's labels to the labelsets we return
for _, lset := range v {
for k, v := range c.Labels {
lset[k] = v
}
}

return v, nil
}

// GetValue loads the raw data for a given set of matchers in the time range
func (c *AddLabelClient) GetValue(ctx context.Context, start, end time.Time, matchers []*labels.Matcher) (model.Value, error) {
filteredMatchers, ok := FilterMatchers(c.Labels, matchers)
if !ok {
return nil, nil
}

val, err := c.API.GetValue(ctx, start, end, filteredMatchers)
if err != nil {
return nil, err
}
if err := promhttputil.ValueAddLabelSet(val, c.Labels); err != nil {
return nil, err
}

return val, nil
}
3 changes: 1 addition & 2 deletions servergroup/labelfilter.go → promclient/labelfilter.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package servergroup
package promclient

import (
"github.com/prometheus/common/model"
Expand All @@ -7,7 +7,6 @@ import (
)

type LabelFilterVisitor struct {
s *ServerGroup
ls model.LabelSet
filterMatch bool
}
Expand Down
Loading

0 comments on commit b5c4dd3

Please sign in to comment.