feat(prometheus): add label and family transformers
parent
1062a5defa
commit
51ef08a13a
|
@ -0,0 +1,35 @@
|
|||
package prometheus
|
||||
|
||||
import dto "github.com/prometheus/client_model/go"
|
||||
|
||||
// labelPairSorter implements sort.Interface. It is used to sort a slice of
|
||||
// dto.LabelPair pointers.
|
||||
type labelPairSorter []*dto.LabelPair
|
||||
|
||||
func (s labelPairSorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s labelPairSorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s labelPairSorter) Less(i, j int) bool {
|
||||
return s[i].GetName() < s[j].GetName()
|
||||
}
|
||||
|
||||
// familySorter implements sort.Interface. It is used to sort a slice of
|
||||
// dto.MetricFamily pointers.
|
||||
type familySorter []*dto.MetricFamily
|
||||
|
||||
func (s familySorter) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s familySorter) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s familySorter) Less(i, j int) bool {
|
||||
return s[i].GetName() < s[j].GetName()
|
||||
}
|
|
@ -1,9 +1,90 @@
|
|||
package prometheus
|
||||
|
||||
import dto "github.com/prometheus/client_model/go"
|
||||
import (
|
||||
"sort"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
// Transformer modifies prometheus metrics families.
|
||||
type Transformer interface {
|
||||
// Transform updates the metrics family
|
||||
Transform(mfs []*dto.MetricFamily) []*dto.MetricFamily
|
||||
}
|
||||
|
||||
var _ Transformer = (*AddLabels)(nil)
|
||||
|
||||
// AddLabels adds labels to all metrics. It will overwrite
|
||||
// the label if it already exists.
|
||||
type AddLabels struct {
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
// Transform adds labels to the metrics.
|
||||
func (a *AddLabels) Transform(mfs []*dto.MetricFamily) []*dto.MetricFamily {
|
||||
for i := range mfs {
|
||||
for j, m := range mfs[i].Metric {
|
||||
// Filter out labels to add
|
||||
labels := m.Label[:0]
|
||||
for _, l := range m.Label {
|
||||
if _, ok := a.Labels[l.GetName()]; !ok {
|
||||
labels = append(labels, l)
|
||||
}
|
||||
}
|
||||
|
||||
// Add all new labels to the metric
|
||||
for k, v := range a.Labels {
|
||||
labels = append(labels, L(k, v))
|
||||
}
|
||||
sort.Sort(labelPairSorter(labels))
|
||||
mfs[i].Metric[j].Label = labels
|
||||
}
|
||||
}
|
||||
return mfs
|
||||
}
|
||||
|
||||
var _ Transformer = (*RemoveLabels)(nil)
|
||||
|
||||
// RemoveLabels adds labels to all metrics. It will overwrite
|
||||
// the label if it already exists.
|
||||
type RemoveLabels struct {
|
||||
Labels map[string]struct{}
|
||||
}
|
||||
|
||||
// Transform removes labels from the metrics.
|
||||
func (r *RemoveLabels) Transform(mfs []*dto.MetricFamily) []*dto.MetricFamily {
|
||||
for i := range mfs {
|
||||
for j, m := range mfs[i].Metric {
|
||||
// Filter out labels
|
||||
labels := m.Label[:0]
|
||||
for _, l := range m.Label {
|
||||
if _, ok := r.Labels[l.GetName()]; !ok {
|
||||
labels = append(labels, l)
|
||||
}
|
||||
}
|
||||
mfs[i].Metric[j].Label = labels
|
||||
}
|
||||
}
|
||||
return mfs
|
||||
}
|
||||
|
||||
var _ Transformer = (*RenameFamilies)(nil)
|
||||
|
||||
// RenameFamilies changes the name of families to another name
|
||||
type RenameFamilies struct {
|
||||
FromTo map[string]string
|
||||
}
|
||||
|
||||
// Transform renames metric families names.
|
||||
func (r *RenameFamilies) Transform(mfs []*dto.MetricFamily) []*dto.MetricFamily {
|
||||
renamed := mfs[:0]
|
||||
for _, mf := range mfs {
|
||||
if to, ok := r.FromTo[mf.GetName()]; ok {
|
||||
mf.Name = &to
|
||||
}
|
||||
renamed = append(renamed, mf)
|
||||
|
||||
}
|
||||
sort.Sort(familySorter(renamed))
|
||||
return renamed
|
||||
}
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
package prometheus_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
pr "github.com/influxdata/influxdb/prometheus"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
func TestAddLabels_Transform(t *testing.T) {
|
||||
type fields struct {
|
||||
Labels map[string]string
|
||||
}
|
||||
type args struct {
|
||||
mfs []*dto.MetricFamily
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want []*dto.MetricFamily
|
||||
}{
|
||||
{
|
||||
name: "add label from metric replaces label",
|
||||
fields: fields{
|
||||
Labels: map[string]string{
|
||||
"handler": "influxdb",
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
mfs: []*dto.MetricFamily{
|
||||
NewCounter("http_api_requests_total", 10,
|
||||
pr.L("handler", "platform"),
|
||||
pr.L("method", "GET"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
},
|
||||
},
|
||||
want: []*dto.MetricFamily{
|
||||
NewCounter("http_api_requests_total", 10,
|
||||
pr.L("handler", "influxdb"),
|
||||
pr.L("method", "GET"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add label from metric replaces label",
|
||||
fields: fields{
|
||||
Labels: map[string]string{
|
||||
"org": "myorg",
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
mfs: []*dto.MetricFamily{
|
||||
NewCounter("http_api_requests_total", 10,
|
||||
pr.L("handler", "platform"),
|
||||
pr.L("method", "GET"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
},
|
||||
},
|
||||
want: []*dto.MetricFamily{
|
||||
NewCounter("http_api_requests_total", 10,
|
||||
pr.L("handler", "platform"),
|
||||
pr.L("method", "GET"),
|
||||
pr.L("org", "myorg"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &pr.AddLabels{
|
||||
Labels: tt.fields.Labels,
|
||||
}
|
||||
if got := a.Transform(tt.args.mfs); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("AddLabels.Transform() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveLabels_Transform(t *testing.T) {
|
||||
type fields struct {
|
||||
Labels map[string]struct{}
|
||||
}
|
||||
type args struct {
|
||||
mfs []*dto.MetricFamily
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want []*dto.MetricFamily
|
||||
}{
|
||||
{
|
||||
name: "remove label from metric",
|
||||
fields: fields{
|
||||
Labels: map[string]struct{}{
|
||||
"handler": struct{}{},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
mfs: []*dto.MetricFamily{
|
||||
NewCounter("http_api_requests_total", 10,
|
||||
pr.L("handler", "platform"),
|
||||
pr.L("method", "GET"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
},
|
||||
},
|
||||
want: []*dto.MetricFamily{
|
||||
NewCounter("http_api_requests_total", 10,
|
||||
pr.L("method", "GET"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no match removes no labels",
|
||||
fields: fields{
|
||||
Labels: map[string]struct{}{
|
||||
"handler": struct{}{},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
mfs: []*dto.MetricFamily{
|
||||
NewCounter("http_api_requests_total", 10,
|
||||
pr.L("method", "GET"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
},
|
||||
},
|
||||
want: []*dto.MetricFamily{
|
||||
NewCounter("http_api_requests_total", 10,
|
||||
pr.L("method", "GET"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &pr.RemoveLabels{
|
||||
Labels: tt.fields.Labels,
|
||||
}
|
||||
if got := r.Transform(tt.args.mfs); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("RemoveLabels.Transform() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenameFamilies_Transform(t *testing.T) {
|
||||
type fields struct {
|
||||
FromTo map[string]string
|
||||
}
|
||||
type args struct {
|
||||
mfs []*dto.MetricFamily
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want []*dto.MetricFamily
|
||||
}{
|
||||
{
|
||||
name: "rename metric family in sort order",
|
||||
fields: fields{
|
||||
FromTo: map[string]string{
|
||||
"http_api_requests_total": "api_requests_total",
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
mfs: []*dto.MetricFamily{
|
||||
NewCounter("handler", 10,
|
||||
pr.L("handler", "platform"),
|
||||
),
|
||||
NewCounter("http_api_requests_total", 10,
|
||||
pr.L("handler", "platform"),
|
||||
pr.L("method", "GET"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
},
|
||||
},
|
||||
want: []*dto.MetricFamily{
|
||||
NewCounter("api_requests_total", 10,
|
||||
pr.L("handler", "platform"),
|
||||
pr.L("method", "GET"),
|
||||
pr.L("path", "/api/v2"),
|
||||
pr.L("status", "2XX"),
|
||||
),
|
||||
NewCounter("handler", 10,
|
||||
pr.L("handler", "platform"),
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ignored if not found",
|
||||
fields: fields{
|
||||
FromTo: map[string]string{
|
||||
"http_api_requests_total": "api_requests_total",
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
mfs: []*dto.MetricFamily{
|
||||
NewCounter("handler", 10,
|
||||
pr.L("handler", "platform"),
|
||||
),
|
||||
},
|
||||
},
|
||||
want: []*dto.MetricFamily{
|
||||
NewCounter("handler", 10,
|
||||
pr.L("handler", "platform"),
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &pr.RenameFamilies{
|
||||
FromTo: tt.fields.FromTo,
|
||||
}
|
||||
if got := r.Transform(tt.args.mfs); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("RenameFamilies.Transform() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue