Skip to content

Commit 155b05a

Browse files
authored
TT-6799 Prometheus pump: Support to disable certain metric families from exposition. (#492)
* support disabling prometheus metric families * update readme and changelog * fix language * disabling of metrics should only work for the base metrics * do not collect and log out disabled metrics * exclude base metrics entirely if they are disabled * checkpoint * update docs
1 parent ba8a4b5 commit 155b05a

File tree

5 files changed

+74
-23
lines changed

5 files changed

+74
-23
lines changed

Diff for: CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
- Initial connector which outputs all analytics into a single elasticsearch index
66
- Enabled the ES connecter to save all output to a rolling index rather than a static index
7+
- Add support to the Prometheus pump to exclude metric families from exposition
78

89
## v0.1
910

1011
- Initial connector to replace MongoDB connector in Tyk
11-
- Added support for uptime purging (redis/mongo only)
12+
- Added support for uptime purging (redis/mongo only)

Diff for: README.md

+2
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ Tyk expose the following counters:
483483
And the following Histogram for latencies:
484484
- tyk_latency{type, api}
485485

486+
Note: base metric families can be removed by configuring the `disabled_metrics` property.
486487

487488
#### Custom Prometheus metrics
488489
From Pump 1.6+ it's possible to add custom prometheus metrics using the `custom_metrics` configuration.
@@ -536,6 +537,7 @@ TYK_PMP_PUMPS_PROMETHEUS_TYPE=prometheus
536537
TYK_PMP_PUMPS_PROMETHEUS_META_ADDR=localhost:9090
537538
TYK_PMP_PUMPS_PROMETHEUS_META_PATH=/metrics
538539
TYK_PMP_PUMPS_PROMETHEUS_META_CUSTOMMETRICS=[]
540+
TYK_PMP_PUMPS_PROMETHEUS_META_DISABLED_METRICS=[]
539541
```
540542

541543
## DogStatsD

Diff for: go.sum

-1
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,6 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
324324
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
325325
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
326326
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
327-
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
328327
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
329328
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
330329
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=

Diff for: pumps/prometheus.go

+33-17
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ type PrometheusConf struct {
3939
// This will enable an experimental feature that will aggregate the histogram metrics request time values before exposing them to prometheus.
4040
// Enabling this will reduce the CPU usage of your prometheus pump but you will loose histogram precision. Experimental.
4141
AggregateObservations bool `json:"aggregate_observations" mapstructure:"aggregate_observations"`
42+
// Metrics to exclude from exposition. Currently, excludes only the base metrics.
43+
DisabledMetrics []string `json:"disabled_metrics" mapstructure:"disabled_metrics"`
4244
// Custom Prometheus metrics.
4345
CustomMetrics []PrometheusMetric `json:"custom_metrics" mapstructure:"custom_metrics"`
4446
}
@@ -69,7 +71,7 @@ type PrometheusMetric struct {
6971
aggregatedObservations bool
7072
}
7173

72-
//histogramCounter is a helper struct to mantain the totalRequestTime and hits in memory
74+
// histogramCounter is a helper struct to mantain the totalRequestTime and hits in memory
7375
type histogramCounter struct {
7476
totalRequestTime uint64
7577
hits uint64
@@ -91,7 +93,7 @@ func (p *PrometheusPump) New() Pump {
9193
return &newPump
9294
}
9395

94-
//CreateBasicMetrics stores all the predefined pump metrics in allMetrics slice
96+
// CreateBasicMetrics stores all the predefined pump metrics in allMetrics slice
9597
func (p *PrometheusPump) CreateBasicMetrics() {
9698

9799
//counter metrics
@@ -160,13 +162,7 @@ func (p *PrometheusPump) Init(conf interface{}) error {
160162
}
161163

162164
//first we init the base metrics
163-
for _, metric := range p.allMetrics {
164-
metric.aggregatedObservations = p.conf.AggregateObservations
165-
errInit := metric.InitVec()
166-
if errInit != nil {
167-
p.log.Error(errInit)
168-
}
169-
}
165+
p.initBaseMetrics()
170166

171167
//then we check the custom ones
172168
p.InitCustomMetrics()
@@ -183,7 +179,27 @@ func (p *PrometheusPump) Init(conf interface{}) error {
183179
return nil
184180
}
185181

186-
//InitCustomMetrics initialise custom prometheus metrics based on p.conf.CustomMetrics and add them into p.allMetrics
182+
func (p *PrometheusPump) initBaseMetrics() {
183+
toDisableSet := map[string]struct{}{}
184+
for _, metric := range p.conf.DisabledMetrics {
185+
toDisableSet[metric] = struct{}{}
186+
}
187+
// exclude disabled base metrics if needed. This disables exposition entirely during scrapes.
188+
trimmedAllMetrics := make([]*PrometheusMetric, 0, len(p.allMetrics))
189+
for _, metric := range p.allMetrics {
190+
if _, isDisabled := toDisableSet[metric.Name]; isDisabled {
191+
continue
192+
}
193+
metric.aggregatedObservations = p.conf.AggregateObservations
194+
if errInit := metric.InitVec(); errInit != nil {
195+
p.log.Error(errInit)
196+
}
197+
trimmedAllMetrics = append(trimmedAllMetrics, metric)
198+
}
199+
p.allMetrics = trimmedAllMetrics
200+
}
201+
202+
// InitCustomMetrics initialise custom prometheus metrics based on p.conf.CustomMetrics and add them into p.allMetrics
187203
func (p *PrometheusPump) InitCustomMetrics() {
188204
if len(p.conf.CustomMetrics) > 0 {
189205
customMetrics := []*PrometheusMetric{}
@@ -358,7 +374,7 @@ func (pm *PrometheusMetric) GetLabelsValues(decoded analytics.AnalyticsRecord) [
358374
return values
359375
}
360376

361-
//Inc is going to fill counterMap and histogramMap with the data from record.
377+
// Inc is going to fill counterMap and histogramMap with the data from record.
362378
func (pm *PrometheusMetric) Inc(values ...string) error {
363379
switch pm.MetricType {
364380
case COUNTER_TYPE:
@@ -370,7 +386,7 @@ func (pm *PrometheusMetric) Inc(values ...string) error {
370386
return nil
371387
}
372388

373-
//Observe will fill hitogramMap with the sum of totalRequest and hits per label value if aggregate_observations is true. If aggregate_observations is set to false (default) it will execute prometheus Observe directly.
389+
// Observe will fill hitogramMap with the sum of totalRequest and hits per label value if aggregate_observations is true. If aggregate_observations is set to false (default) it will execute prometheus Observe directly.
374390
func (pm *PrometheusMetric) Observe(requestTime int64, values ...string) error {
375391
switch pm.MetricType {
376392
case HISTOGRAM_TYPE:
@@ -399,10 +415,10 @@ func (pm *PrometheusMetric) Observe(requestTime int64, values ...string) error {
399415
return nil
400416
}
401417

402-
//Expose executes prometheus library functions using the counter/histogram vector from the PrometheusMetric struct.
403-
//If the PrometheusMetric is COUNTER_TYPE, it will execute prometheus client Add function to add the counters from counterMap to the labels value metric
404-
//If the PrometheusMetric is HISTOGRAM_TYPE and aggregate_observations config is true, it will calculate the average value of the metrics in the histogramMap and execute prometheus Observe.
405-
//If aggregate_observations is false, it won't do anything since it means that we already exposed the metric.
418+
// Expose executes prometheus library functions using the counter/histogram vector from the PrometheusMetric struct.
419+
// If the PrometheusMetric is COUNTER_TYPE, it will execute prometheus client Add function to add the counters from counterMap to the labels value metric
420+
// If the PrometheusMetric is HISTOGRAM_TYPE and aggregate_observations config is true, it will calculate the average value of the metrics in the histogramMap and execute prometheus Observe.
421+
// If aggregate_observations is false, it won't do anything since it means that we already exposed the metric.
406422
func (pm *PrometheusMetric) Expose() error {
407423
switch pm.MetricType {
408424
case COUNTER_TYPE:
@@ -426,7 +442,7 @@ func (pm *PrometheusMetric) Expose() error {
426442
return nil
427443
}
428444

429-
//getAverageRequestTime returns the average request time of an histogramCounter dividing the sum of all the RequestTimes by the hits.
445+
// getAverageRequestTime returns the average request time of an histogramCounter dividing the sum of all the RequestTimes by the hits.
430446
func (c histogramCounter) getAverageRequestTime() float64 {
431447
return float64(c.totalRequestTime / c.hits)
432448
}

Diff for: pumps/prometheus_test.go

+37-4
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ package pumps
22

33
import (
44
"errors"
5+
"io"
56
"testing"
67

78
"github.com/TykTechnologies/tyk-pump/analytics"
89
"github.com/prometheus/client_golang/prometheus"
10+
"github.com/sirupsen/logrus"
911
"github.com/stretchr/testify/assert"
1012
)
1113

12-
func TestInitVec(t *testing.T) {
14+
func TestPrometheusInitVec(t *testing.T) {
1315
tcs := []struct {
1416
testName string
1517
customMetric PrometheusMetric
@@ -82,7 +84,7 @@ func TestInitVec(t *testing.T) {
8284
}
8385
}
8486

85-
func TestInitCustomMetrics(t *testing.T) {
87+
func TestPrometheusInitCustomMetrics(t *testing.T) {
8688
tcs := []struct {
8789
testName string
8890
metrics []PrometheusMetric
@@ -183,7 +185,7 @@ func TestInitCustomMetrics(t *testing.T) {
183185
}
184186
}
185187

186-
func TestGetLabelsValues(t *testing.T) {
188+
func TestPrometheusGetLabelsValues(t *testing.T) {
187189
tcs := []struct {
188190
testName string
189191
customMetric PrometheusMetric
@@ -539,7 +541,7 @@ func TestPrometheusCreateBasicMetrics(t *testing.T) {
539541

540542
}
541543

542-
func TestEnsureLabels(t *testing.T) {
544+
func TestPrometheusEnsureLabels(t *testing.T) {
543545
testCases := []struct {
544546
name string
545547
metricType string
@@ -601,3 +603,34 @@ func TestEnsureLabels(t *testing.T) {
601603
})
602604
}
603605
}
606+
607+
func TestPrometheusDisablingMetrics(t *testing.T) {
608+
p := &PrometheusPump{}
609+
newPump := p.New().(*PrometheusPump)
610+
611+
log := logrus.New()
612+
log.Out = io.Discard
613+
newPump.log = logrus.NewEntry(log)
614+
615+
newPump.conf = &PrometheusConf{DisabledMetrics: []string{"tyk_http_status_per_path"}}
616+
617+
newPump.initBaseMetrics()
618+
619+
defer func() {
620+
for i := range newPump.allMetrics {
621+
if newPump.allMetrics[i].MetricType == COUNTER_TYPE {
622+
prometheus.Unregister(newPump.allMetrics[i].counterVec)
623+
} else if newPump.allMetrics[i].MetricType == HISTOGRAM_TYPE {
624+
prometheus.Unregister(newPump.allMetrics[i].histogramVec)
625+
}
626+
}
627+
}()
628+
629+
metricMap := map[string]*PrometheusMetric{}
630+
for _, metric := range newPump.allMetrics {
631+
metricMap[metric.Name] = metric
632+
}
633+
634+
assert.Contains(t, metricMap, "tyk_http_status")
635+
assert.NotContains(t, metricMap, "tyk_http_status_per_path")
636+
}

0 commit comments

Comments
 (0)