- 可观测性
- 指标监控
【免费下载链接】windows_exporter
Prometheus exporter for Windows machines
netframework 是 windows_exporter 中用于采集 .NET Framework 运行时性能计数器的收集器,它通过 Windows 性能数据助手(PDH,Performance Data Helper)直接读取.NET CLR Exceptions、.NET CLR Memory、.NET CLR Jit等八个计数器对象,按进程粒度暴露异常、GC、JIT 编译、线程锁、互操作等运行时指标。读完本文,你将掌握该收集器的启用与子收集器配置方法、全部 47 个指标的名称/类型/标签语义、以及源码层面"单查询采样 + 原始计数器换算"的实现原理与兼容性处理细节。
收集器概述与基本信息
netframework 收集器的定位非常明确:为运行在 Windows 上的 .NET Framework 应用程序提供 Prometheus 可观测性。它保留了 PDH 原始计数器的度量类型与单位,其中按秒计数的计数器按文档约定以累计值(cumulative)形式发布。该收集器的关键属性如下:
| 属性 | 值 |
|---|---|
| Metric name prefix | netframework |
| Performance counter objects | .NET CLR Exceptions、.NET CLR Interop、.NET CLR Jit、.NET CLR Loading、.NET CLR LocksAndThreads、.NET CLR Memory、.NET CLR Remoting、.NET CLR Security |
| Enabled by default? | 否 |
从 README.md 的收集器清单可以看到,netframework 被归类为 ".NET Framework metrics",默认不随主程序启用,需要显式开启。
三个需要特别注意的行为约定
原文档明确了该收集器在数据语义上的三条约定,理解它们对正确解读指标至关重要:
_Global_实例被排除:.NET CLR 计数器对象中的_Global_聚合实例不会出现在输出中,只有具体进程实例(如w3wp、worker)才会生成指标序列。- 实例后缀不是稳定进程标识:在一次抓取中,PDH 会为同名的多个进程追加出现次数后缀(如
worker、worker#1),用于在同一时间点区分同名进程;这些后缀不是稳定的进程标识符,进程重启后同名实例的序号可能变化。若需要稳定关联进程,应结合 CLR Memory 系列指标中携带的process_id标签使用。 - 缺失计数器对象的处理:某个性能计数器对象(如
.NET CLR Remoting)不存在时,该子收集器返回无数据;而单个计数器初始化失败则会被报告为错误。这一差异化的容错策略由源码中的onlyMissingObject判定逻辑实现(详见下文源码解读)。
时间类指标的兼容性换算
为保证与既有监控体系兼容,文档特别说明了两类时间指标的换算规则:
- JIT 与运行时安全检查时间(
windows_netframework_clrjit_jit_time_percent、windows_netframework_clrsecurity_rt_checks_time_percent):保留原始计数器分子除以性能计数器频率(performance-clock frequency)的结果。源码在 netframework.go 中通过QueryPerformanceFrequency获取频率并缓存为perfFrequency,采集时执行raw / perfFrequency换算(见 netframework_clrjit.go)。 - GC 时间(
windows_netframework_clrmemory_gc_time_percent):使用100 * raw分子 / raw基数计算;当基数(base)为 0 时,该样本跳过此指标,但其余有效指标照常发布。此逻辑在 netframework_clrmemory.go 中实现,并有专门测试 TestGCZeroBaseDoesNotPublishInvalidRatio 验证:base 为 0 时gc_time_percent不出现,而allocated_bytes_total仍正常输出。
启用与配置:命令行 Flag 与 YAML 配置
命令行 Flag:--collector.netframework.enabled
由于 netframework 默认不启用,第一步需要在全局收集器开关中显式加入:
windows_exporter.exe --collectors.enabled=netframework第二步是通过--collector.netframework.enabled控制该收集器内部启用的子收集器。它是一个逗号分隔的子收集器列表,未指定时默认启用全部,支持的值如下:
| 值 | 对应计数器对象 |
|---|---|
clrexceptions | .NET CLR Exceptions |
clrinterop | .NET CLR Interop |
clrjit | .NET CLR Jit |
clrloading | .NET CLR Loading |
clrlocksandthreads | .NET CLR LocksAndThreads |
clrmemory | .NET CLR Memory |
clrremoting | .NET CLR Remoting |
clrsecurity | .NET CLR Security |
示例(只采集异常与内存指标,减少抓取开销):
windows_exporter.exe --collectors.enabled=netframework --collector.netframework.enabled=clrexceptions,clrmemory从 netframework.go 可以看到该 Flag 的默认值由ConfigDefaults.CollectorsEnabled拼出,即上述 8 个子收集器全量;传入非法子收集器名时,Build会返回错误并列出所有合法取值(netframework.go)。
YAML 配置文件方式
在配置文件(参考 config.yaml 与 docs/example_config.yml 的结构)中,netframework 的配置项为collector.netframework.enabled,对应 pkg/collector/config.go 中的netframework.Config结构体(其字段带yaml:"enabled"标签,见 netframework.go):
collectors: enabled: netframework collector: netframework: enabled: clrexceptions,clrinterop,clrjit,clrloading,clrlocksandthreads,clrmemory,clrremoting,clrsecurity默认配置由 pkg/collector/config.go 注入netframework.ConfigDefaults,子收集器注册与装配分别发生在 collection.go 与 map.go。
指标详解:八个 CLR 子收集器
所有指标名称均以windows_netframework_开头(windows为命名空间,netframework为收集器名)。下面按子收集器逐一列出完整指标语义。
CLR Exceptions(.NET CLR Exceptions)
| 名称 | 描述 | 类型 | 标签 |
|---|---|---|---|
windows_netframework_clrexceptions_exceptions_thrown_total | 显示自应用程序启动以来抛出的异常总数,包含 .NET 异常以及被转换为 .NET 异常的非托管异常。 | counter | process |
windows_netframework_clrexceptions_exceptions_filters_total | 显示已执行的 .NET 异常过滤器总数。无论异常是否被处理,过滤器都会被评估。 | counter | process |
windows_netframework_clrexceptions_exceptions_finallys_total | 显示已执行的 finally 块总数。仅统计因异常而执行的 finally 块,正常代码路径上的 finally 块不计入此计数器。 | counter | process |
windows_netframework_clrexceptions_throw_to_catch_depth_total | 显示从抛出异常的栈帧到处理异常的栈帧所遍历的栈帧总数。 | counter | process |
源码 netframework_clrexceptions.go 中对应的原始 PDH 计数器分别为# of Exceps Thrown、# of Filters / sec、# of Finallys / sec、Throw To Catch Depth / sec——注意这些按秒计数器的原始值直接以累计值发布,与文档开头的约定一致。
CLR Interop(.NET CLR Interop)
| 名称 | 描述 | 类型 | 标签 |
|---|---|---|---|
windows_netframework_clrinterop_com_callable_wrappers_total | 显示当前 COM 可调用包装器(CCW)的数量。CCW 是被非托管 COM 客户端引用的托管对象的代理。 | counter | process |
windows_netframework_clrinterop_interop_marshalling_total | 显示自应用程序启动以来参数与返回值在托管与非托管代码之间往返封送(marshal)的总次数。 | counter | process |
windows_netframework_clrinterop_interop_stubs_created_total | 显示公共语言运行时创建的存根(stub)当前数量。存根负责在 COM 互操作调用或平台调用(P/Invoke)期间封送参数与返回值。 | counter | process |
原始 PDH 计数器为# of CCWs、# of marshalling、# of Stubs(netframework_clrinterop.go)。注意与直觉相反,CCW 与 stub 的"当前数量"在输出中被声明为 counter 类型,这是沿用 PDH 原始类型的结果。
CLR JIT(.NET CLR Jit)
| 名称 | 描述 | 类型 | 标签 |
|---|---|---|---|
windows_netframework_clrjit_jit_methods_total | 显示自应用程序启动以来经 JIT 编译的方法总数,不含预 JIT(pre-JIT)编译的方法。 | counter | process |
windows_netframework_clrjit_jit_time_percent | 显示 JIT 编译所花费时间的百分比。该计数器在每个 JIT 编译阶段结束时更新;JIT 编译阶段发生在某个方法及其依赖项被编译时。 | gauge | process |
windows_netframework_clrjit_jit_standard_failures_total | 显示自应用程序启动以来 JIT 编译器编译失败的方法峰值数量。失败可能因 MSIL 无法验证或 JIT 编译器内部错误导致。 | gauge | process |
windows_netframework_clrjit_jit_il_bytes_total | 显示自应用程序启动以来 JIT 编译器编译的 Microsoft 中间语言(MSIL)字节总数。 | counter | process |
原始 PDH 计数器为# of Methods JITted、% Time in Jit、Standard Jit Failures、Total # of IL Bytes Jitted(netframework_clrjit.go)。jit_time_percent的取值即上文所述除以QueryPerformanceFrequency的结果。
CLR Loading(.NET CLR Loading)
| 名称 | 描述 | 类型 | 标签 |
|---|---|---|---|
windows_netframework_clrloading_loader_heap_size_bytes | 显示类加载器跨所有应用程序域提交的内存当前大小(字节)。已提交内存是在磁盘分页文件中预留的物理空间。 | gauge | process |
windows_netframework_clrloading_appdomains_loaded_current | 显示当前应用程序中已加载的应用程序域数量。 | gauge | process |
windows_netframework_clrloading_assemblies_loaded_current | 显示当前运行的应用程序中跨所有应用程序域加载的程序集数量。若程序集以域中立方式从多个应用程序域加载,此计数器仅递增一次。 | gauge | process |
windows_netframework_clrloading_classes_loaded_current | 显示所有程序集中当前已加载的类数量。 | gauge | process |
windows_netframework_clrloading_appdomains_loaded_total | 显示自应用程序启动以来应用程序域加载的峰值数量。 | counter | process |
windows_netframework_clrloading_appdomains_unloaded_total | 显示自应用程序启动以来卸载的应用程序域总数。若某个应用程序域被多次加载与卸载,每次卸载都会递增此计数器。 | counter | process |
windows_netframework_clrloading_assemblies_loaded_total | 显示自应用程序启动以来加载的程序集总数。若程序集以域中立方式从多个应用程序域加载,此计数器仅递增一次。 | counter | process |
windows_netframework_clrloading_classes_loaded_total | 显示自应用程序启动以来所有程序集中累计加载的类数量。 | counter | process |
windows_netframework_clrloading_class_load_failures_total | 显示自应用程序启动以来加载失败的类数量的峰值。 | counter | process |
原始 PDH 计数器包括Bytes in Loader Heap、Current appdomains、Current Assemblies、Current Classes Loaded、Total Appdomains、Total appdomains unloaded、Total Assemblies、Total Classes Loaded、Total # of Load Failures(netframework_clrloading.go)。
CLR Locks and Threads(.NET CLR LocksAndThreads)
| 名称 | 描述 | 类型 | 标签 |
|---|---|---|---|
windows_netframework_clrlocksandthreads_current_queue_length | 显示应用程序中当前等待获取托管锁的线程总数。 | gauge | process |
windows_netframework_clrlocksandthreads_current_logical_threads | 显示应用程序中当前的托管线程对象数量,同时统计运行中与已停止的线程。 | gauge | process |
windows_netframework_clrlocksandthreads_physical_threads_current | 显示由公共语言运行时创建并拥有的、作为托管线程对象底层支撑的原生操作系统线程数量。该值不包含运行时内部操作使用的线程,是操作系统进程中线程的一个子集。 | gauge | process |
windows_netframework_clrlocksandthreads_recognized_threads_current | 显示当前被运行时识别的线程数量。这些线程与对应的托管线程对象关联;运行时并不创建它们,但它们至少在运行时内运行过一次。 | gauge | process |
windows_netframework_clrlocksandthreads_recognized_threads_total | 显示自应用程序启动以来被运行时识别的线程总数,语义同recognized_threads_current。 | counter | process |
windows_netframework_clrlocksandthreads_queue_length_total | 显示自应用程序启动以来等待获取托管锁的线程总数。 | counter | process |
windows_netframework_clrlocksandthreads_contentions_total | 显示运行时中线程尝试获取托管锁但未成功的总次数。 | counter | process |
原始 PDH 计数器为Current Queue Length、# of current logical Threads、# of current physical Threads、# of current recognized threads、# of total recognized threads、Queue Length Peak、Total # of Contentions(netframework_clrlocksandthreads.go)。
CLR Memory(.NET CLR Memory)
| 名称 | 描述 | 类型 | 标签 |
|---|---|---|---|
windows_netframework_clrmemory_allocated_bytes_total | 显示在垃圾回收堆上分配的字节总数。 | counter | process,process_id |
windows_netframework_clrmemory_finalization_survivors | 显示因等待终结(finalize)而在回收后存活的垃圾回收对象数量。 | gauge | process,process_id |
windows_netframework_clrmemory_heap_size_bytes | 显示可分配的最大字节数;不代表当前已分配的字节数。 | gauge | process,process_id,area |
windows_netframework_clrmemory_promoted_bytes | 显示最近一次 GC 中从某一代晋升到下一代(promoted)的字节数。内存存活过垃圾回收即为晋升。 | gauge | process,process_id,area |
windows_netframework_clrmemory_number_gc_handles | 显示当前使用的垃圾回收句柄数量。GC 句柄是面向运行时与托管环境之外资源的句柄。 | gauge | process,process_id |
windows_netframework_clrmemory_collections_total | 显示自应用程序启动以来各代对象被垃圾回收的次数。 | counter | process,process_id,area |
windows_netframework_clrmemory_induced_gc_total | 显示因显式调用GC.Collect而执行垃圾回收的峰值次数。 | counter | process,process_id |
windows_netframework_clrmemory_number_pinned_objects | 显示最近一次垃圾回收中遇到的固定(pinned)对象数量。 | gauge | process,process_id |
windows_netframework_clrmemory_number_sink_blocksinuse | 显示当前使用的同步块数量。同步块是按对象分配、用于存储同步信息的数据结构;它们持有托管对象的弱引用,必须被垃圾回收器扫描。 | gauge | process,process_id |
windows_netframework_clrmemory_committed_bytes | 显示垃圾回收器当前提交的虚拟内存字节数。已提交内存是在磁盘分页文件中预留了空间的物理内存。 | gauge | process,process_id |
windows_netframework_clrmemory_reserved_bytes | 显示垃圾回收器当前保留的虚拟内存字节数。保留内存是在尚未使用磁盘或主内存页时为应用程序预留的虚拟内存空间。 | gauge | process,process_id |
windows_netframework_clrmemory_gc_time_percent | 显示最近一次采样中执行垃圾回收所花费时间的百分比。 | gauge | process,process_id |
CLR Memory 是唯一同时携带process_id标签的子收集器(process_id取自原始计数器Process ID),也是唯一带area标签的子收集器。从 netframework_clrmemory.go 的原始计数器映射与 collectClrMemory 的发布逻辑可以确认area的具体取值:
heap_size_bytes的area取值为Gen0、Gen1、Gen2、LOH(分别对应原始计数器Gen 0 heap size、Gen 1 heap size、Gen 2 heap size、Large Object Heap size);promoted_bytes的area取值为Gen0、Gen1(对应Gen 0 Promoted Bytes/Sec、Gen 1 Promoted Bytes/Sec);collections_total的area取值为Gen0、Gen1、Gen2(对应# Gen 0 Collections、# Gen 1 Collections、# Gen 2 Collections)。
其余原始计数器还包括Allocated Bytes/sec、Finalization Survivors、# GC Handles、# Induced GC、# of Pinned Objects、# of Sink Blocks in use、# Total committed Bytes、# Total reserved Bytes、% Time in GC及其 base 值% Time in GC,secondvalue。
CLR Remoting(.NET CLR Remoting)
| 名称 | 描述 | 类型 | 标签 |
|---|---|---|---|
windows_netframework_clrremoting_channels_total | 显示自应用程序启动以来跨所有应用程序域注册的远程处理通道总数。 | counter | process |
windows_netframework_clrremoting_context_bound_classes_loaded | 显示当前已加载的上下文绑定(context-bound)类数量。 | gauge | process |
windows_netframework_clrremoting_context_bound_objects_total | 显示已分配的上下文绑定对象总数。 | counter | process |
windows_netframework_clrremoting_context_proxies_total | 显示自进程启动以来该进程中的远程处理代理对象总数。 | counter | process |
windows_netframework_clrremoting_contexts | 显示应用程序中当前的远程处理上下文数量。 | gauge | process |
windows_netframework_clrremoting_remote_calls_total | 显示自应用程序启动以来调用的远程过程调用总数。 | counter | process |
原始 PDH 计数器为Channels、Context-Bound Classes Loaded、Context-Bound Objects Alloc / sec、Context Proxies、Contexts、Total Remote Calls(netframework_clrremoting.go)。值得一提的是,Remoting 计数器路径并未出现在当前微软官方 .NET Framework 性能计数器文档中,其路径由 netframework_counter_paths_test.go 依据 Netdata 的 perflib 收集器与 Mono 的 CLR 计数器定义交叉验证,测试注释中明确说明了这一出处。
CLR Security(.NET CLR Security)
| 名称 | 描述 | 类型 | 标签 |
|---|---|---|---|
windows_netframework_clrsecurity_link_time_checks_total | 显示自应用程序启动以来执行的链接时代码访问安全检查总数。 | counter | process |
windows_netframework_clrsecurity_rt_checks_time_percent | 显示最近一次采样中执行运行时代码访问安全检查所花费时间的百分比。 | gauge | process |
windows_netframework_clrsecurity_stack_walk_depth | 显示最近一次运行时代码访问安全检查期间的栈深度。 | gauge | process |
windows_netframework_clrsecurity_runtime_checks_total | 显示自应用程序启动以来执行的运行时代码访问安全检查总数。 | counter | process |
原始 PDH 计数器为# Link Time Checks、% Time in RT checks、Stack Walk Depth、Total Runtime Checks(netframework_clrsecurity.go)。其中rt_checks_time_percent与 JIT 时间指标一样,除以QueryPerformanceFrequency后发布。
源码实现:单查询采样与并发采集架构
该收集器的实现集中在 netframework.go,其架构有几个值得关注的工程决策:
1. 单一 PDH 查询采样全部子收集器。Collector结构体持有唯一的perfQuery *pdh.Query,在Build中通过pdh.NewQuery()创建,Collect阶段先执行一次perfQuery.Collect(),再让各子收集器读取同一份样本。源码注释解释了原因:.NET CLR 计数器提供程序一次只服务一个查询,且每个查询都会遍历所有 .NET 进程,独立查询会互相排队等待(netframework.go)。pdh.ErrNoData(无 .NET 进程)被放行,其余错误才上报。
2. 子收集器并发执行。各子收集器的 collect 函数通过recovery.Group并发运行(netframework.go),单个子收集器失败不会阻塞其余指标发布——测试 TestCollectRetainsSuccessfulChildMetrics 验证了"一个子收集器报错时,成功子收集器的指标仍被完整输出"。
3. 标签缓存降低开销。进程的process标签在其生命周期内保持不变,因此使用 labelcache 缓存系列标签对,跨抓取复用,避免重复分配 Prometheus label 对。
4. 缺失对象的优雅降级。newPerfCollector在初始化失败时调用onlyMissingObject递归解包错误(支持errors.Join的多错误包裹),若错误全部属于pdh.CstatusNoObject(计数器对象缺失),则返回unavailablePerfCollector——其Collect返回pdh.ErrNoData且不发布任何指标(netframework.go)。测试 TestMissingObjectErrorClassification 覆盖了"仅缺对象返回 true、混入其他错误返回 false、缺单个计数器不算缺对象"三种情况。这与文档中"缺失 counter object 返回无数据、缺失单个 counter 报告错误"的约定一一对应。
测试与验证体系
该收集器的正确性由三类测试保障:
- netframework_test.go:提供
TestCollector与BenchmarkCollector,通过 testutils 对收集器做端到端的抓取与基准测试。 - netframework_counter_paths_test.go:以反射方式校验每个
perfData结构体的perfdata标签与期望的 PDH 计数器名完全一致,覆盖全部 8 个子收集器共 60 余个计数器路径。 - netframework_pdh_test.go:使用
fixturePerfCollector注入固定原始值,逐指标断言名称、类型、数值与标签;测试中特意使用了worker、worker#1、report_Total等实例名,验证同名实例后缀被原样保留为process标签值,同时确认_Global_被排除。
使用建议与注意事项
- 按需启用子收集器:若只关心 GC 与内存,仅启用
clrmemory即可显著减少抓取数据量;clrremoting在当前 .NET Framework 文档中已无官方路径佐证,非 Remoting 场景可关闭。 - 结合
process_id定位进程:CLR Memory 系列的process_id标签是稳定且唯一的进程标识;其余子收集器仅靠process名称 + 出现序号区分同名进程,跨抓取关联时应以process_id为准。 - 时间类指标的单位语义:
jit_time_percent、rt_checks_time_percent、gc_time_percent均为百分比语义的 gauge,前两者由原始值除以性能计数器频率得到,后者为100 * raw / base;当 GC base 为 0 时该指标会暂时缺失,属预期行为而非采集故障。 - 无 .NET 进程时的表现:目标机器上没有运行任何 .NET Framework 进程时,
perfQuery.Collect()返回pdh.ErrNoData,收集器不输出任何 netframework 指标;若计数器对象整体缺失(例如精简安装),对应子收集器静默返回无数据,而单个计数器缺失则会在日志中报告初始化错误。
该收集器的完整官方文档位于 docs/collector.netframework.md,指标命名、标签与本文完全一致;源码入口为 internal/collector/netframework/,可按需深入阅读各子收集器的原始计数器映射与换算逻辑。
- 可观测性
- 指标监控
【免费下载链接】windows_exporter
Prometheus exporter for Windows machines
相关推荐
windows_exporter smb collector 完整指南:基于 PDH 性能计数器采集 SMB 服务器共享指标
windows_exporter smb collector 完整指南:基于 PDH 性能计数器采集 SMB 服务器共享指标 导读 smb collector
可观测性指标监控windows_exporter Process 收集器完全指南:基于 NtQuerySystemInformation 的进程指标采集与实战配置
windows_exporter Process 收集器完全指南:基于 NtQuerySystemInformation 的进程指标采集与实战配置 导读 本文深
可观测性指标监控windows_exporter 的 cpu 采集器详解:基于 Windows 性能计数器的 CPU 监控指标、PromQL 查询与告警实践
windows_exporter 的 cpu 采集器详解:基于 Windows 性能计数器的 CPU 监控指标、PromQL 查询与告警实践 本文围绕 wind
可观测性指标监控
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考