diff --git a/README.md b/README.md index 7d0bd5f5..bfce2637 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Name | Description | Enabled by default [ad](docs/collector.ad.md) | Active Directory Domain Services | [adfs](docs/collector.adfs.md) | Active Directory Federation Services | [cpu](docs/collector.cpu.md) | CPU usage | ✓ +[cpu_info](docs/collector.cpu_info.md) | CPU Information | [cs](docs/collector.cs.md) | "Computer System" metrics (system properties, num cpus/total memory) | ✓ [container](docs/collector.container.md) | Container metrics | [dfsr](docs/collector.dfsr.md) | DFSR metrics | diff --git a/collector/cpu_info.go b/collector/cpu_info.go new file mode 100644 index 00000000..502fd3aa --- /dev/null +++ b/collector/cpu_info.go @@ -0,0 +1,96 @@ +// +build windows + +package collector + +import ( + "errors" + "strconv" + "strings" + + "github.com/StackExchange/wmi" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/log" +) + +func init() { + registerCollector("cpu_info", newCpuInfoCollector) +} + +// If you are adding additional labels to the metric, make sure that they get added in here as well. See below for explanation. +const ( + win32ProcessorQuery = "SELECT Architecture, DeviceId, Description, Family, L2CacheSize, L3CacheSize, Name FROM Win32_Processor" +) + +// A CpuInfoCollector is a Prometheus collector for a few WMI metrics in Win32_Processor +type CpuInfoCollector struct { + CpuInfo *prometheus.Desc +} + +func newCpuInfoCollector() (Collector, error) { + return &CpuInfoCollector{ + CpuInfo: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, "", "cpu_info"), + "Labeled CPU information as provided provided by Win32_Processor", + []string{ + "architecture", + "device_id", + "description", + "family", + "l2_cache_size", + "l3_cache_size", + "name"}, + nil, + ), + }, nil +} + +type win32_Processor struct { + Architecture uint32 + DeviceID string + Description string + Family uint16 + L2CacheSize uint32 + L3CacheSize uint32 + Name string +} + +// Collect sends the metric values for each metric +// to the provided prometheus Metric channel. +func (c *CpuInfoCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error { + if desc, err := c.collect(ch); err != nil { + log.Error("failed collecting cpu_info metrics:", desc, err) + return err + } + return nil +} + +func (c *CpuInfoCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) { + var dst []win32_Processor + // We use a static query here because the provided methods in wmi.go all issue a SELECT *; + // This results in the time consuming LoadPercentage field being read which seems to measure each CPU + // serially over a 1 second interval, so the scrape time is at least 1s * num_sockets + if err := wmi.Query(win32ProcessorQuery, &dst); err != nil { + return nil, err + } + if len(dst) == 0 { + return nil, errors.New("WMI query returned empty result set") + } + + // Some CPUs end up exposing trailing spaces for certain strings, so clean them up + for _, processor := range dst { + ch <- prometheus.MustNewConstMetric( + c.CpuInfo, + prometheus.GaugeValue, + 1.0, + strconv.Itoa(int(processor.Architecture)), + strings.TrimRight(processor.DeviceID, " "), + strings.TrimRight(processor.Description, " "), + strconv.Itoa(int(processor.Family)), + strconv.Itoa(int(processor.L2CacheSize)), + strconv.Itoa(int(processor.L3CacheSize)), + strings.TrimRight(processor.Name, " "), + ) + } + + return nil, nil +} diff --git a/docs/collector.cpu_info.md b/docs/collector.cpu_info.md new file mode 100644 index 00000000..9ad36b4d --- /dev/null +++ b/docs/collector.cpu_info.md @@ -0,0 +1,31 @@ +# cpu_info collector + +The cpu_info collector exposes metrics detailing a per-socket breakdown of the Processors in the system + +||| +-|- +Metric name prefix | `cpu_info` +Classes | [`Win32_Processor`](https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-processor) +Enabled by default? | No + +## Flags + +None + +## Metrics + +Name | Description | Type | Labels +-----|-------------|------|------- +`windows_cpu_info` | Labeled CPU information | gauge | `architecture`, `device_id`, `description`, `family`, `l2_cache_size` `l3_cache_size`, `name` + +### Example metric +``` +windows_cpu_info{architecture="9",description="AMD64 Family 23 Model 49 Stepping 0",device_id="CPU0",family="107",l2_cache_size="32768",l3_cache_size="262144",name="AMD EPYC 7702P 64-Core Processor"} 1 +``` +The value of the metric is irrelevant, but the labels expose some useful information on the CPU installed in each socket. + +## Useful queries +_This collector does not yet have any useful queries added, we would appreciate your help adding them!_ + +## Alerting examples +_This collector does not yet have alerting examples, we would appreciate your help adding them!_