Skip to content

Commit

Permalink
[receiver/windowsperfcountersreceiver] Update how metrics are establi…
Browse files Browse the repository at this point in the history
…shed (#8376)

* Add ability to define metrics

* Update tests

* Update Readme

* Add attributes to readme

* Update values for metric config in readme

* Update changelog

* Fix lint

* Fix misspelling

* Force rerun

* Rename keys in Counter config

* Restructure metrics into map

* Remove Value type & Add defaults

* Remove extra test case

* Fix tests

* Add handling for no metrics defined

* Add no metric definition test

* Rework Readme wording

* Add no metrics factory test

* Add no Metrics config test

* Add no metric specified test

* Fix test

* Add More Tests

* Add ignoreValues option

* Fix changelog
  • Loading branch information
Mrod1598 authored Mar 21, 2022
1 parent 9a5bf6e commit ba8c797
Show file tree
Hide file tree
Showing 25 changed files with 895 additions and 168 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### 🛑 Breaking changes 🛑

- `windowsperfcountersreceiver`: Added metrics configuration (#8376)

## v0.47.0

### 💡 Enhancements 💡
Expand Down
86 changes: 65 additions & 21 deletions receiver/windowsperfcountersreceiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ interface](https://docs.microsoft.com/en-us/windows/win32/perfctrs/using-the-pdh
It is based on the [Telegraf Windows Performance Counters Input
Plugin](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/win_perf_counters).

Metrics will be generated with names and labels that match the performance
counter path, i.e.

- `Memory\Committed Bytes`
- `Processor\% Processor Time`, with a datapoint for each `Instance` label = (`_Total`, `1`, `2`, `3`, ... )

Expand All @@ -25,11 +22,25 @@ be configured:
```yaml
windowsperfcounters:
collection_interval: <duration> # default = "1m"
metrics:
<metric name>:
description: <description>
unit: <unit type>
gauge:
<metric name>:
description: <description>
unit: <unit type>
sum:
aggregation: <cumulative or delta>
monotonic: <true or false>
perfcounters:
- object: <object name>
instances: [<instance name>]*
counters:
- <counter name>
- name: <counter name>
metric: <metric name>
attributes:
<key>: <value>
```
*Note `instances` can have several special values depending on the type of
Expand All @@ -53,60 +64,93 @@ you can configure multiple `windowsperfcounters` receivers with different
```yaml
receivers:
windowsperfcounters/memory:
metrics:
bytes.committed:
description: the number of bytes committed to memory
unit: By
gauge:
collection_interval: 30s
perfcounters:
- object: Memory
counters:
- Committed Bytes
- name: Committed Bytes
metric: bytes.committed
windowsperfcounters/processor:
collection_interval: 1m
metrics:
processor.time:
description: active and idle time of the processor
unit: "%"
gauge:
perfcounters:
- object: "Processor"
instances: "*"
counters:
- "% Processor Time"
- name: "% Processor Time"
metric: processor.time
attributes:
state: active
- object: "Processor"
instances: [1, 2]
counters:
- "% Idle Time"
- name: "% Idle Time"
metric: processor.time
attributes:
state: idle
service:
pipelines:
metrics:
receivers: [windowsperfcounters/memory, windowsperfcounters/processor]
```

### Changing metric format
### Defining metric format

To report metrics in the desired output format, define a metric and reference it in the corresponding counter, along with any applicable attributes. The metric's data type can either be `gauge` (default) or `sum`.

| Field Name | Description | Value | Default |
| -- | -- | -- | -- |
| name | The key for the metric. | string | Counter Name |
| description | definition of what the metric measures. | string | |
| unit | what is being measured. | string | `1` |
| sum | representation of a sum metric. | Sum Config | |
| gauge | representation of a gauge metric. | Gauge Config | |


To report metrics in the desired output format, it's recommended you use this
receiver with the [metrics transform
processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/metricstransformprocessor).
#### Sum Config

| Field Name | Description | Value | Default |
| -- | -- | -- | -- |
| aggregation | The type of aggregation temporality for the metric. | [`cumulative` or `delta`] | |
| monotonic | whether or not the metric value can decrease. | false | |

#### Gauge Config

A `gauge` config currently accepts no settings. It is specified as an object for forwards compatibility.

e.g. To output the `Memory/Committed Bytes` counter as a metric with the name
`system.memory.usage`:
`bytes.committed`:

```yaml
receivers:
windowsperfcounters:
metrics:
bytes.committed:
description: the number of bytes committed to memory
unit: By
gauge:
collection_interval: 30s
perfcounters:
- object: Memory
counters:
- Committed Bytes
processors:
metricstransformprocessor:
transforms:
- metric_name: "Memory/Committed Bytes"
action: update
new_name: system.memory.usage
- name: Committed Bytes
metric: bytes.committed
service:
pipelines:
metrics:
receivers: [windowsperfcounters]
processors: [metricstransformprocessor]
```

## Recommended configuration for common applications
Expand Down
71 changes: 63 additions & 8 deletions receiver/windowsperfcountersreceiver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,37 @@ import (
type Config struct {
scraperhelper.ScraperControllerSettings `mapstructure:",squash"`

PerfCounters []PerfCounterConfig `mapstructure:"perfcounters"`
MetricMetaData map[string]MetricConfig `mapstructure:"metrics"`
PerfCounters []PerfCounterConfig `mapstructure:"perfcounters"`
}

// PerfCounterConfig defines configuration for a perf counter object.
type PerfCounterConfig struct {
Object string `mapstructure:"object"`
Instances []string `mapstructure:"instances"`
Counters []string `mapstructure:"counters"`
Object string `mapstructure:"object"`
Instances []string `mapstructure:"instances"`
Counters []CounterConfig `mapstructure:"counters"`
}

// MetricsConfig defines the configuration for a metric to be created.
type MetricConfig struct {
Unit string `mapstructure:"unit"`
Description string `mapstructure:"description"`
Gauge GaugeMetric `mapstructure:"gauge"`
Sum SumMetric `mapstructure:"sum"`
}

type GaugeMetric struct {
}

type SumMetric struct {
Aggregation string `mapstructure:"aggregation"`
Monotonic bool `mapstructure:"monotonic"`
}

type CounterConfig struct {
Metric string `mapstructure:"metric"`
Name string `mapstructure:"name"`
Attributes map[string]string `mapstructure:"attributes"`
}

func (c *Config) Validate() error {
Expand All @@ -46,23 +69,55 @@ func (c *Config) Validate() error {
errs = multierr.Append(errs, fmt.Errorf("must specify at least one perf counter"))
}

for name, metric := range c.MetricMetaData {
if metric.Unit == "" {
metric.Unit = "1"
}

if (metric.Sum != SumMetric{}) {
if (metric.Gauge != GaugeMetric{}) {
errs = multierr.Append(errs, fmt.Errorf("metric %q provides both a sum config and a gauge config", name))
}

if metric.Sum.Aggregation != "cumulative" && metric.Sum.Aggregation != "delta" {
errs = multierr.Append(errs, fmt.Errorf("sum metric %q includes an invalid aggregation", name))
}
}
}

var perfCounterMissingObjectName bool
for _, pc := range c.PerfCounters {
if pc.Object == "" {
perfCounterMissingObjectName = true
continue
}

if len(pc.Counters) == 0 {
errs = multierr.Append(errs, fmt.Errorf("perf counter for object %q does not specify any counters", pc.Object))
}

for _, counter := range pc.Counters {
if counter.Metric == "" {
continue
}

foundMatchingMetric := false
for name := range c.MetricMetaData {
if counter.Metric == name {
foundMatchingMetric = true
}
}
if !foundMatchingMetric {
errs = multierr.Append(errs, fmt.Errorf("perf counter for object %q includes an undefined metric", pc.Object))
}
}

for _, instance := range pc.Instances {
if instance == "" {
errs = multierr.Append(errs, fmt.Errorf("perf counter for object %q includes an empty instance", pc.Object))
break
}
}

if len(pc.Counters) == 0 {
errs = multierr.Append(errs, fmt.Errorf("perf counter for object %q does not specify any counters", pc.Object))
}
}

if perfCounterMissingObjectName {
Expand Down
Loading

0 comments on commit ba8c797

Please sign in to comment.