diff --git a/README.md b/README.md index e3669a7c..8566f514 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Name | Description | Enabled by default [iis](docs/collector.iis.md) | [Win32_PerfRawData_W3SVC_WebService](https://msdn.microsoft.com/en-us/library/aa394345) IIS metrics | [logical_disk](docs/collector.logical_disk.md) | [Win32_PerfRawData_PerfDisk_LogicalDisk](https://msdn.microsoft.com/en-us/windows/hardware/aa394307(v=vs.71)) metrics (disk I/O) | ✓ [net](docs/collector.net.md) | [Win32_PerfRawData_Tcpip_NetworkInterface](https://technet.microsoft.com/en-us/security/aa394340(v=vs.80)) metrics (network interface I/O) | ✓ +[memory](docs/collector.memory.md) | Memory usage metrics | [msmq](docs/collector.msmq.md) | [Win32_PerfRawData_MSMQ_MSMQQueue](http://wutils.com/wmi/root/cimv2/win32_perfrawdata_msmq_msmqqueue/) metrics (MSMQ/journal count) | [mssql](docs/collector.mssql.md) | various [SQL Server Performance Objects](https://docs.microsoft.com/en-us/sql/relational-databases/performance-monitor/use-sql-server-objects#SQLServerPOs) metrics | [os](docs/collector.os.md) | [Win32_OperatingSystem](https://msdn.microsoft.com/en-us/library/aa394239) metrics (memory, processes, users) | ✓ diff --git a/collector/memory.go b/collector/memory.go new file mode 100644 index 00000000..e9cffc4d --- /dev/null +++ b/collector/memory.go @@ -0,0 +1,501 @@ +// returns data points from Win32_PerfRawData_PerfOS_Memory +// - Win32_PerfRawData_PerfOS_Memory class +package collector + +import ( + "github.com/StackExchange/wmi" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/log" +) + +func init() { + Factories["memory"] = NewMemoryCollector +} + +// A MemoryCollector is a Prometheus collector for WMI Win32_PerfRawData_PerfOS_Memory metrics +type MemoryCollector struct { + AvailableBytes *prometheus.Desc + CacheBytes *prometheus.Desc + CacheBytesPeak *prometheus.Desc + CacheFaultsTotal *prometheus.Desc + CommitLimit *prometheus.Desc + CommittedBytes *prometheus.Desc + DemandZeroFaultsTotal *prometheus.Desc + FreeAndZeroPageListBytes *prometheus.Desc + FreeSystemPageTableEntries *prometheus.Desc + ModifiedPageListBytes *prometheus.Desc + PageFaultsTotal *prometheus.Desc + SwapPageReadsTotal *prometheus.Desc + SwapPagesReadTotal *prometheus.Desc + SwapPagesWrittenTotal *prometheus.Desc + SwapPageOperationsTotal *prometheus.Desc + SwapPageWritesTotal *prometheus.Desc + PoolNonpagedAllocsTotal *prometheus.Desc + PoolNonpagedBytes *prometheus.Desc + PoolPagedAllocsTotal *prometheus.Desc + PoolPagedBytes *prometheus.Desc + PoolPagedResidentBytes *prometheus.Desc + StandbyCacheCoreBytes *prometheus.Desc + StandbyCacheNormalPriorityBytes *prometheus.Desc + StandbyCacheReserveBytes *prometheus.Desc + SystemCacheResidentBytes *prometheus.Desc + SystemCodeResidentBytes *prometheus.Desc + SystemCodeTotalBytes *prometheus.Desc + SystemDriverResidentBytes *prometheus.Desc + SystemDriverTotalBytes *prometheus.Desc + TransitionFaultsTotal *prometheus.Desc + TransitionPagesRepurposedTotal *prometheus.Desc + WriteCopiesTotal *prometheus.Desc +} + +// NewMemoryCollector ... +func NewMemoryCollector() (Collector, error) { + const subsystem = "memory" + + return &MemoryCollector{ + AvailableBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "available_bytes"), + "The amount of physical memory immediately available for allocation to a process or for system use. It is equal to the sum of memory assigned to"+ + " the standby (cached), free and zero page lists (AvailableBytes)", + nil, + nil, + ), + CacheBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "cache_bytes"), + "(CacheBytes)", + nil, + nil, + ), + CacheBytesPeak: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "cache_bytes_peak"), + "(CacheBytesPeak)", + nil, + nil, + ), + CacheFaultsTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "cache_faults_total"), + "(CacheFaultsPersec)", + nil, + nil, + ), + CommitLimit: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "commit_limit"), + "(CommitLimit)", + nil, + nil, + ), + CommittedBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "committed_bytes"), + "(CommittedBytes)", + nil, + nil, + ), + DemandZeroFaultsTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "demand_zero_faults_total"), + "The number of zeroed pages required to satisfy faults. Zeroed pages, pages emptied of previously stored data and filled with zeros, are a security"+ + " feature of Windows that prevent processes from seeing data stored by earlier processes that used the memory space (DemandZeroFaults)", + nil, + nil, + ), + FreeAndZeroPageListBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "free_and_zero_page_list_bytes"), + "(FreeAndZeroPageListBytes)", + nil, + nil, + ), + FreeSystemPageTableEntries: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "free_system_page_table_entries"), + "(FreeSystemPageTableEntries)", + nil, + nil, + ), + ModifiedPageListBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "modified_page_list_bytes"), + "(ModifiedPageListBytes)", + nil, + nil, + ), + PageFaultsTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "page_faults_total"), + "(PageFaultsPersec)", + nil, + nil, + ), + SwapPageReadsTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "swap_page_reads_total"), + "Number of disk page reads (a single read operation reading several pages is still only counted once) (PageReadsPersec)", + nil, + nil, + ), + SwapPagesReadTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "swap_pages_read_total"), + "Number of pages read across all page reads (ie counting all pages read even if they are read in a single operation) (PagesInputPersec)", + nil, + nil, + ), + SwapPagesWrittenTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "swap_pages_written_total"), + "Number of pages written across all page writes (ie counting all pages written even if they are written in a single operation) (PagesOutputPersec)", + nil, + nil, + ), + SwapPageOperationsTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "swap_page_operations_total"), + "Total number of swap page read and writes (PagesPersec)", + nil, + nil, + ), + SwapPageWritesTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "swap_page_writes_total"), + "Number of disk page writes (a single write operation writing several pages is still only counted once) (PageWritesPersec)", + nil, + nil, + ), + PoolNonpagedAllocsTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "pool_nonpaged_allocs_total"), + "The number of calls to allocate space in the nonpaged pool. The nonpaged pool is an area of system memory area for objects that cannot be written"+ + " to disk, and must remain in physical memory as long as they are allocated (PoolNonpagedAllocs)", + nil, + nil, + ), + PoolNonpagedBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "pool_nonpaged_bytes_total"), + "(PoolNonpagedBytes)", + nil, + nil, + ), + PoolPagedAllocsTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "pool_paged_allocs_total"), + "(PoolPagedAllocs)", + nil, + nil, + ), + PoolPagedBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "pool_paged_bytes"), + "(PoolPagedBytes)", + nil, + nil, + ), + PoolPagedResidentBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "pool_paged_resident_bytes"), + "(PoolPagedResidentBytes)", + nil, + nil, + ), + StandbyCacheCoreBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "standby_cache_core_bytes"), + "(StandbyCacheCoreBytes)", + nil, + nil, + ), + StandbyCacheNormalPriorityBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "standby_cache_normal_priority_bytes"), + "(StandbyCacheNormalPriorityBytes)", + nil, + nil, + ), + StandbyCacheReserveBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "standby_cache_reserve_bytes"), + "(StandbyCacheReserveBytes)", + nil, + nil, + ), + SystemCacheResidentBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "system_cache_resident_bytes"), + "(SystemCacheResidentBytes)", + nil, + nil, + ), + SystemCodeResidentBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "system_code_resident_bytes"), + "(SystemCodeResidentBytes)", + nil, + nil, + ), + SystemCodeTotalBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "system_code_total_bytes"), + "(SystemCodeTotalBytes)", + nil, + nil, + ), + SystemDriverResidentBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "system_driver_resident_bytes"), + "(SystemDriverResidentBytes)", + nil, + nil, + ), + SystemDriverTotalBytes: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "system_driver_total_bytes"), + "(SystemDriverTotalBytes)", + nil, + nil, + ), + TransitionFaultsTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "transition_faults_total"), + "(TransitionFaultsPersec)", + nil, + nil, + ), + TransitionPagesRepurposedTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "transition_pages_repurposed_total"), + "(TransitionPagesRePurposedPersec)", + nil, + nil, + ), + WriteCopiesTotal: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "write_copies_total"), + "The number of page faults caused by attempting to write that were satisfied by copying the page from elsewhere in physical memory (WriteCopiesPersec)", + nil, + nil, + ), + }, nil +} + +// Collect sends the metric values for each metric +// to the provided prometheus Metric channel. +func (c *MemoryCollector) Collect(ch chan<- prometheus.Metric) error { + if desc, err := c.collect(ch); err != nil { + log.Error("failed collecting memory metrics:", desc, err) + return err + } + return nil +} + +type Win32_PerfRawData_PerfOS_Memory struct { + AvailableBytes uint64 + AvailableKBytes uint64 + AvailableMBytes uint64 + CacheBytes uint64 + CacheBytesPeak uint64 + CacheFaultsPersec uint32 + CommitLimit uint64 + CommittedBytes uint64 + DemandZeroFaultsPersec uint32 + FreeAndZeroPageListBytes uint64 + FreeSystemPageTableEntries uint32 + ModifiedPageListBytes uint64 + PageFaultsPersec uint32 + PageReadsPersec uint32 + PagesInputPersec uint32 + PagesOutputPersec uint32 + PagesPersec uint32 + PageWritesPersec uint32 + PoolNonpagedAllocs uint32 + PoolNonpagedBytes uint64 + PoolPagedAllocs uint32 + PoolPagedBytes uint64 + PoolPagedResidentBytes uint64 + StandbyCacheCoreBytes uint64 + StandbyCacheNormalPriorityBytes uint64 + StandbyCacheReserveBytes uint64 + SystemCacheResidentBytes uint64 + SystemCodeResidentBytes uint64 + SystemCodeTotalBytes uint64 + SystemDriverResidentBytes uint64 + SystemDriverTotalBytes uint64 + TransitionFaultsPersec uint32 + TransitionPagesRePurposedPersec uint32 + WriteCopiesPersec uint32 +} + +func (c *MemoryCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) { + var dst []Win32_PerfRawData_PerfOS_Memory + q := queryAll(&dst) + if err := wmi.Query(q, &dst); err != nil { + return nil, err + } + + ch <- prometheus.MustNewConstMetric( + c.AvailableBytes, + prometheus.GaugeValue, + float64(dst[0].AvailableBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.CacheBytes, + prometheus.GaugeValue, + float64(dst[0].CacheBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.CacheBytesPeak, + prometheus.GaugeValue, + float64(dst[0].CacheBytesPeak), + ) + + ch <- prometheus.MustNewConstMetric( + c.CacheFaultsTotal, + prometheus.GaugeValue, + float64(dst[0].CacheFaultsPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.CommitLimit, + prometheus.GaugeValue, + float64(dst[0].CommitLimit), + ) + + ch <- prometheus.MustNewConstMetric( + c.CommittedBytes, + prometheus.GaugeValue, + float64(dst[0].CommittedBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.DemandZeroFaultsTotal, + prometheus.GaugeValue, + float64(dst[0].DemandZeroFaultsPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.FreeAndZeroPageListBytes, + prometheus.GaugeValue, + float64(dst[0].FreeAndZeroPageListBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.FreeSystemPageTableEntries, + prometheus.GaugeValue, + float64(dst[0].FreeSystemPageTableEntries), + ) + + ch <- prometheus.MustNewConstMetric( + c.ModifiedPageListBytes, + prometheus.GaugeValue, + float64(dst[0].ModifiedPageListBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.PageFaultsTotal, + prometheus.GaugeValue, + float64(dst[0].PageFaultsPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.SwapPageReadsTotal, + prometheus.GaugeValue, + float64(dst[0].PageReadsPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.SwapPagesReadTotal, + prometheus.GaugeValue, + float64(dst[0].PagesInputPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.SwapPagesWrittenTotal, + prometheus.GaugeValue, + float64(dst[0].PagesOutputPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.SwapPageOperationsTotal, + prometheus.GaugeValue, + float64(dst[0].PagesPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.SwapPageWritesTotal, + prometheus.GaugeValue, + float64(dst[0].PageWritesPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.PoolNonpagedAllocsTotal, + prometheus.GaugeValue, + float64(dst[0].PoolNonpagedAllocs), + ) + + ch <- prometheus.MustNewConstMetric( + c.PoolNonpagedBytes, + prometheus.GaugeValue, + float64(dst[0].PoolNonpagedBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.PoolPagedAllocsTotal, + prometheus.GaugeValue, + float64(dst[0].PoolPagedAllocs), + ) + + ch <- prometheus.MustNewConstMetric( + c.PoolPagedBytes, + prometheus.GaugeValue, + float64(dst[0].PoolPagedBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.PoolPagedResidentBytes, + prometheus.GaugeValue, + float64(dst[0].PoolPagedResidentBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.StandbyCacheCoreBytes, + prometheus.GaugeValue, + float64(dst[0].StandbyCacheCoreBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.StandbyCacheNormalPriorityBytes, + prometheus.GaugeValue, + float64(dst[0].StandbyCacheNormalPriorityBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.StandbyCacheReserveBytes, + prometheus.GaugeValue, + float64(dst[0].StandbyCacheReserveBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.SystemCacheResidentBytes, + prometheus.GaugeValue, + float64(dst[0].SystemCacheResidentBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.SystemCodeResidentBytes, + prometheus.GaugeValue, + float64(dst[0].SystemCodeResidentBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.SystemCodeTotalBytes, + prometheus.GaugeValue, + float64(dst[0].SystemCodeTotalBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.SystemDriverResidentBytes, + prometheus.GaugeValue, + float64(dst[0].SystemDriverResidentBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.SystemDriverTotalBytes, + prometheus.GaugeValue, + float64(dst[0].SystemDriverTotalBytes), + ) + + ch <- prometheus.MustNewConstMetric( + c.TransitionFaultsTotal, + prometheus.GaugeValue, + float64(dst[0].TransitionFaultsPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.TransitionPagesRepurposedTotal, + prometheus.GaugeValue, + float64(dst[0].TransitionPagesRePurposedPersec), + ) + + ch <- prometheus.MustNewConstMetric( + c.WriteCopiesTotal, + prometheus.GaugeValue, + float64(dst[0].WriteCopiesPersec), + ) + + return nil, nil +} diff --git a/docs/collector.memory.md b/docs/collector.memory.md new file mode 100644 index 00000000..2b5247c4 --- /dev/null +++ b/docs/collector.memory.md @@ -0,0 +1,59 @@ +# memory collector + +The memory collector exposes metrics about system memory usage + +Metric name prefix | `memory` +Classes | `Win32_PerfRawData_PerfOS_Memory` +Enabled by default? | Yes + +## Flags + +None + +## Metrics + +Name | Description | Type | Labels +-----|-------------|------|------- +`wmi_cs_logical_processors` | Number of installed logical processors | gauge | None +`wmi_cs_physical_memory_bytes` | Total installed physical memory | gauge | None +`wmi_memory_available_bytes` | The amount of physical memory immediately available for allocation to a process or for system use. It is equal to the sum of memory assigned to the standby (cached), free and zero page lists | gauge | None +`wmi_memory_cache_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_cache_bytes_peak` | _Not yet documented_ | gauge | None +`wmi_memory_cache_faults_total` | _Not yet documented_ | gauge | None +`wmi_memory_commit_limit` | _Not yet documented_ | gauge | None +`wmi_memory_committed_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_demand_zero_faults_total` | The number of zeroed pages required to satisfy faults. Zeroed pages, pages emptied of previously stored data and filled with zeros, are a security feature of Windows that prevent processes from seeing data stored by earlier processes that used the memory space | gauge | None +`wmi_memory_free_and_zero_page_list_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_free_system_page_table_entries` | _Not yet documented_ | gauge | None +`wmi_memory_modified_page_list_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_page_faults_total` | _Not yet documented_ | gauge | None +`wmi_memory_swap_page_reads_total` | Number of disk page reads (a single read operation reading several pages is still only counted once) | gauge | None +`wmi_memory_swap_pages_read_total` | Number of pages read across all page reads (ie counting all pages read even if they are read in a single operation) | gauge | None +`wmi_memory_swap_pages_written_total` | Number of pages written across all page writes (ie counting all pages written even if they are written in a single operation) | gauge | None +`wmi_memory_swap_page_operations_total` | Total number of swap page read and writes (PagesPersec) | gauge | None +`wmi_memory_swap_page_writes_total` | Number of disk page writes (a single write operation writing several pages is still only counted once) | gauge | None +`wmi_memory_pool_nonpaged_allocs_total` | The number of calls to allocate space in the nonpaged pool. The nonpaged pool is an area of system memory area for objects that cannot be written to disk, and must remain in physical memory as long as they are allocated | gauge | None +`wmi_memory_pool_nonpaged_bytes_total` | _Not yet documented_ | gauge | None +`wmi_memory_pool_paged_allocs_total` | _Not yet documented_ | gauge | None +`wmi_memory_pool_paged_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_pool_paged_resident_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_standby_cache_core_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_standby_cache_normal_priority_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_standby_cache_reserve_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_system_cache_resident_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_system_code_resident_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_system_code_total_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_system_driver_resident_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_system_driver_total_bytes` | _Not yet documented_ | gauge | None +`wmi_memory_transition_faults_total` | _Not yet documented_ | gauge | None +`wmi_memory_transition_pages_repurposed_total` | _Not yet documented_ | gauge | None +`wmi_memory_write_copies_total` | The number of page faults caused by attempting to write that were satisfied by copying the page from elsewhere in physical memory | gauge | None + +### Example metric +_This collector does not yet have explained examples, we would appreciate your help adding them!_ + +## 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!_