Skip to content

Commit 4359600

Browse files
Add network device dimension and option to filter by it
1 parent 71392e5 commit 4359600

File tree

9 files changed

+266
-53
lines changed

9 files changed

+266
-53
lines changed

receiver/hostmetricsreceiver/README.md

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
11
# Host Metrics Receiver
22

3-
The Host Metrics receiver generates metrics about the host system. This is
4-
intended to be used when the collector is deployed as an agent.
3+
The Host Metrics receiver generates metrics about the host system scraped
4+
from various sources. This is intended to be used when the collector is
5+
deployed as an agent.
56

6-
The categories of metrics scraped can be configured under the `scrapers` key.
7-
For example:
7+
If you are only interested in a subset of metrics from a particular source,
8+
it is recommended you use this receiver with the `Filter` processor.
9+
10+
## Configuration
11+
12+
The collection interval and the categories of metrics to be scraped can be
13+
configured:
814

915
```yaml
1016
hostmetrics:
11-
collection_interval: 1m
17+
collection_interval: <duration> # default = 1m
1218
scrapers:
13-
cpu:
14-
memory:
15-
disk:
19+
<scraper1>:
20+
<scraper2>:
21+
...
1622
```
1723

1824
If you would like to scrape some metrics at a different frequency than others,
1925
you can configure multiple `hostmetrics` receivers with different
20-
`collection_interval values`. For example:
26+
`collection_interval` values. For example:
2127

2228
```yaml
2329
receivers:
@@ -38,3 +44,56 @@ service:
3844
metrics:
3945
receivers: [hostmetrics, hostmetrics/disk]
4046
```
47+
48+
## Scrapers
49+
50+
The available scrapers are:
51+
52+
- **CPU**: CPU utilization metrics
53+
- **Disk**: Disk I/O metrics
54+
- **Load**: CPU load metrics
55+
- **File System**: File System utilization metrics
56+
- **Memory**: Memory utilization metrics
57+
- **Network**: Network interface I/O metrics & TCP connection metrics
58+
- **Processes** (not supported on Windows): Process count metrics
59+
- **Swap**: Swap space utilization and I/O metrics
60+
- **Process** (Linux & Windows only): Per process CPU, Memory, and Disk I/O metrics
61+
62+
Several scrapers support additional configuration:
63+
64+
#### Disk
65+
66+
```yaml
67+
disk:
68+
<include|exclude>:
69+
devices: [ <device name> ... ]
70+
match_type: <strict|regexp>
71+
```
72+
73+
#### File System
74+
75+
```yaml
76+
filesystem:
77+
<include|exclude>:
78+
devices: [ <device name> ... ]
79+
match_type: <strict|regexp>
80+
```
81+
82+
#### Network
83+
84+
```yaml
85+
network:
86+
<include|exclude>:
87+
interfaces: [ <interface name> ... ]
88+
match_type: <strict|regexp>
89+
```
90+
91+
#### Process
92+
93+
```yaml
94+
process:
95+
disk:
96+
<include|exclude>:
97+
names: [ <process name> ... ]
98+
match_type: <strict|regexp>
99+
```

receiver/hostmetricsreceiver/config_test.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,17 @@ func TestLoadConfig(t *testing.T) {
7171
loadscraper.TypeStr: &loadscraper.Config{},
7272
filesystemscraper.TypeStr: &filesystemscraper.Config{},
7373
memoryscraper.TypeStr: &memoryscraper.Config{},
74-
networkscraper.TypeStr: &networkscraper.Config{},
75-
processesscraper.TypeStr: &processesscraper.Config{},
76-
swapscraper.TypeStr: &swapscraper.Config{},
74+
networkscraper.TypeStr: &networkscraper.Config{
75+
Include: networkscraper.MatchConfig{
76+
Interfaces: []string{"test1"},
77+
Config: filterset.Config{MatchType: "strict"},
78+
},
79+
},
80+
processesscraper.TypeStr: &processesscraper.Config{},
81+
swapscraper.TypeStr: &swapscraper.Config{},
7782
processscraper.TypeStr: &processscraper.Config{
7883
Include: processscraper.MatchConfig{
79-
Names: []string{"test1", "test2"},
84+
Names: []string{"test2", "test3"},
8085
Config: filterset.Config{MatchType: "regexp"},
8186
},
8287
},

receiver/hostmetricsreceiver/internal/scraper/networkscraper/config.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,24 @@
1414

1515
package networkscraper
1616

17-
import "go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal"
17+
import (
18+
"go.opentelemetry.io/collector/internal/processor/filterset"
19+
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal"
20+
)
1821

1922
// Config relating to Network Metric Scraper.
2023
type Config struct {
2124
internal.ConfigSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct
25+
26+
// Include specifies a filter on the network interfaces that should be included from the generated metrics.
27+
// Exclude specifies a filter on the network interfaces that should be excluded from the generated metrics.
28+
// If neither `include` or `exclude` are set, metrics will be generated for all network interfaces.
29+
Include MatchConfig `mapstructure:"include"`
30+
Exclude MatchConfig `mapstructure:"exclude"`
31+
}
32+
33+
type MatchConfig struct {
34+
filterset.Config `mapstructure:",squash"`
35+
36+
Interfaces []string `mapstructure:"interfaces"`
2237
}

receiver/hostmetricsreceiver/internal/scraper/networkscraper/factory.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ func (f *Factory) CreateMetricsScraper(
4545
logger *zap.Logger,
4646
config internal.Config,
4747
) (internal.Scraper, error) {
48-
cfg := config.(*Config)
49-
return obsreportscraper.WrapScraper(newNetworkScraper(ctx, cfg), TypeStr), nil
48+
scraper, err := newNetworkScraper(ctx, config.(*Config))
49+
if err != nil {
50+
return nil, err
51+
}
52+
53+
return obsreportscraper.WrapScraper(scraper, TypeStr), nil
5054
}

receiver/hostmetricsreceiver/internal/scraper/networkscraper/factory_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,12 @@ func TestCreateMetricsScraper(t *testing.T) {
3737
assert.NoError(t, err)
3838
assert.NotNil(t, scraper)
3939
}
40+
41+
func TestCreateMetricsScraper_Error(t *testing.T) {
42+
factory := &Factory{}
43+
cfg := &Config{Include: MatchConfig{Interfaces: []string{""}}}
44+
45+
_, err := factory.CreateMetricsScraper(context.Background(), zap.NewNop(), cfg)
46+
47+
assert.Error(t, err)
48+
}

receiver/hostmetricsreceiver/internal/scraper/networkscraper/network_metadata.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
// network metric constants
2222

2323
const (
24+
interfaceLabelName = "interface"
2425
directionLabelName = "direction"
2526
stateLabelName = "state"
2627
)

receiver/hostmetricsreceiver/internal/scraper/networkscraper/network_scraper.go

Lines changed: 96 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,23 @@ package networkscraper
1616

1717
import (
1818
"context"
19+
"fmt"
1920
"time"
2021

2122
"github.com/shirou/gopsutil/host"
2223
"github.com/shirou/gopsutil/net"
2324

2425
"go.opentelemetry.io/collector/component/componenterror"
2526
"go.opentelemetry.io/collector/consumer/pdata"
27+
"go.opentelemetry.io/collector/internal/processor/filterset"
2628
)
2729

2830
// scraper for Network Metrics
2931
type scraper struct {
3032
config *Config
3133
startTime pdata.TimestampUnixNano
34+
includeFS filterset.FilterSet
35+
excludeFS filterset.FilterSet
3236

3337
// for mocking
3438
bootTime func() (uint64, error)
@@ -37,8 +41,26 @@ type scraper struct {
3741
}
3842

3943
// newNetworkScraper creates a set of Network related metrics
40-
func newNetworkScraper(_ context.Context, cfg *Config) *scraper {
41-
return &scraper{config: cfg, bootTime: host.BootTime, ioCounters: net.IOCounters, connections: net.Connections}
44+
func newNetworkScraper(_ context.Context, cfg *Config) (*scraper, error) {
45+
scraper := &scraper{config: cfg, bootTime: host.BootTime, ioCounters: net.IOCounters, connections: net.Connections}
46+
47+
var err error
48+
49+
if len(cfg.Include.Interfaces) > 0 {
50+
scraper.includeFS, err = filterset.CreateFilterSet(cfg.Include.Interfaces, &cfg.Include.Config)
51+
if err != nil {
52+
return nil, fmt.Errorf("error creating network interface include filters: %w", err)
53+
}
54+
}
55+
56+
if len(cfg.Exclude.Interfaces) > 0 {
57+
scraper.excludeFS, err = filterset.CreateFilterSet(cfg.Exclude.Interfaces, &cfg.Exclude.Config)
58+
if err != nil {
59+
return nil, fmt.Errorf("error creating network interface exclude filters: %w", err)
60+
}
61+
}
62+
63+
return scraper, nil
4264
}
4365

4466
// Initialize
@@ -82,33 +104,73 @@ func (s *scraper) ScrapeMetrics(_ context.Context) (pdata.MetricSlice, error) {
82104

83105
func (s *scraper) scrapeAndAppendNetworkCounterMetrics(metrics pdata.MetricSlice, startTime pdata.TimestampUnixNano) error {
84106
// get total stats only
85-
networkStatsSlice, err := s.ioCounters( /*perNetworkInterfaceController=*/ false)
107+
ioCounters, err := s.ioCounters( /*perNetworkInterfaceController=*/ true)
86108
if err != nil {
87109
return err
88110
}
89111

90-
networkStats := networkStatsSlice[0]
112+
// filter network interfaces by name
113+
ioCounters = s.filterByInterface(ioCounters)
114+
115+
if len(ioCounters) > 0 {
116+
startIdx := metrics.Len()
117+
metrics.Resize(startIdx + 4)
118+
initializeNetworkPacketsMetric(metrics.At(startIdx+0), networkPacketsDescriptor, startTime, ioCounters)
119+
initializeNetworkDroppedPacketsMetric(metrics.At(startIdx+1), networkDroppedPacketsDescriptor, startTime, ioCounters)
120+
initializeNetworkErrorsMetric(metrics.At(startIdx+2), networkErrorsDescriptor, startTime, ioCounters)
121+
initializeNetworkIOMetric(metrics.At(startIdx+3), networkIODescriptor, startTime, ioCounters)
122+
}
91123

92-
startIdx := metrics.Len()
93-
metrics.Resize(startIdx + 4)
94-
initializeNetworkMetric(metrics.At(startIdx+0), networkPacketsDescriptor, startTime, networkStats.PacketsSent, networkStats.PacketsRecv)
95-
initializeNetworkMetric(metrics.At(startIdx+1), networkDroppedPacketsDescriptor, startTime, networkStats.Dropout, networkStats.Dropin)
96-
initializeNetworkMetric(metrics.At(startIdx+2), networkErrorsDescriptor, startTime, networkStats.Errout, networkStats.Errin)
97-
initializeNetworkMetric(metrics.At(startIdx+3), networkIODescriptor, startTime, networkStats.BytesSent, networkStats.BytesRecv)
98124
return nil
99125
}
100126

101-
func initializeNetworkMetric(metric pdata.Metric, metricDescriptor pdata.MetricDescriptor, startTime pdata.TimestampUnixNano, transmitValue, receiveValue uint64) {
127+
func initializeNetworkPacketsMetric(metric pdata.Metric, metricDescriptor pdata.MetricDescriptor, startTime pdata.TimestampUnixNano, ioCountersSlice []net.IOCountersStat) {
102128
metricDescriptor.CopyTo(metric.MetricDescriptor())
103129

104130
idps := metric.Int64DataPoints()
105-
idps.Resize(2)
106-
initializeNetworkDataPoint(idps.At(0), startTime, transmitDirectionLabelValue, int64(transmitValue))
107-
initializeNetworkDataPoint(idps.At(1), startTime, receiveDirectionLabelValue, int64(receiveValue))
131+
idps.Resize(2 * len(ioCountersSlice))
132+
for idx, ioCounters := range ioCountersSlice {
133+
initializeNetworkDataPoint(idps.At(2*idx+0), startTime, ioCounters.Name, transmitDirectionLabelValue, int64(ioCounters.PacketsSent))
134+
initializeNetworkDataPoint(idps.At(2*idx+1), startTime, ioCounters.Name, receiveDirectionLabelValue, int64(ioCounters.PacketsRecv))
135+
}
108136
}
109137

110-
func initializeNetworkDataPoint(dataPoint pdata.Int64DataPoint, startTime pdata.TimestampUnixNano, directionLabel string, value int64) {
138+
func initializeNetworkDroppedPacketsMetric(metric pdata.Metric, metricDescriptor pdata.MetricDescriptor, startTime pdata.TimestampUnixNano, ioCountersSlice []net.IOCountersStat) {
139+
metricDescriptor.CopyTo(metric.MetricDescriptor())
140+
141+
idps := metric.Int64DataPoints()
142+
idps.Resize(2 * len(ioCountersSlice))
143+
for idx, ioCounters := range ioCountersSlice {
144+
initializeNetworkDataPoint(idps.At(2*idx+0), startTime, ioCounters.Name, transmitDirectionLabelValue, int64(ioCounters.Dropout))
145+
initializeNetworkDataPoint(idps.At(2*idx+1), startTime, ioCounters.Name, receiveDirectionLabelValue, int64(ioCounters.Dropin))
146+
}
147+
}
148+
149+
func initializeNetworkErrorsMetric(metric pdata.Metric, metricDescriptor pdata.MetricDescriptor, startTime pdata.TimestampUnixNano, ioCountersSlice []net.IOCountersStat) {
150+
metricDescriptor.CopyTo(metric.MetricDescriptor())
151+
152+
idps := metric.Int64DataPoints()
153+
idps.Resize(2 * len(ioCountersSlice))
154+
for idx, ioCounters := range ioCountersSlice {
155+
initializeNetworkDataPoint(idps.At(2*idx+0), startTime, ioCounters.Name, transmitDirectionLabelValue, int64(ioCounters.Errout))
156+
initializeNetworkDataPoint(idps.At(2*idx+1), startTime, ioCounters.Name, receiveDirectionLabelValue, int64(ioCounters.Errin))
157+
}
158+
}
159+
160+
func initializeNetworkIOMetric(metric pdata.Metric, metricDescriptor pdata.MetricDescriptor, startTime pdata.TimestampUnixNano, ioCountersSlice []net.IOCountersStat) {
161+
metricDescriptor.CopyTo(metric.MetricDescriptor())
162+
163+
idps := metric.Int64DataPoints()
164+
idps.Resize(2 * len(ioCountersSlice))
165+
for idx, ioCounters := range ioCountersSlice {
166+
initializeNetworkDataPoint(idps.At(2*idx+0), startTime, ioCounters.Name, transmitDirectionLabelValue, int64(ioCounters.BytesSent))
167+
initializeNetworkDataPoint(idps.At(2*idx+1), startTime, ioCounters.Name, receiveDirectionLabelValue, int64(ioCounters.BytesRecv))
168+
}
169+
}
170+
171+
func initializeNetworkDataPoint(dataPoint pdata.Int64DataPoint, startTime pdata.TimestampUnixNano, interfaceLabel, directionLabel string, value int64) {
111172
labelsMap := dataPoint.LabelsMap()
173+
labelsMap.Insert(interfaceLabelName, interfaceLabel)
112174
labelsMap.Insert(directionLabelName, directionLabel)
113175
dataPoint.SetStartTime(startTime)
114176
dataPoint.SetTimestamp(pdata.TimestampUnixNano(uint64(time.Now().UnixNano())))
@@ -170,3 +232,22 @@ func initializeNetworkTCPConnectionsDataPoint(dataPoint pdata.Int64DataPoint, st
170232
dataPoint.SetTimestamp(pdata.TimestampUnixNano(uint64(time.Now().UnixNano())))
171233
dataPoint.SetValue(value)
172234
}
235+
236+
func (s *scraper) filterByInterface(ioCounters []net.IOCountersStat) []net.IOCountersStat {
237+
if s.includeFS == nil && s.excludeFS == nil {
238+
return ioCounters
239+
}
240+
241+
filteredIOCounters := make([]net.IOCountersStat, 0, len(ioCounters))
242+
for _, io := range ioCounters {
243+
if s.includeInterface(io.Name) {
244+
filteredIOCounters = append(filteredIOCounters, io)
245+
}
246+
}
247+
return filteredIOCounters
248+
}
249+
250+
func (s *scraper) includeInterface(interfaceName string) bool {
251+
return (s.includeFS == nil || s.includeFS.Matches(interfaceName)) &&
252+
(s.excludeFS == nil || !s.excludeFS.Matches(interfaceName))
253+
}

0 commit comments

Comments
 (0)