-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
2/3 Add Windows Performance Counters Receiver skeleton implementation (…
…#1211) Adds skeleton for Windows Performance Counters Receiver with very basic initial functionality that can read simple counters that do not include any instance into a Gauge metric - see the added README.md for more details. **Link to tracking Issue:** #1088 Note the scaffolding code makes use of the new `receiverhelper` & `scraperhelper` functions added in the Core PRs referenced below. **Depends on:** #1175, open-telemetry/opentelemetry-collector#1886, open-telemetry/opentelemetry-collector#1890
- Loading branch information
1 parent
f000242
commit 9b9dd09
Showing
22 changed files
with
2,605 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
include ../../Makefile.Common | ||
include ../../Makefile.Common |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Windows Performance Counters Receiver | ||
|
||
#### :warning: This receiver is still under construction. It currently only supports very basic functionality, i.e. performance counters with no 'Instance'. | ||
|
||
This receiver, for Windows only, captures the configured system, application, or | ||
custom performance counter data from the Windows registry using the [PDH | ||
interface](https://docs.microsoft.com/en-us/windows/win32/perfctrs/using-the-pdh-functions-to-consume-counter-data). | ||
|
||
## Configuration | ||
|
||
The collection interval and the list of performance counters to be scraped can | ||
be configured: | ||
|
||
```yaml | ||
windowsperfcounters: | ||
collection_interval: <duration> # default = "1m" | ||
counters: | ||
- object: <object name> | ||
counters: | ||
- <counter name> | ||
``` | ||
### Scraping at different frequencies | ||
If you would like to scrape some counters at a different frequency than others, | ||
you can configure multiple `windowsperfcounters` receivers with different | ||
`collection_interval` values. For example: | ||
|
||
```yaml | ||
receivers: | ||
windowsperfcounters/memory: | ||
collection_interval: 30s | ||
counters: | ||
- object: Memory | ||
counters: | ||
- Committed Bytes | ||
windowsperfcounters/connections: | ||
collection_interval: 1m | ||
counters: | ||
- object: TCPv4 | ||
counters: | ||
- Connections Established | ||
service: | ||
pipelines: | ||
metrics: | ||
receivers: [windowsperfcounters/memory, windowsperfcounters/connections] | ||
``` | ||
|
||
### Changing metric format | ||
|
||
To report metrics in the desired output format, it's recommended you use this | ||
receiver with the metrics transform processor, e.g.: | ||
|
||
```yaml | ||
receivers: | ||
windowsperfcounters: | ||
collection_interval: 30s | ||
counters: | ||
- object: Memory | ||
counters: | ||
- Committed Bytes | ||
processors: | ||
metricstransformprocessor: | ||
transforms: | ||
# rename "Memory/Committed Bytes" -> system.memory.usage | ||
- metric_name: "Memory/Committed Bytes" | ||
action: update | ||
new_name: system.memory.usage | ||
service: | ||
pipelines: | ||
metrics: | ||
receivers: [windowsperfcounters] | ||
processors: [metricstransformprocessor] | ||
``` | ||
|
||
## Recommended configuration for common applications | ||
|
||
### IIS | ||
|
||
TODO | ||
|
||
### SQL Server | ||
|
||
TODO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package windowsperfcountersreceiver | ||
|
||
import ( | ||
"fmt" | ||
|
||
"go.opentelemetry.io/collector/component/componenterror" | ||
"go.opentelemetry.io/collector/config/configmodels" | ||
"go.opentelemetry.io/collector/receiver/receiverhelper" | ||
) | ||
|
||
// Config defines configuration for HostMetrics receiver. | ||
type Config struct { | ||
configmodels.ReceiverSettings `mapstructure:",squash"` | ||
receiverhelper.ScraperControllerSettings `mapstructure:",squash"` | ||
|
||
PerfCounters []PerfCounterConfig `mapstructure:"perfcounters"` | ||
} | ||
|
||
type PerfCounterConfig struct { | ||
Object string `mapstructure:"object"` | ||
Counters []string `mapstructure:"counters"` | ||
} | ||
|
||
func (c *Config) validate() error { | ||
var errors []error | ||
|
||
if c.CollectionInterval <= 0 { | ||
errors = append(errors, fmt.Errorf("collection_interval must be a positive duration")) | ||
} | ||
|
||
if len(c.PerfCounters) == 0 { | ||
errors = append(errors, fmt.Errorf("must specify at least one perf counter")) | ||
} | ||
|
||
var perfCounterMissingObjectName bool | ||
for _, pc := range c.PerfCounters { | ||
if pc.Object == "" { | ||
perfCounterMissingObjectName = true | ||
continue | ||
} | ||
|
||
if len(pc.Counters) == 0 { | ||
errors = append(errors, fmt.Errorf("perf counter for object %q does not specify any counters", pc.Object)) | ||
} | ||
} | ||
|
||
if perfCounterMissingObjectName { | ||
errors = append(errors, fmt.Errorf("must specify object name for all perf counters")) | ||
} | ||
|
||
return componenterror.CombineErrors(errors) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package windowsperfcountersreceiver | ||
|
||
import ( | ||
"fmt" | ||
"path" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"go.opentelemetry.io/collector/component/componenttest" | ||
"go.opentelemetry.io/collector/config/configmodels" | ||
"go.opentelemetry.io/collector/config/configtest" | ||
"go.opentelemetry.io/collector/receiver/receiverhelper" | ||
) | ||
|
||
func TestLoadConfig(t *testing.T) { | ||
factories, err := componenttest.ExampleComponents() | ||
require.NoError(t, err) | ||
|
||
factory := NewFactory() | ||
factories.Receivers[typeStr] = factory | ||
cfg, err := configtest.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories) | ||
|
||
require.NoError(t, err) | ||
require.NotNil(t, cfg) | ||
|
||
assert.Equal(t, len(cfg.Receivers), 2) | ||
|
||
r0 := cfg.Receivers["windowsperfcounters"] | ||
defaultConfigSingleObject := factory.CreateDefaultConfig() | ||
defaultConfigSingleObject.(*Config).PerfCounters = []PerfCounterConfig{{Object: "object", Counters: []string{"counter"}}} | ||
|
||
assert.Equal(t, defaultConfigSingleObject, r0) | ||
|
||
r1 := cfg.Receivers["windowsperfcounters/customname"].(*Config) | ||
expectedConfig := &Config{ | ||
ReceiverSettings: configmodels.ReceiverSettings{ | ||
TypeVal: typeStr, | ||
NameVal: "windowsperfcounters/customname", | ||
}, | ||
ScraperControllerSettings: receiverhelper.ScraperControllerSettings{ | ||
CollectionInterval: 30 * time.Second, | ||
}, | ||
PerfCounters: []PerfCounterConfig{ | ||
{ | ||
Object: "object1", | ||
Counters: []string{"counter1"}, | ||
}, | ||
{ | ||
Object: "object2", | ||
Counters: []string{"counter1", "counter2"}, | ||
}, | ||
}, | ||
} | ||
|
||
assert.Equal(t, expectedConfig, r1) | ||
} | ||
|
||
func TestLoadConfig_Error(t *testing.T) { | ||
type testCase struct { | ||
name string | ||
cfgFile string | ||
expectedErr string | ||
} | ||
|
||
const ( | ||
errorPrefix = "error reading receivers configuration for windowsperfcounters" | ||
negativeCollectionIntervalErr = "collection_interval must be a positive duration" | ||
noPerfCountersErr = "must specify at least one perf counter" | ||
noObjectNameErr = "must specify object name for all perf counters" | ||
noCountersErr = `perf counter for object "%s" does not specify any counters` | ||
) | ||
|
||
testCases := []testCase{ | ||
{ | ||
name: "NegativeCollectionInterval", | ||
cfgFile: "config-negative-collection-interval.yaml", | ||
expectedErr: fmt.Sprintf("%s: %s", errorPrefix, negativeCollectionIntervalErr), | ||
}, | ||
{ | ||
name: "NoPerfCounters", | ||
cfgFile: "config-noperfcounters.yaml", | ||
expectedErr: fmt.Sprintf("%s: %s", errorPrefix, noPerfCountersErr), | ||
}, | ||
{ | ||
name: "NoObjectName", | ||
cfgFile: "config-noobjectname.yaml", | ||
expectedErr: fmt.Sprintf("%s: %s", errorPrefix, noObjectNameErr), | ||
}, | ||
{ | ||
name: "NoCounters", | ||
cfgFile: "config-nocounters.yaml", | ||
expectedErr: fmt.Sprintf("%s: %s", errorPrefix, fmt.Sprintf(noCountersErr, "object")), | ||
}, | ||
{ | ||
name: "AllErrors", | ||
cfgFile: "config-allerrors.yaml", | ||
expectedErr: fmt.Sprintf("%s: [%s; %s; %s]", errorPrefix, negativeCollectionIntervalErr, fmt.Sprintf(noCountersErr, "object"), noObjectNameErr), | ||
}, | ||
} | ||
|
||
for _, test := range testCases { | ||
t.Run(test.name, func(t *testing.T) { | ||
factories, err := componenttest.ExampleComponents() | ||
require.NoError(t, err) | ||
|
||
factory := NewFactory() | ||
factories.Receivers[typeStr] = factory | ||
_, err = configtest.LoadConfigFile(t, path.Join(".", "testdata", test.cfgFile), factories) | ||
|
||
require.EqualError(t, err, test.expectedErr) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright 2020, OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// windowsperfcountersreceiver implements a collector receiver that | ||
// collects the configured performance counter data at the configured | ||
// collection interval and converts them into OTLP equivalent metric | ||
// representations. | ||
// | ||
// This receiver is only compatible with Windows. | ||
package windowsperfcountersreceiver |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
extensions: | ||
zpages: | ||
endpoint: 0.0.0.0:55679 | ||
|
||
receivers: | ||
windowsperfcounters: | ||
collection_interval: 1s | ||
perfcounters: | ||
- object: "Memory" | ||
counters: | ||
- "Committed Bytes" | ||
|
||
exporters: | ||
logging: | ||
prometheus: | ||
endpoint: 0.0.0.0:8889 | ||
|
||
service: | ||
pipelines: | ||
metrics: | ||
receivers: [windowsperfcounters] | ||
exporters: [prometheus, logging] | ||
|
||
extensions: [zpages] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package windowsperfcountersreceiver | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/spf13/viper" | ||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/config/configmodels" | ||
"go.opentelemetry.io/collector/receiver/receiverhelper" | ||
) | ||
|
||
// This file implements Factory for WindowsPerfCounters receiver. | ||
|
||
// The value of "type" key in configuration. | ||
const typeStr = "windowsperfcounters" | ||
|
||
// NewFactory creates a new factory for windows perf counters receiver. | ||
func NewFactory() component.ReceiverFactory { | ||
return receiverhelper.NewFactory( | ||
typeStr, | ||
createDefaultConfig, | ||
receiverhelper.WithMetrics(createMetricsReceiver), | ||
receiverhelper.WithCustomUnmarshaler(customUnmarshaler)) | ||
} | ||
|
||
// customUnmarshaler returns custom unmarshaler for this config. | ||
func customUnmarshaler(componentViperSection *viper.Viper, intoCfg interface{}) error { | ||
err := componentViperSection.Unmarshal(intoCfg) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return intoCfg.(*Config).validate() | ||
} | ||
|
||
// createDefaultConfig creates the default configuration for receiver. | ||
func createDefaultConfig() configmodels.Receiver { | ||
return &Config{ | ||
ReceiverSettings: configmodels.ReceiverSettings{ | ||
TypeVal: typeStr, | ||
NameVal: typeStr, | ||
}, | ||
ScraperControllerSettings: receiverhelper.ScraperControllerSettings{ | ||
CollectionInterval: time.Minute, | ||
}, | ||
} | ||
} |
Oops, something went wrong.