Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add constant labels for the metrics (#385) #386

Merged
merged 20 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cmd/easeprobe/probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ import (
"sync"
"time"

log "github.com/sirupsen/logrus"

"github.com/megaease/easeprobe/channel"
"github.com/megaease/easeprobe/conf"
"github.com/megaease/easeprobe/global"
"github.com/megaease/easeprobe/probe"
log "github.com/sirupsen/logrus"
)

func configProbers(probers []probe.Prober) []probe.Prober {
conf.MergeConstLabels(probers)

gProbeConf := global.ProbeSettings{
Interval: conf.Get().Settings.Probe.Interval,
Timeout: conf.Get().Settings.Probe.Timeout,
Expand Down
35 changes: 35 additions & 0 deletions conf/constlables.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package conf

import (
"github.com/megaease/easeprobe/probe"
)

// MergeConstLabels merge const labels from all probers.
//
// Prometheus requires all metric of the same name have the same set of labels in a collector
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
//
// Prometheus requires all metric of the same name have the same set of labels in a collector
// Prometheus requires all metric of the same name have the same set of labels in a collector

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

func MergeConstLabels(ps []probe.Prober) {
var constLabels = make(map[string]bool)
for _, p := range ps {
for k, _ := range p.LabelMap() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

please fix this and the following code lint warnings

Copy link
Contributor Author

@qdongxu qdongxu Aug 19, 2023

Choose a reason for hiding this comment

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

updated.

constLabels[k] = true
}
}

for _, p := range ps {
buildConstLabels(p, constLabels)
}
}

func buildConstLabels(p probe.Prober, constLabels map[string]bool) {
ls := p.LabelMap()
if ls == nil {
ls = make(map[string]string)
p.SetLabelMap(ls)
}

for k, _ := range constLabels {
if _, ok := ls[k]; !ok {
ls[k] = ""
}
}
}
45 changes: 45 additions & 0 deletions conf/constlables_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package conf

import (
"testing"

"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"

"github.com/megaease/easeprobe/probe"
"github.com/megaease/easeprobe/probe/base"
"github.com/megaease/easeprobe/probe/http"
"github.com/megaease/easeprobe/probe/shell"
"github.com/megaease/easeprobe/probe/tcp"
)

func TestMergeConstLabels(t *testing.T) {

ps := []probe.Prober{
&http.HTTP{
DefaultProbe: base.DefaultProbe{
Labels: prometheus.Labels{"service": "service_a"},
},
},
&tcp.TCP{
DefaultProbe: base.DefaultProbe{
Labels: prometheus.Labels{"host": "host_b"},
},
},
&shell.Shell{},
}

MergeConstLabels(ps)

assert.Equal(t, 2, len(ps[0].LabelMap()))
assert.Equal(t, "service_a", ps[0].LabelMap()["service"])
assert.Equal(t, "", ps[0].LabelMap()["host"])

assert.Equal(t, 2, len(ps[1].LabelMap()))
assert.Equal(t, "", ps[1].LabelMap()["service"])
assert.Equal(t, "host_b", ps[1].LabelMap()["host"])

assert.Equal(t, 2, len(ps[2].LabelMap()))
assert.Equal(t, "", ps[2].LabelMap()["service"])
assert.Equal(t, "", ps[2].LabelMap()["host"])
}
12 changes: 11 additions & 1 deletion docs/Manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ The following is an example of the alerting interval for HTTP Probe:
http:
- name: Web Service
url: https://example.com:1080
labels:
service: web_example
env: wg-idc-prod
alert:
strategy: regular
factor: 1
Expand Down Expand Up @@ -273,7 +276,9 @@ http:
# A Website
- name: MegaEase Website (Global)
url: https://megaease.com

labels:
team: ease
owner: megaease
# Some of the Software support the HTTP Query
- name: ElasticSearch
url: https://elasticsearch.server:9200
Expand Down Expand Up @@ -513,6 +518,8 @@ tcp:
interval: 2m # default is 60 seconds
proxy: socks5:https://proxy.server:1080 # Optional. Only support socks5.
# Also support the `ALL_PROXY` environment.
labels:
env: production
- name: Kafka
host: kafka.server:9093
```
Expand All @@ -532,6 +539,9 @@ ping:
privileged: true # if true, the ping will be executed with icmp, otherwise use udp, default: false (Note: On Windows platform, this must be set to True)
timeout: 10s # default is 30 seconds
interval: 2m # default is 60 seconds
labels:
env: development
role: primary
```

## 1.5 Shell
Expand Down
54 changes: 45 additions & 9 deletions metric/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type MetricsType interface {
}

var (
registries = make([]*prometheus.Registry, 0)
counterMap = make(map[string]*prometheus.CounterVec)
gaugeMap = make(map[string]*prometheus.GaugeVec)
histogramMap = make(map[string]*prometheus.HistogramVec)
Expand All @@ -57,11 +58,12 @@ func Gauge(key string) *prometheus.GaugeVec {

// NewCounter create the counter metric
func NewCounter(namespace, subsystem, name, metric string,
help string, labels []string) *prometheus.CounterVec {
help string, labels []string, constLabels prometheus.Labels) *prometheus.CounterVec {

metricName, err := getAndValid(namespace, subsystem, name, metric, labels)
metricName, err := getAndValid(namespace, subsystem, name, metric, labels, constLabels)
if err != nil {
log.Errorf("[%s] %v", module, err)
log.Errorf("[namespace: %s, subsystem: %s, name: %s, metric: %s] %v",
namespace, subsystem, name, metric, err)
return nil
}

Expand All @@ -75,23 +77,25 @@ func NewCounter(namespace, subsystem, name, metric string,
Name: metricName,
Help: help,
},
labels,
mergeLabels(labels, constLabels),
)
prometheus.MustRegister(counterMap[metricName])

// registries[len(registries)-1].MustRegister(m)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// registries[len(registries)-1].MustRegister(m)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated.

prometheus.MustRegister(counterMap[metricName])
log.Infof("[%s] Counter <%s> is created!", module, metricName)
return counterMap[metricName]
}

// NewGauge create the gauge metric
func NewGauge(namespace, subsystem, name, metric string,
help string, labels []string) *prometheus.GaugeVec {
help string, labels []string, constLabels prometheus.Labels) *prometheus.GaugeVec {

metricName, err := getAndValid(namespace, subsystem, name, metric, labels)
metricName, err := getAndValid(namespace, subsystem, name, metric, labels, constLabels)
if err != nil {
log.Errorf("[%s] %v", module, err)
return nil
}

if m, find := gaugeMap[metricName]; find {
log.Debugf("[%s] Gauge <%s> already created!", module, metricName)
return m
Expand All @@ -102,15 +106,27 @@ func NewGauge(namespace, subsystem, name, metric string,
Name: metricName,
Help: help,
},
labels,
mergeLabels(labels, constLabels),
)

prometheus.MustRegister(gaugeMap[metricName])

log.Infof("[%s] Gauge <%s> is created!", module, metricName)
return gaugeMap[metricName]
}

func getAndValid(namespace, subsystem, name, metric string, labels []string) (string, error) {
func mergeLabels(labels []string, constLabels prometheus.Labels) []string {
l := make([]string, 0, len(labels)+len(constLabels))
l = append(l, labels...)

for k, _ := range constLabels {
l = append(l, k)
}

return l
}

func getAndValid(namespace, subsystem, name, metric string, labels []string, constLabels prometheus.Labels) (string, error) {
metricName := GetName(namespace, subsystem, name, metric)
if ValidMetricName(metricName) == false {
return "", fmt.Errorf("Invalid metric name: %s", metricName)
Expand All @@ -121,6 +137,19 @@ func getAndValid(namespace, subsystem, name, metric string, labels []string) (st
return "", fmt.Errorf("Invalid label name: %s", l)
}
}

for l, _ := range constLabels {
if !ValidLabelName(l) {
return "", fmt.Errorf("invalid const label name: %s", l)
}
}

for _, l := range labels {
if _, ok := constLabels[l]; ok {
return "", fmt.Errorf("label '%s' is duplicated", l)
}
}

return metricName, nil
}

Expand Down Expand Up @@ -179,3 +208,10 @@ func RemoveInvalidChars(name string) string {
}
return string(result)
}

func AddConstLabels(labels prometheus.Labels, constLabels prometheus.Labels) prometheus.Labels {
for k, v := range constLabels {
labels[k] = v
}
Comment on lines +212 to +214
Copy link
Collaborator

Choose a reason for hiding this comment

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

should check if a label exists both in labels and constLabels and report the error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated

return labels
}
30 changes: 21 additions & 9 deletions metric/prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"testing"

"bou.ke/monkey"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -65,12 +66,12 @@ func TestGetName(t *testing.T) {

func TestNewMetrics(t *testing.T) {
NewCounter("namespace", "subsystem", "counter", "metric",
"help", []string{"label1", "label2"})
"help", []string{"label1", "label2"}, prometheus.Labels{})
assert.NotNil(t, GetName("namespace_subsystem_counter_metric"))
assert.NotNil(t, Counter("namespace_subsystem_counter_metric"))

NewGauge("namespace", "subsystem", "gauge", "metric",
"help", []string{"label1", "label2"})
"help", []string{"label1", "label2"}, prometheus.Labels{})
assert.NotNil(t, GetName("namespace_subsystem_gauge_metric"))
assert.NotNil(t, Gauge("namespace_subsystem_gauge_metric"))
}
Expand Down Expand Up @@ -110,35 +111,46 @@ func TestName(t *testing.T) {

func TestDuplicateName(t *testing.T) {
counter1 := NewCounter("namespace", "subsystem", "counter", "metric",
"help", []string{})
"help", []string{}, prometheus.Labels{})
counter2 := NewCounter("namespace", "subsystem", "counter", "metric",
"help", []string{})
"help", []string{}, prometheus.Labels{})
assert.Equal(t, counter1, counter2)

gauge1 := NewGauge("namespace", "subsystem", "gauge", "metric",
"help", []string{})
"help", []string{}, prometheus.Labels{})
gauge2 := NewGauge("namespace", "subsystem", "gauge", "metric",
"help", []string{})
"help", []string{}, prometheus.Labels{})
assert.Equal(t, gauge1, gauge2)
}

func TestInvalidName(t *testing.T) {

//label errors
counter := NewCounter("namespace", "subsystem", "counter", "metric",
"help", []string{"label-1", "label:2"})
"help", []string{"label-1", "label:2"}, prometheus.Labels{})
assert.Nil(t, counter)

gauge := NewGauge("namespace", "subsystem", "gauge", "metric",
"help", []string{"label-1", "label:2"})
"help", []string{"label-1", "label:2"}, prometheus.Labels{})
assert.Nil(t, gauge)

monkey.Patch(ValidMetricName, func(name string) bool {
return false
})
counter = NewCounter("namespace", "subsystem", "counter", "metric",
"help", []string{})
"help", []string{}, prometheus.Labels{})
assert.Nil(t, counter)

monkey.UnpatchAll()
}

func TestDuplicateLabels(t *testing.T) {

_, err := getAndValid("namespace", "subsystem", "counter", "metric",
[]string{"label1", "label2"}, prometheus.Labels{"label3": "value3"})
assert.Nil(t, err)

_, err = getAndValid("namespace", "subsystem", "counter", "metric",
[]string{"label1", "label2"}, prometheus.Labels{"label1": "value1"})
assert.Error(t, err)
}
Loading
Loading