Skip to content

Commit

Permalink
[receiver/windowsperfcounter] Move configs from pkg/winperfcounters (#…
Browse files Browse the repository at this point in the history
…10022)

This refactoring reduces coupling between `windowsperfcounterreceiver` and `pkg/winperfcounters` packages by moving config structs specific to `windowsperfcounterreceiver` along with other logic related to the configs from `pkg/winperfcounters`.
  • Loading branch information
dmitryax authored May 20, 2022
1 parent 97c74ec commit 8eec12f
Show file tree
Hide file tree
Showing 17 changed files with 252 additions and 378 deletions.
33 changes: 0 additions & 33 deletions pkg/winperfcounters/config.go

This file was deleted.

32 changes: 0 additions & 32 deletions pkg/winperfcounters/config_windows.go

This file was deleted.

2 changes: 0 additions & 2 deletions pkg/winperfcounters/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ go 1.17

require (
github.com/stretchr/testify v1.7.1
go.uber.org/multierr v1.8.0
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
)

Expand All @@ -13,7 +12,6 @@ require (
github.com/kr/pretty v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.6.2 // indirect
go.uber.org/atomic v1.9.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
Expand Down
7 changes: 0 additions & 7 deletions pkg/winperfcounters/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 6 additions & 80 deletions pkg/winperfcounters/watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ package winperfcounters // import "github.com/open-telemetry/opentelemetry-colle
import (
"fmt"

"go.uber.org/multierr"

"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/winperfcounters/internal/pdh"
"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/winperfcounters/internal/third_party/telegraf/win_perf_counters"
)

// TODO: This package became redundant as a wrapper. pkg/winperfcounters/internal/pdh can be moved here.

var _ PerfCounterWatcher = (*Watcher)(nil)

// PerfCounterWatcher represents how to scrape data
Expand All @@ -35,16 +36,11 @@ type PerfCounterWatcher interface {
ScrapeData() ([]CounterValue, error)
// Close all counters/handles related to the query and free all associated memory.
Close() error
// GetMetricRep gets the representation of the metric the watcher is connected to
GetMetricRep() MetricRep
}

const instanceLabelName = "instance"
type CounterValue = win_perf_counters.CounterValue

type Watcher struct {
Counter *pdh.PerfCounter
MetricRep
}
type Watcher = pdh.PerfCounter

// NewWatcher creates new PerfCounterWatcher by provided parts of its path.
func NewWatcher(object, instance, counterName string) (PerfCounterWatcher, error) {
Expand All @@ -53,72 +49,7 @@ func NewWatcher(object, instance, counterName string) (PerfCounterWatcher, error
if err != nil {
return nil, fmt.Errorf("failed to create perf counter with path %v: %w", path, err)
}
return Watcher{Counter: counter}, nil
}

func (w Watcher) Path() string {
return w.Counter.Path()
}

func (w Watcher) ScrapeData() ([]CounterValue, error) {
scrapedCounterValues, err := w.Counter.ScrapeData()
if err != nil {
return []CounterValue{}, err
}

counterValues := []CounterValue{}
for _, counterValue := range scrapedCounterValues {
metric := w.GetMetricRep()
if counterValue.InstanceName != "" {
if metric.Attributes == nil {
metric.Attributes = map[string]string{instanceLabelName: counterValue.InstanceName}
}
metric.Attributes[instanceLabelName] = counterValue.InstanceName
}
counterValues = append(counterValues, CounterValue{MetricRep: metric, Value: counterValue.Value})
}
return counterValues, nil
}

func (w Watcher) Close() error {
return w.Counter.Close()
}

func (w Watcher) GetMetricRep() MetricRep {
return w.MetricRep
}

// BuildPaths creates watchers and their paths from configs.
func (objCfg ObjectConfig) BuildPaths() ([]PerfCounterWatcher, error) {
var errs error
var watchers []PerfCounterWatcher

for _, instance := range objCfg.instances() {
for _, counterCfg := range objCfg.Counters {
counterPath := counterPath(objCfg.Object, instance, counterCfg.Name)

c, err := pdh.NewPerfCounter(counterPath, true)
if err != nil {
errs = multierr.Append(errs, fmt.Errorf("counter %v: %w", counterPath, err))
} else {
newWatcher := Watcher{Counter: c}

if counterCfg.MetricRep.Name != "" {
metricCfg := MetricRep{Name: counterCfg.MetricRep.Name}
if counterCfg.Attributes != nil {
metricCfg.Attributes = counterCfg.Attributes
}
newWatcher.MetricRep = metricCfg
} else {
newWatcher.MetricRep.Name = c.Path()
}

watchers = append(watchers, newWatcher)
}
}
}

return watchers, errs
return counter, nil
}

func counterPath(object, instance, counterName string) string {
Expand All @@ -128,8 +59,3 @@ func counterPath(object, instance, counterName string) string {

return fmt.Sprintf("\\%s%s\\%s", object, instance, counterName)
}

type CounterValue struct {
MetricRep
Value float64
}
132 changes: 21 additions & 111 deletions pkg/winperfcounters/watcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,136 +21,46 @@ import (
"testing"

"github.com/stretchr/testify/require"
"go.uber.org/multierr"
)

// Test_PathBuilder tests that paths are built correctly given a ObjectConfig
func Test_PathBuilder(t *testing.T) {
func TestCounterPath(t *testing.T) {
testCases := []struct {
name string
cfgs []ObjectConfig
expectedErr string
expectedPaths []string
name string
object string
instance string
counterName string
expectedPath string
}{
{
name: "basicPath",
cfgs: []ObjectConfig{
{
Object: "Memory",
Counters: []CounterConfig{{Name: "Committed Bytes"}},
},
},
expectedPaths: []string{"\\Memory\\Committed Bytes"},
name: "basicPath",
object: "Memory",
counterName: "Committed Bytes",
expectedPath: "\\Memory\\Committed Bytes",
},
{
name: "multiplePaths",
cfgs: []ObjectConfig{
{
Object: "Memory",
Counters: []CounterConfig{{Name: "Committed Bytes"}},
},
{
Object: "Memory",
Counters: []CounterConfig{{Name: "Available Bytes"}},
},
},
expectedPaths: []string{"\\Memory\\Committed Bytes", "\\Memory\\Available Bytes"},
},
{
name: "multipleIndividualCounters",
cfgs: []ObjectConfig{
{
Object: "Memory",
Counters: []CounterConfig{
{Name: "Committed Bytes"},
{Name: "Available Bytes"},
},
},
{
Object: "Memory",
Counters: []CounterConfig{},
},
},
expectedPaths: []string{"\\Memory\\Committed Bytes", "\\Memory\\Available Bytes"},
},
{
name: "invalidCounter",
cfgs: []ObjectConfig{
{
Object: "Broken",
Counters: []CounterConfig{{Name: "Broken Counter"}},
},
},

expectedErr: "counter \\Broken\\Broken Counter: The specified object was not found on the computer.\r\n",
},
{
name: "multipleInvalidCounters",
cfgs: []ObjectConfig{
{
Object: "Broken",
Counters: []CounterConfig{{Name: "Broken Counter"}},
},
{
Object: "Broken part 2",
Counters: []CounterConfig{{Name: "Broken again"}},
},
},
expectedErr: "counter \\Broken\\Broken Counter: The specified object was not found on the computer.\r\n; counter \\Broken part 2\\Broken again: The specified object was not found on the computer.\r\n",
name: "basicPathWithInstance",
object: "Web Service",
instance: "_Total",
counterName: "Current Connections",
expectedPath: "\\Web Service(_Total)\\Current Connections",
},
}

for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
var errs error
allWatchers := []PerfCounterWatcher{}
for _, cfg := range test.cfgs {
watchers, err := cfg.BuildPaths()
if err != nil {
errs = multierr.Append(errs, err)
continue
}
allWatchers = append(allWatchers, watchers...)
}

if test.expectedErr != "" {
require.EqualError(t, errs, test.expectedErr)
return
}

actualPaths := []string{}
for _, watcher := range allWatchers {
actualPaths = append(actualPaths, watcher.Path())
}

require.Equal(t, test.expectedPaths, actualPaths)
path := counterPath(test.object, test.instance, test.counterName)
require.Equal(t, test.expectedPath, path)
})
}
}

// Test_Scraping_Wildcard tests that wildcard instances pull out values
func Test_Scraping_Wildcard(t *testing.T) {
counterVals := []CounterValue{}
var errs error

cfg := ObjectConfig{
Object: "LogicalDisk",
Instances: []string{"*"},
Counters: []CounterConfig{{Name: "Free Megabytes"}},
}
watchers, err := cfg.BuildPaths()
watcher, err := NewWatcher("LogicalDisk", "*", "Free Megabytes")
require.NoError(t, err)

for _, watcher := range watchers {
value, err := watcher.ScrapeData()
if err != nil {
errs = multierr.Append(errs, err)
continue
}

require.NoError(t, err)
counterVals = append(counterVals, value...)
}
values, err := watcher.ScrapeData()
require.NoError(t, err)

require.GreaterOrEqual(t, len(counterVals), 3)
require.GreaterOrEqual(t, len(values), 3)
}
17 changes: 1 addition & 16 deletions receiver/activedirectorydsreceiver/counters.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,20 +243,5 @@ const (
type defaultWatcherCreater struct{}

func (defaultWatcherCreater) Create(counterName string) (winperfcounters.PerfCounterWatcher, error) {
conf := winperfcounters.ObjectConfig{
Object: object,
Instances: []string{instanceName},
Counters: []winperfcounters.CounterConfig{
{
Name: counterName,
},
},
}

watchers, err := conf.BuildPaths()
if err != nil {
return nil, err
}

return watchers[0], nil
return winperfcounters.NewWatcher(object, instanceName, counterName)
}
Loading

0 comments on commit 8eec12f

Please sign in to comment.