pagefile: BREAKING: move paging metrics from os to dedicated collector (click PR for more information) (#1735)

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke 2024-11-14 22:39:59 +01:00 committed by GitHub
parent df8513ab8e
commit 7a9a4e5831
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 238 additions and 25 deletions

View File

@ -41,6 +41,7 @@ Name | Description | Enabled by default
[netframework](docs/collector.netframework.md) | .NET Framework metrics |
[net](docs/collector.net.md) | Network interface I/O | &#10003;
[os](docs/collector.os.md) | OS metrics (memory, processes, users) | &#10003;
[pagefile](docs/collector.pagefile.md) | pagefile metrics |
[perfdata](docs/collector.perfdata.md) | Custom perfdata metrics |
[physical_disk](docs/collector.physical_disk.md) | physical disk metrics | &#10003;
[printer](docs/collector.printer.md) | Printer metrics |

View File

@ -15,11 +15,9 @@ None
## Metrics
| Name | Description | Type | Labels |
|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|------------------------------------------------------------------------|
|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|------------------------------------------------------------------------|
| `windows_os_hostname` | Labelled system hostname information as provided by ComputerSystem.DNSHostName and ComputerSystem.Domain | gauge | `domain`, `fqdn`, `hostname` |
| `windows_os_info` | Contains full product name & version in labels. Note that the `major_version` for Windows 11 is "10"; a build number greater than 22000 represents Windows 11. | gauge | `product`, `version`, `major_version`, `minor_version`, `build_number` |
| `windows_os_paging_limit_bytes` | Total number of bytes that can be stored in the operating system paging files. 0 (zero) indicates that there are no paging files | gauge | None |
| `windows_os_paging_free_bytes` | Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out | gauge | None |
### Example metric

View File

@ -0,0 +1,38 @@
# pagefile collector
The pagefile collector exposes metrics about the pagefile usage
|||
-|-
Metric name prefix | `pagefile`
Classes | [`Win32_OperatingSystem`](https://msdn.microsoft.com/en-us/library/aa394239)
Enabled by default? | Yes
## Flags
None
## Metrics
| Name | Description | Type | Labels |
|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------|-------|--------|
| `windows_pagefile_free_bytes` | Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out | gauge | `file` |
| `windows_pagefile_limit_bytes` | Number of bytes that can be stored in the operating system paging files. 0 (zero) indicates that there are no paging files | gauge | `file` |
### Example metric
```
# HELP windows_pagefile_free_bytes OperatingSystem.FreeSpaceInPagingFiles
# TYPE windows_pagefile_free_bytes gauge
windows_pagefile_free_bytes{file="C:\\pagefile.sys"} 6.025797632e+09
# HELP windows_pagefile_limit_bytes OperatingSystem.SizeStoredInPagingFiles
# TYPE windows_pagefile_limit_bytes gauge
windows_pagefile_limit_bytes{file="C:\\pagefile.sys"} 6.442450944e+09
```
## Useful queries
_This collector does not yet have useful queries, we would appreciate your help adding them!_
## Alerting examples
_This collector does not yet have alerting examples, we would appreciate your help adding them!_

View File

@ -36,7 +36,12 @@ type Collector struct {
hostname *prometheus.Desc
osInformation *prometheus.Desc
// pagingFreeBytes
// Deprecated: Use windows_paging_free_bytes instead.
pagingFreeBytes *prometheus.Desc
// pagingLimitBytes
// Deprecated: Use windows_paging_total_bytes instead.
pagingLimitBytes *prometheus.Desc
// users
@ -151,13 +156,13 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
)
c.pagingLimitBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "paging_limit_bytes"),
"OperatingSystem.SizeStoredInPagingFiles",
"Deprecated: Use windows_pagefile_limit_bytes instead.",
nil,
nil,
)
c.pagingFreeBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "paging_free_bytes"),
"OperatingSystem.FreeSpaceInPagingFiles",
"Deprecated: Use windows_pagefile_free_bytes instead.",
nil,
nil,
)

View File

@ -0,0 +1,5 @@
package pagefile
const (
usage = "% Usage"
)

View File

@ -0,0 +1,136 @@
//go:build windows
package pagefile
import (
"fmt"
"log/slog"
"os"
"strings"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/psapi"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus"
)
const Name = "pagefile"
type Config struct{}
var ConfigDefaults = Config{}
// A Collector is a Prometheus Collector for WMI metrics.
type Collector struct {
config Config
perfDataCollector perfdata.Collector
pagingFreeBytes *prometheus.Desc
pagingLimitBytes *prometheus.Desc
}
func New(config *Config) *Collector {
if config == nil {
config = &ConfigDefaults
}
c := &Collector{
config: *config,
}
return c
}
func NewWithFlags(_ *kingpin.Application) *Collector {
return &Collector{}
}
func (c *Collector) GetName() string {
return Name
}
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
return []string{}, nil
}
func (c *Collector) Close(_ *slog.Logger) error {
return nil
}
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
counters := []string{
usage,
}
var err error
c.perfDataCollector, err = perfdata.NewCollector(perfdata.V2, "Paging File", perfdata.AllInstances, counters)
if err != nil {
return fmt.Errorf("failed to create Paging File collector: %w", err)
}
c.pagingLimitBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "limit_bytes"),
"Number of bytes that can be stored in the operating system paging files. 0 (zero) indicates that there are no paging files",
[]string{"file"},
nil,
)
c.pagingFreeBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "free_bytes"),
"Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out",
[]string{"file"},
nil,
)
return nil
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
return c.collectPaging(ch)
}
func (c *Collector) collectPaging(ch chan<- prometheus.Metric) error {
data, err := c.perfDataCollector.Collect()
if err != nil {
return fmt.Errorf("failed to collect Paging File metrics: %w", err)
}
gpi, err := psapi.GetPerformanceInfo()
if err != nil {
return err
}
for fileName, pageFile := range data {
fileString := strings.ReplaceAll(fileName, `\??\`, "")
file, err := os.Stat(fileString)
var fileSize float64
// For unknown reasons, Windows doesn't always create a page file. Continue collection rather than aborting.
if err == nil {
fileSize = float64(file.Size())
}
ch <- prometheus.MustNewConstMetric(
c.pagingFreeBytes,
prometheus.GaugeValue,
fileSize-(pageFile[usage].FirstValue*float64(gpi.PageSize)),
fileString,
)
ch <- prometheus.MustNewConstMetric(
c.pagingLimitBytes,
prometheus.GaugeValue,
fileSize,
fileString,
)
}
return nil
}

View File

@ -0,0 +1,16 @@
package pagefile_test
import (
"testing"
"github.com/prometheus-community/windows_exporter/internal/collector/pagefile"
"github.com/prometheus-community/windows_exporter/internal/testutils"
)
func BenchmarkCollector(b *testing.B) {
testutils.FuncBenchmarkCollector(b, pagefile.Name, pagefile.NewWithFlags)
}
func TestCollector(t *testing.T) {
testutils.TestCollector(t, pagefile.New, nil)
}

View File

@ -5,6 +5,7 @@ package v2
import (
"errors"
"fmt"
"slices"
"strings"
"unsafe"
@ -17,6 +18,7 @@ type Collector struct {
object string
counters map[string]Counter
handle pdhQueryHandle
totalCounterRequested bool
}
type Counter struct {
@ -42,6 +44,7 @@ func NewCollector(object string, instances []string, counters []string) (*Collec
object: object,
counters: make(map[string]Counter, len(counters)),
handle: handle,
totalCounterRequested: slices.Contains(instances, "_Total"),
}
for _, counterName := range counters {
@ -166,12 +169,10 @@ func (c *Collector) Collect() (map[string]map[string]perftypes.CounterValues, er
metricType = prometheus.GaugeValue
}
_, isTotalCounterRequests := c.counters["_Total"]
for _, item := range items {
if item.RawValue.CStatus == PdhCstatusValidData || item.RawValue.CStatus == PdhCstatusNewData {
instanceName := windows.UTF16PtrToString(item.SzName)
if strings.HasSuffix(instanceName, "_Total") && !isTotalCounterRequests {
if strings.HasSuffix(instanceName, "_Total") && !c.totalCounterRequested {
continue
}

View File

@ -39,6 +39,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/netframework"
"github.com/prometheus-community/windows_exporter/internal/collector/nps"
"github.com/prometheus-community/windows_exporter/internal/collector/os"
"github.com/prometheus-community/windows_exporter/internal/collector/pagefile"
"github.com/prometheus-community/windows_exporter/internal/collector/perfdata"
"github.com/prometheus-community/windows_exporter/internal/collector/physical_disk"
"github.com/prometheus-community/windows_exporter/internal/collector/printer"
@ -107,6 +108,7 @@ func NewWithConfig(config Config) *MetricCollectors {
collectors[netframework.Name] = netframework.New(&config.NetFramework)
collectors[nps.Name] = nps.New(&config.Nps)
collectors[os.Name] = os.New(&config.OS)
collectors[pagefile.Name] = pagefile.New(&config.Paging)
collectors[perfdata.Name] = perfdata.New(&config.PerfData)
collectors[physical_disk.Name] = physical_disk.New(&config.PhysicalDisk)
collectors[printer.Name] = printer.New(&config.Printer)

View File

@ -29,6 +29,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/netframework"
"github.com/prometheus-community/windows_exporter/internal/collector/nps"
"github.com/prometheus-community/windows_exporter/internal/collector/os"
"github.com/prometheus-community/windows_exporter/internal/collector/pagefile"
"github.com/prometheus-community/windows_exporter/internal/collector/perfdata"
"github.com/prometheus-community/windows_exporter/internal/collector/physical_disk"
"github.com/prometheus-community/windows_exporter/internal/collector/printer"
@ -79,6 +80,7 @@ type Config struct {
NetFramework netframework.Config `yaml:"net_framework"`
Nps nps.Config `yaml:"nps"`
OS os.Config `yaml:"os"`
Paging pagefile.Config `yaml:"paging"`
PerfData perfdata.Config `yaml:"perf_data"`
PhysicalDisk physical_disk.Config `yaml:"physical_disk"`
Printer printer.Config `yaml:"printer"`
@ -132,6 +134,7 @@ var ConfigDefaults = Config{
NetFramework: netframework.ConfigDefaults,
Nps: nps.ConfigDefaults,
OS: os.ConfigDefaults,
Paging: pagefile.ConfigDefaults,
PerfData: perfdata.ConfigDefaults,
PhysicalDisk: physical_disk.ConfigDefaults,
Printer: printer.ConfigDefaults,

View File

@ -33,6 +33,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/netframework"
"github.com/prometheus-community/windows_exporter/internal/collector/nps"
"github.com/prometheus-community/windows_exporter/internal/collector/os"
"github.com/prometheus-community/windows_exporter/internal/collector/pagefile"
"github.com/prometheus-community/windows_exporter/internal/collector/perfdata"
"github.com/prometheus-community/windows_exporter/internal/collector/physical_disk"
"github.com/prometheus-community/windows_exporter/internal/collector/printer"
@ -89,6 +90,7 @@ var BuildersWithFlags = map[string]BuilderWithFlags[Collector]{
netframework.Name: NewBuilderWithFlags(netframework.NewWithFlags),
nps.Name: NewBuilderWithFlags(nps.NewWithFlags),
os.Name: NewBuilderWithFlags(os.NewWithFlags),
pagefile.Name: NewBuilderWithFlags(pagefile.NewWithFlags),
perfdata.Name: NewBuilderWithFlags(perfdata.NewWithFlags),
physical_disk.Name: NewBuilderWithFlags(physical_disk.NewWithFlags),
printer.Name: NewBuilderWithFlags(printer.NewWithFlags),

View File

@ -122,6 +122,7 @@ windows_exporter_collector_success{collector="logon"} 1
windows_exporter_collector_success{collector="memory"} 1
windows_exporter_collector_success{collector="net"} 1
windows_exporter_collector_success{collector="os"} 1
windows_exporter_collector_success{collector="pagefile"} 1
windows_exporter_collector_success{collector="perfdata"} 1
windows_exporter_collector_success{collector="physical_disk"} 1
windows_exporter_collector_success{collector="printer"} 1
@ -144,6 +145,7 @@ windows_exporter_collector_timeout{collector="logon"} 0
windows_exporter_collector_timeout{collector="memory"} 0
windows_exporter_collector_timeout{collector="net"} 0
windows_exporter_collector_timeout{collector="os"} 0
windows_exporter_collector_timeout{collector="pagefile"} 0
windows_exporter_collector_timeout{collector="perfdata"} 0
windows_exporter_collector_timeout{collector="physical_disk"} 0
windows_exporter_collector_timeout{collector="printer"} 0
@ -297,9 +299,9 @@ windows_exporter_collector_timeout{collector="udp"} 0
# TYPE windows_os_hostname gauge
# HELP windows_os_info Contains full product name & version in labels. Note that the "major_version" for Windows 11 is \\"10\\"; a build number greater than 22000 represents Windows 11.
# TYPE windows_os_info gauge
# HELP windows_os_paging_free_bytes OperatingSystem.FreeSpaceInPagingFiles
# HELP windows_os_paging_free_bytes Deprecated: Use windows_pagefile_free_bytes instead.
# TYPE windows_os_paging_free_bytes gauge
# HELP windows_os_paging_limit_bytes OperatingSystem.SizeStoredInPagingFiles
# HELP windows_os_paging_limit_bytes Deprecated: Use windows_pagefile_limit_bytes instead.
# TYPE windows_os_paging_limit_bytes gauge
# HELP windows_os_physical_memory_free_bytes Deprecated: Use `windows_memory_physical_free_bytes` instead.
# TYPE windows_os_physical_memory_free_bytes gauge
@ -321,6 +323,10 @@ windows_exporter_collector_timeout{collector="udp"} 0
# TYPE windows_os_virtual_memory_free_bytes gauge
# HELP windows_os_visible_memory_bytes Deprecated: Use `windows_memory_physical_total_bytes` instead.
# TYPE windows_os_visible_memory_bytes gauge
# HELP windows_pagefile_free_bytes Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out
# TYPE windows_pagefile_free_bytes gauge
# HELP windows_pagefile_limit_bytes Number of bytes that can be stored in the operating system paging files. 0 (zero) indicates that there are no paging files
# TYPE windows_pagefile_limit_bytes gauge
# HELP windows_perfdata_memory_cache_faults_sec Performance data for \\Memory\\Cache Faults/sec
# TYPE windows_perfdata_memory_cache_faults_sec counter
# HELP windows_perfdata_processor_information__privileged_time Performance data for \\Processor Information\\% Privileged Time

View File

@ -18,14 +18,14 @@ mkdir $textfile_dir | Out-Null
Copy-Item 'e2e-textfile.prom' -Destination "$($textfile_dir)/e2e-textfile.prom"
# Omit dynamic collector information that will change after each run
$skip_re = "^(go_|windows_exporter_build_info|windows_exporter_collector_duration_seconds|windows_exporter_perflib_snapshot_duration_seconds|windows_exporter_scrape_duration_seconds|process_|windows_textfile_mtime_seconds|windows_cpu|windows_cs|windows_cache|windows_logon|windows_logical_disk|windows_physical_disk|windows_memory|windows_net|windows_os|windows_process|windows_service_process|windows_printer|windows_udp|windows_tcp|windows_system|windows_time|windows_session|windows_perfdata|windows_textfile_mtime_seconds)"
$skip_re = "^(go_|windows_exporter_build_info|windows_exporter_collector_duration_seconds|windows_exporter_perflib_snapshot_duration_seconds|windows_exporter_scrape_duration_seconds|process_|windows_textfile_mtime_seconds|windows_cpu|windows_cs|windows_cache|windows_logon|windows_pagefile|windows_logical_disk|windows_physical_disk|windows_memory|windows_net|windows_os|windows_process|windows_service_process|windows_printer|windows_udp|windows_tcp|windows_system|windows_time|windows_session|windows_perfdata|windows_textfile_mtime_seconds)"
# Start process in background, awaiting HTTP requests.
# Use default collectors, port and address: http://localhost:9182/metrics
$exporter_proc = Start-Process `
-PassThru `
-FilePath ..\windows_exporter.exe `
-ArgumentList "--log.level=debug","--web.disable-exporter-metrics","--collectors.enabled=[defaults],cpu_info,textfile,process,perfdata,scheduled_task,tcp,udp,time,system,service,logical_disk,printer,os,net,memory,logon,cache","--collector.process.include=explorer.exe","--collector.scheduled_task.include=.*GAEvents","--collector.service.include=Themes","--collector.textfile.directories=$($textfile_dir)",@"
-ArgumentList "--log.level=debug","--web.disable-exporter-metrics","--collectors.enabled=[defaults],cpu_info,textfile,process,pagefile,perfdata,scheduled_task,tcp,udp,time,system,service,logical_disk,printer,os,net,memory,logon,cache","--collector.process.include=explorer.exe","--collector.scheduled_task.include=.*GAEvents","--collector.service.include=Themes","--collector.textfile.directories=$($textfile_dir)",@"
--collector.perfdata.objects="[{\"object\":\"Processor Information\",\"instance_label\":\"core\",\"instances\":[\"*\"],\"counters\":{\"% Processor Time\":{},\"% Privileged Time\":{}}},{\"object\":\"Memory\",\"counters\":{\"Cache Faults/sec\":{\"type\":\"counter\"}}}]"
"@ `
-WindowStyle Hidden `