- 可观测性
- 指标监控
【免费下载链接】windows_exporter
Prometheus exporter for Windows machines
本文以 docs/collector.pagefile.md 为核心,结合 internal/collector/pagefile/pagefile.go 的实现源码,完整讲解 windows_exporter 中 pagefile collector 的启用方式、指标清单与示例输出,并深入剖析windows_pagefile_free_bytes与windows_pagefile_limit_bytes两项指标如何由 PDH 性能计数器Paging File和 Win32 APIGetPerformanceInfo联合计算而来,帮助读者掌握 Windows 页面文件(pagefile)用量监控的采集原理与落地方法。
pagefile collector 概览
pagefile collector 用于暴露操作系统页面文件(paging file,即pagefile.sys)的使用情况。在 Windows 中,物理内存不足时虚拟内存会落到页面文件上,当页面文件接近写满时,系统可能出现内存分配失败、commit 超限等问题,因此对它的容量与剩余空间进行持续监控是 Windows 主机监控中的常见需求。
根据 collector 文档 的元信息,该 collector 的关键属性如下:
| 属性 | 值 |
|---|---|
| Metric name prefix | pagefile |
| Data source | Performance counterPaging File、GetPerformanceInfo |
| Enabled by default? | No |
值得注意的是,该 collector默认不启用(README.md 的 collector 列表中 pagefile 一栏没有勾选标记)。这一点也可以从源码得到印证:pkg/collector/types.go 中定义的默认 collector 集合为:
const DefaultCollectors = "cpu,memory,logical_disk,physical_disk,net,os,service,system"pagefile不在其中,因此需要通过命令行或配置显式打开。
文档中 Flags 一节明确写着 "None",即该 collector 不注册任何专属命令行参数。从源码看也一致:pagefile.go 中NewWithFlags只是返回一个空的Collector{},而Config结构体为空结构体:
// internal/collector/pagefile/pagefile.go const Name = "pagefile" type Config struct{} var ConfigDefaults = Config{} func NewWithFlags(_ *kingpin.Application) *Collector { return &Collector{} }这也意味着 pagefile collector 没有可调参数,行为是确定的:采集所有页面文件实例。
启用方式:命令行与配置文件
通过--collectors.enabled启用
在 cmd/windows_exporter/main.go 中,exporter 通过 kingpin 注册了如下 flag:
--collectors.enabled:逗号分隔的 collector 列表,可使用[defaults]占位符代表所有默认启用的 collector;--collectors.disabled:要排除的 collector 列表,用于从默认集合中移除某项。
因此,单独启用 pagefile collector(只采集它):
.\windows_exporter.exe --collectors.enabled=pagefile在保留默认 collector 的基础上追加启用:
.\windows_exporter.exe --collectors.enabled=[defaults],pagefile--collectors.enabled的解析逻辑见 main.go 中的 expandEnabledCollectors:它先把字符串中的[defaults]替换为DefaultCollectors常量,再按逗号切分并去重。解析后的列表会经过 Collection.Enable 校验,出现未知 collector 名会直接报unknown collector错误。
通过库接口启用(YAML 配置)
pagefile collector 也可以作为库被外部程序集成。在 pkg/collector/config.go 中,其配置段以paging为 YAML 键名:
Paging pagefile.Config `yaml:"paging"`对应注册在 pkg/collector/collection.go:
collectors[pagefile.Name] = pagefile.New(&config.Paging)这里有一个容易混淆的细节:collector 的注册名是pagefile(用于--collectors.enabled),而库配置结构中的字段名/YAML 键是paging。由于pagefile.Config是空结构体,配置文件中并不需要为它写任何字段,了解这一命名差异即可避免查阅配置时产生困惑。
指标清单与示例输出
pagefile collector 暴露两个 gauge 指标,均以页面文件路径作为file标签区分多个页面文件实例:
| 指标名 | 说明 | 类型 | 标签 |
|---|---|---|---|
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(页面文件可存储的总字节数,0 表示没有页面文件) | gauge | file |
这两个指标描述文本同时硬编码在 pagefile.go 的 Build 方法 中:
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, )prometheus.BuildFQName以 internal/types/const.go 中的Namespace = "windows"加上 collector 名pagefile和指标后缀拼接出最终的windows_pagefile_*名称。
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从示例可以看出:一台在C:\下配置了约 6 GB 页面文件的机器,limit_bytes约为 6.44e9 字节,free_bytes约为 6.03e9 字节,二者之差即当前已被使用的页面文件空间。
底层原理:两个指标是如何计算出来的
文档给出的数据源是 "Performance counterPaging File,GetPerformanceInfo"。结合源码,完整的数据流如下:
1. PDH 采集Paging File对象的% Usage计数器
collector 通过通用的 PDH 框架 internal/pdh/collector.go 采集性能计数器。在 Build 中:
c.perfDataCollector, err = pdh.NewCollectorperfDataCounterValues), pdh.CounterTypeRaw, "Paging File", pdh.InstancesAll, )参数含义:
pdh.CounterTypeRaw:读取原始计数值(而非格式化后的显示值);"Paging File":Windows 性能对象名;pdh.InstancesAll:即["*"],采集所有实例——每个页面文件就是一个实例。
采集哪些计数器由泛型结构体的perfdatatag 声明,见 internal/collector/pagefile/types.go:
type perfDataCounterValues struct { Name string Usage float64 `perfdata:"% Usage"` }pdh.NewCollector会扫描结构体字段,按 tag 把计数器路径组装为\Paging File(*)\% Usage(见 formatCounterPath),并注册所有实例。采集结果按行填回perfDataCounterValues:Name为实例名(即页面文件路径),Usage为% Usage计数器的原始值——在 Windows 中该计数器的 raw 值代表已使用的页面数,这也是 collector 能把它当作页数使用的原因。
2. 通过GetPerformanceInfo获取系统页大小
把页数换算成字节需要系统的页大小。collector 调用 psapi.dll 的GetPerformanceInfoWin32 API,其绑定见 internal/headers/psapi/psapi.go:
// PerformanceInformation is a wrapper of the PERFORMANCE_INFORMATION struct. type PerformanceInformation struct { cb uint32 CommitTotal uint CommitLimit uint CommitPeak uint PhysicalTotal uint PhysicalAvailable uint SystemCache uint KernelTotal uint KernelPaged uint KernelNonpaged uint PageSize uint HandleCount uint32 ProcessCount uint32 ThreadCount uint32 }GetPerformanceInfo()通过windows.NewLazySystemDLL("psapi.dll")延迟加载并调用该 API,返回包含PageSize(通常为 4096 字节)在内的PERFORMANCE_INFORMATION结构。
3. 计算 free 与 limit
Collect 方法 的完整逻辑:
func (c *Collector) Collect(ch chan<- prometheus.Metric, _ time.Duration) error { err := c.perfDataCollector.Collect(&c.perfDataObject) if err != nil { return fmt.Errorf("failed to collect Paging File metrics: %w", err) } gpi, err := psapi.GetPerformanceInfo() if err != nil { return err } for _, data := range c.perfDataObject { fileString := strings.ReplaceAll(data.Name, `\??\`, "") 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-(data.Usage*float64(gpi.PageSize)), fileString, ) ch <- prometheus.MustNewConstMetric( c.pagingLimitBytes, prometheus.GaugeValue, fileSize, fileString, ) } return nil }三个实现细节值得注意:
limit_bytes取的是磁盘上页面文件的大小,即os.Stat(pagefile).Size(),而不是 PDH 计数器提供的"最大可用"值。页大小由GetPerformanceInfo提供,因此文档把两者都列为数据源。- 实例名会剥离
\??\前缀。PDH 报告的页面文件实例名是 NT 内核风格路径(如\??\C:\pagefile.sys),collector 用strings.ReplaceAll去掉前缀,得到可供 Prometheus 查询的常规路径C:\pagefile.sys,这也解释了示例指标中file="C:\\pagefile.sys"的形态。 - 页面文件不存在时不中断采集。代码注释说明 "For unknown reasons, Windows doesn't always create a page file"。若
os.Stat失败,fileSize保持 0,limit_bytes输出 0(与指标说明中"0 表示没有页面文件"的语义一致),采集继续进行而非整体报错。从源码结构看,这种"降级继续"的策略意味着个别实例异常不会影响其他实例的指标输出。
综合起来,指标的计算关系为:
windows_pagefile_limit_bytes{file} = stat(pagefile).Size windows_pagefile_free_bytes{file} = stat(pagefile).Size − 已用页数(% Usage raw) × PageSize注册、生命周期与测试
注册到 collector 映射
pagefile collector 在 pkg/collector/map.go 中被挂入 builders 映射:
pagefile.Name: NewBuilderWithFlags(pagefile.NewWithFlags),运行时所有启用的 collector 并发采集(见 pkg/collector/collect.go 的collectAll),每个 collector 的成败与耗时分别体现在 exporter 自带指标windows_exporter_collector_success{collector="pagefile"}、windows_exporter_collector_duration_seconds{collector="pagefile"}上,可用于确认该 collector 是否在工作。
单元测试与基准测试
collector 的测试位于 internal/collector/pagefile/pagefile_test.go:
func BenchmarkCollector(b *testing.B) { testutils.FuncBenchmarkCollector(b, pagefile.Name, pagefile.NewWithFlags) } func TestCollector(t *testing.T) { testutils.TestCollector(t, pagefile.New, nil) }internal/utils/testutils/testutils.go 中的TestCollector会在真实 Windows 环境上执行Build与两次Collect,把结果注册进prometheus.NewPedanticRegistry校验指标合法性,并通过WINDOWS_EXPORTER_TEST_COLLECTORS环境变量区分 CI 预置环境与本地开发机(后者遇到不支持的子系统会 skip)。FuncBenchmarkCollector则循环执行Collect以测量单轮采集开销。
实用查询与告警(社区待补充)
需要如实说明:按照 collector 文档 的当前状态,"Useful queries" 与 "Alerting examples" 两个小节均标注为占位内容——"This collector does not yet have useful queries, we would appreciate your help adding them!"。也就是说,仓库当前并未为该 collector 提供官方示例查询或告警规则,这部分正是社区可以贡献的方向。
如果要按 docs/collector-template.md 的结构贡献内容,基于本文给出的两个指标,合理的起点可以围绕"页面文件剩余比例"这类派生量展开,例如以windows_pagefile_free_bytes / windows_pagefile_limit_bytes作为基础表达式。此外,仓库中已有关于 commit 内存超限的 runbook docs/runbooks/windowsmemorycommithighusage.md 在排查步骤中明确提到了检查页面文件配置与容量:
Get-CimInstance Win32_PageFileUsage Get-CimInstance Win32_PageFileSetting Get-Volume这说明 pagefile 指标与内存 commit 告警场景是天然相关的:commit limit 受物理内存与页面文件容量共同约束,当windows_pagefile_free_bytes持续走低时,往往是触发 commit 类告警的前兆之一。
小结
- pagefile collector 通过 PDH
Paging File(*)\% Usage计数器与 Win32GetPerformanceInfo的PageSize,结合磁盘上pagefile.sys文件的实际大小,计算出每个页面文件的limit_bytes(总容量)与free_bytes(剩余空间)两个 gauge 指标,并以file标签支持多页面文件场景; - 它默认不启用、无任何专属 flag,启用方式为
--collectors.enabled=pagefile(或[defaults],pagefile),库集成的 YAML 键为paging; - 页大小换算、
\??\前缀剥离、页文件缺失时的降级策略等实现细节均可在 internal/collector/pagefile/pagefile.go 中直接核对; - 官方查询与告警示例目前仍是社区待补充状态,结合内存 commit 监控的 runbook 场景,剩余空间比例是构建派生指标和告警的自然切入点。
- 可观测性
- 指标监控
【免费下载链接】windows_exporter
Prometheus exporter for Windows machines
相关推荐
windows_exporter msmq Collector:基于性能计数器监控 MSMQ 消息队列
windows_exporter msmq Collector:基于性能计数器监控 MSMQ 消息队列 msmq collector 用于在 Windows 机
可观测性指标监控windows_exporter 的 cpu 采集器详解:基于 Windows 性能计数器的 CPU 监控指标、PromQL 查询与告警实践
windows_exporter 的 cpu 采集器详解:基于 Windows 性能计数器的 CPU 监控指标、PromQL 查询与告警实践 本文围绕 wind
可观测性指标监控windows_exporter fsrmquota Collector 详解:用 Prometheus 监控 FSRM 磁盘配额
windows_exporter fsrmquota Collector 详解:用 Prometheus 监控 FSRM 磁盘配额 本文以 fsrmquota
可观测性指标监控
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考