Skip to content

Commit a09fb87

Browse files
authored
Merge pull request #2774 from byyML/master
ADD "disable_specific_metrics" which can remove specific metric by name or regex
2 parents 58ab9b1 + 9d8c85c commit a09fb87

13 files changed

+711
-15
lines changed

cmd/cadvisor.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ var (
113113
container.ResctrlMetrics: struct{}{},
114114
container.CPUSetMetrics: struct{}{},
115115
}
116+
// metrics to be ignored,the difference between ignoreMetrics and ignoreSpecificMetrics is the former filters a certain type of metrics and the later filters specific metrics.
117+
ignoreSpecificMetrics DenyList = DenyList{}
116118
)
117119

118120
type metricSetValue struct {
@@ -142,8 +144,27 @@ func (ml *metricSetValue) Set(value string) error {
142144
return nil
143145
}
144146

147+
type DenyList []string
148+
149+
func (ms *DenyList) String() string {
150+
return strings.Join(*ms, ",")
151+
}
152+
153+
// Set converts a comma-separated string of metrics into a slice and appends it to the DenyList.
154+
func (ms *DenyList) Set(value string) error {
155+
metrics := strings.Split(value, ",")
156+
for _, metric := range metrics {
157+
metric = strings.TrimSpace(metric)
158+
if len(metric) != 0 {
159+
*ms = append(*ms, metric)
160+
}
161+
}
162+
return nil
163+
}
164+
145165
func init() {
146166
flag.Var(&ignoreMetrics, "disable_metrics", "comma-separated list of `metrics` to be disabled. Options are 'accelerator', 'cpu_topology','disk', 'diskIO', 'memory_numa', 'network', 'tcp', 'udp', 'percpu', 'sched', 'process', 'hugetlb', 'referenced_memory', 'resctrl', 'cpuset'.")
167+
flag.Var(&ignoreSpecificMetrics, "disable_specific_metrics", "Comma-separated list of metrics not to be enabled. This list comprises of exact metric names and/or regex patterns.It differs from the 'disable_metrics' in that 'disable_specific_metrics' filters specific metrics, while 'disable_metrics' filters a certain type of metrics.Besides, 'disable_specific_metrics' will only disable metrics being exported by Prometheus ")
147168

148169
// Default logging verbosity to V(2)
149170
flag.Set("v", "2")
@@ -160,6 +181,7 @@ func main() {
160181
}
161182

162183
includedMetrics := toIncludedMetrics(ignoreMetrics.MetricSet)
184+
denyList, err := metrics.NewDenyList(ignoreSpecificMetrics)
163185

164186
setMaxProcs()
165187

@@ -172,7 +194,7 @@ func main() {
172194

173195
collectorHttpClient := createCollectorHttpClient(*collectorCert, *collectorKey)
174196

175-
resourceManager, err := manager.New(memoryStorage, sysFs, housekeepingConfig, includedMetrics, &collectorHttpClient, strings.Split(*rawCgroupPrefixWhiteList, ","), *perfEvents)
197+
resourceManager, err := manager.New(memoryStorage, sysFs, housekeepingConfig, includedMetrics, &collectorHttpClient, strings.Split(*rawCgroupPrefixWhiteList, ","), *perfEvents, denyList)
176198
if err != nil {
177199
klog.Fatalf("Failed to create a manager: %s", err)
178200
}
@@ -199,7 +221,7 @@ func main() {
199221
}
200222

201223
// Register Prometheus collector to gather information about containers, Go runtime, processes, and machine
202-
cadvisorhttp.RegisterPrometheusHandler(mux, resourceManager, *prometheusEndpoint, containerLabelFunc, includedMetrics)
224+
cadvisorhttp.RegisterPrometheusHandler(mux, resourceManager, *prometheusEndpoint, containerLabelFunc, includedMetrics, denyList)
203225

204226
// Start the manager.
205227
if err := resourceManager.Start(); err != nil {

cmd/internal/http/handlers.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@ func RegisterHandlers(mux httpmux.Mux, containerManager manager.Manager, httpAut
9595
// RegisterPrometheusHandler creates a new PrometheusCollector and configures
9696
// the provided HTTP mux to handle the given Prometheus endpoint.
9797
func RegisterPrometheusHandler(mux httpmux.Mux, resourceManager manager.Manager, prometheusEndpoint string,
98-
f metrics.ContainerLabelsFunc, includedMetrics container.MetricSet) {
98+
f metrics.ContainerLabelsFunc, includedMetrics container.MetricSet, denyList *metrics.DenyList) {
9999
goCollector := prometheus.NewGoCollector()
100100
processCollector := prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{})
101-
machineCollector := metrics.NewPrometheusMachineCollector(resourceManager, includedMetrics)
101+
machineCollector := metrics.NewPrometheusMachineCollector(resourceManager, includedMetrics, denyList)
102102

103103
mux.Handle(prometheusEndpoint, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
104104
opts, err := api.GetRequestOptions(req)
@@ -111,7 +111,7 @@ func RegisterPrometheusHandler(mux httpmux.Mux, resourceManager manager.Manager,
111111

112112
r := prometheus.NewRegistry()
113113
r.MustRegister(
114-
metrics.NewPrometheusCollector(resourceManager, f, includedMetrics, clock.RealClock{}, opts),
114+
metrics.NewPrometheusCollector(resourceManager, f, includedMetrics, clock.RealClock{}, opts, denyList),
115115
machineCollector,
116116
goCollector,
117117
processCollector,

manager/manager.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
info "github.com/google/cadvisor/info/v1"
3838
"github.com/google/cadvisor/info/v2"
3939
"github.com/google/cadvisor/machine"
40+
"github.com/google/cadvisor/metrics"
4041
"github.com/google/cadvisor/nvm"
4142
"github.com/google/cadvisor/perf"
4243
"github.com/google/cadvisor/resctrl"
@@ -146,7 +147,7 @@ type HouskeepingConfig = struct {
146147
}
147148

148149
// New takes a memory storage and returns a new manager.
149-
func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, houskeepingConfig HouskeepingConfig, includedMetricsSet container.MetricSet, collectorHTTPClient *http.Client, rawContainerCgroupPathPrefixWhiteList []string, perfEventsFile string) (Manager, error) {
150+
func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, houskeepingConfig HouskeepingConfig, includedMetricsSet container.MetricSet, collectorHTTPClient *http.Client, rawContainerCgroupPathPrefixWhiteList []string, perfEventsFile string, denyList *metrics.DenyList) (Manager, error) {
150151
if memoryCache == nil {
151152
return nil, fmt.Errorf("manager requires memory storage")
152153
}
@@ -198,6 +199,7 @@ func New(memoryCache *memory.InMemoryCache, sysfs sysfs.SysFs, houskeepingConfig
198199
maxHousekeepingInterval: *houskeepingConfig.Interval,
199200
allowDynamicHousekeeping: *houskeepingConfig.AllowDynamic,
200201
includedMetrics: includedMetricsSet,
202+
DenyList: denyList,
201203
containerWatchers: []watcher.ContainerWatcher{},
202204
eventsChannel: eventsChannel,
203205
collectorHTTPClient: collectorHTTPClient,
@@ -257,6 +259,7 @@ type manager struct {
257259
maxHousekeepingInterval time.Duration
258260
allowDynamicHousekeeping bool
259261
includedMetrics container.MetricSet
262+
DenyList *metrics.DenyList
260263
containerWatchers []watcher.ContainerWatcher
261264
eventsChannel chan watcher.ContainerEvent
262265
collectorHTTPClient *http.Client

metrics/deny_list.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2021 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package metrics
16+
17+
import (
18+
"regexp"
19+
)
20+
21+
// DenyList encapsulates the logic needed to filter based on a string.
22+
type DenyList struct {
23+
rList []*regexp.Regexp
24+
}
25+
26+
// New constructs a new DenyList based on a white- and a
27+
// DenyList. Only one of them can be not empty.
28+
func NewDenyList(b []string) (*DenyList, error) {
29+
l := &DenyList{}
30+
var regs []*regexp.Regexp
31+
for _, item := range b {
32+
r, err := regexp.Compile(item)
33+
if err != nil {
34+
return nil, err
35+
}
36+
regs = append(regs, r)
37+
}
38+
l.rList = regs
39+
return l, nil
40+
}
41+
42+
// IsIncluded returns if the given item is included.
43+
func (l *DenyList) IsDenied(item string) bool {
44+
var matched bool
45+
for _, r := range l.rList {
46+
matched = r.MatchString(item)
47+
if matched {
48+
break
49+
}
50+
}
51+
52+
return matched
53+
}

metrics/deny_list_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2021 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package metrics
16+
17+
import (
18+
"bufio"
19+
"io"
20+
"strings"
21+
22+
"github.com/stretchr/testify/assert"
23+
"os"
24+
"testing"
25+
)
26+
27+
var (
28+
ignoreSpecificMetrics = []string{"^machine_(memory|cpu).*", "^container_fs_*", "^container_cpu_*", "^container_blkio_.*"}
29+
)
30+
31+
func TestNewDenyList(t *testing.T) {
32+
denyList, err := NewDenyList(ignoreSpecificMetrics)
33+
assert.Nil(t, err)
34+
35+
testDenyListIsDenied(t, denyList, "testdata/deny_metrics")
36+
testDenyListAllowed(t, denyList, "testdata/allow_metrics")
37+
38+
}
39+
40+
func testDenyListIsDenied(t *testing.T, denyList *DenyList, metricsFile string) {
41+
deniedMetrics, err := os.Open(metricsFile)
42+
if err != nil {
43+
t.Fatalf("unable to read input test file %s", metricsFile)
44+
}
45+
buf := bufio.NewReader(deniedMetrics)
46+
for {
47+
line, err := buf.ReadString('\n')
48+
line = strings.TrimSpace(line)
49+
if err != nil {
50+
if err == io.EOF {
51+
break
52+
}
53+
}
54+
assert.True(t, denyList.IsDenied(line))
55+
56+
}
57+
}
58+
59+
func testDenyListAllowed(t *testing.T, denyList *DenyList, metricsFile string) {
60+
allowedMetrics, err := os.Open(metricsFile)
61+
if err != nil {
62+
t.Fatalf("unable to read input test file %s", metricsFile)
63+
}
64+
buf := bufio.NewReader(allowedMetrics)
65+
for {
66+
line, err := buf.ReadString('\n')
67+
line = strings.TrimSpace(line)
68+
if err != nil {
69+
if err == io.EOF {
70+
break
71+
}
72+
}
73+
assert.False(t, denyList.IsDenied(line))
74+
}
75+
}

metrics/prometheus.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ type PrometheusCollector struct {
105105
// ContainerLabelsFunc specifies which base labels will be attached to all
106106
// exported metrics. If left to nil, the DefaultContainerLabels function
107107
// will be used instead.
108-
func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetrics container.MetricSet, now clock.Clock, opts v2.RequestOptions) *PrometheusCollector {
108+
func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetrics container.MetricSet, now clock.Clock, opts v2.RequestOptions, denyList *DenyList) *PrometheusCollector {
109109
if f == nil {
110110
f = DefaultContainerLabels
111111
}
@@ -1757,6 +1757,13 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetri
17571757
},
17581758
}...)
17591759
}
1760+
var filtered []containerMetric
1761+
for _, val := range c.containerMetrics {
1762+
if !denyList.IsDenied(val.name) {
1763+
filtered = append(filtered, val)
1764+
}
1765+
}
1766+
c.containerMetrics = filtered
17601767
return c
17611768
}
17621769

metrics/prometheus_machine.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ type PrometheusMachineCollector struct {
6767
}
6868

6969
// NewPrometheusMachineCollector returns a new PrometheusCollector.
70-
func NewPrometheusMachineCollector(i infoProvider, includedMetrics container.MetricSet) *PrometheusMachineCollector {
70+
func NewPrometheusMachineCollector(i infoProvider, includedMetrics container.MetricSet, denyList *DenyList) *PrometheusMachineCollector {
7171
c := &PrometheusMachineCollector{
7272

7373
infoProvider: i,
@@ -192,6 +192,13 @@ func NewPrometheusMachineCollector(i infoProvider, includedMetrics container.Met
192192
},
193193
}...)
194194
}
195+
var filtered []machineMetric
196+
for _, val := range c.machineMetrics {
197+
if !denyList.IsDenied(val.name) {
198+
filtered = append(filtered, val)
199+
}
200+
}
201+
c.machineMetrics = filtered
195202
return c
196203
}
197204

metrics/prometheus_machine_test.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ package metrics
1717
import (
1818
"bytes"
1919
"io/ioutil"
20+
"os"
2021
"reflect"
2122
"testing"
2223
"time"
2324

2425
"github.com/google/cadvisor/container"
2526
"github.com/prometheus/client_golang/prometheus"
27+
"github.com/prometheus/client_golang/prometheus/testutil"
2628
"github.com/prometheus/common/expfmt"
2729
"github.com/stretchr/testify/assert"
2830
)
@@ -31,7 +33,9 @@ const machineMetricsFile = "testdata/prometheus_machine_metrics"
3133
const machineMetricsFailureFile = "testdata/prometheus_machine_metrics_failure"
3234

3335
func TestPrometheusMachineCollector(t *testing.T) {
34-
collector := NewPrometheusMachineCollector(testSubcontainersInfoProvider{}, container.AllMetrics)
36+
denyList, err := NewDenyList([]string{})
37+
assert.Nil(t, err)
38+
collector := NewPrometheusMachineCollector(testSubcontainersInfoProvider{}, container.AllMetrics, denyList)
3539
registry := prometheus.NewRegistry()
3640
registry.MustRegister(collector)
3741

@@ -51,11 +55,13 @@ func TestPrometheusMachineCollector(t *testing.T) {
5155
}
5256

5357
func TestPrometheusMachineCollectorWithFailure(t *testing.T) {
58+
denyList, err := NewDenyList([]string{})
59+
assert.Nil(t, err)
5460
provider := &erroringSubcontainersInfoProvider{
5561
successfulProvider: testSubcontainersInfoProvider{},
5662
shouldFail: true,
5763
}
58-
collector := NewPrometheusMachineCollector(provider, container.AllMetrics)
64+
collector := NewPrometheusMachineCollector(provider, container.AllMetrics, denyList)
5965
registry := prometheus.NewRegistry()
6066
registry.MustRegister(collector)
6167

@@ -73,6 +79,29 @@ func TestPrometheusMachineCollectorWithFailure(t *testing.T) {
7379
assert.Equal(t, string(expectedMetrics), collectedMetrics)
7480
}
7581

82+
func TestPrometheusMachineCollectorWithDenyList(t *testing.T) {
83+
denyList, err := NewDenyList(ignoreSpecificMetrics)
84+
assert.Nil(t, err)
85+
cMachine := NewPrometheusMachineCollector(testSubcontainersInfoProvider{}, container.AllMetrics, denyList)
86+
registry := prometheus.NewRegistry()
87+
registry.MustRegister(cMachine)
88+
89+
testPrometheusMachineCollectorWithIsDenied(t, registry, "testdata/prometheus_machine_metrics_denylist")
90+
91+
}
92+
93+
func testPrometheusMachineCollectorWithIsDenied(t *testing.T, gatherer prometheus.Gatherer, metricsFile string) {
94+
wantMetrics, err := os.Open(metricsFile)
95+
if err != nil {
96+
t.Fatalf("unable to read input test file %s", metricsFile)
97+
}
98+
99+
err = testutil.GatherAndCompare(gatherer, wantMetrics)
100+
if err != nil {
101+
t.Fatalf("Metric comparison failed: %s", err)
102+
}
103+
}
104+
76105
func TestGetMemoryByType(t *testing.T) {
77106
machineInfo, err := testSubcontainersInfoProvider{}.GetMachineInfo()
78107
assert.Nil(t, err)

0 commit comments

Comments
 (0)