//go:build windows // +build windows package collector import ( "errors" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/yusufpapurcu/wmi" ) // A VmwareCollector is a Prometheus collector for WMI Win32_PerfRawData_vmGuestLib_VMem/Win32_PerfRawData_vmGuestLib_VCPU metrics type VmwareCollector struct { logger log.Logger MemActive *prometheus.Desc MemBallooned *prometheus.Desc MemLimit *prometheus.Desc MemMapped *prometheus.Desc MemOverhead *prometheus.Desc MemReservation *prometheus.Desc MemShared *prometheus.Desc MemSharedSaved *prometheus.Desc MemShares *prometheus.Desc MemSwapped *prometheus.Desc MemTargetSize *prometheus.Desc MemUsed *prometheus.Desc CpuLimitMHz *prometheus.Desc CpuReservationMHz *prometheus.Desc CpuShares *prometheus.Desc CpuStolenTotal *prometheus.Desc CpuTimeTotal *prometheus.Desc EffectiveVMSpeedMHz *prometheus.Desc HostProcessorSpeedMHz *prometheus.Desc } // newVmwareCollector constructs a new VmwareCollector func newVmwareCollector(logger log.Logger) (Collector, error) { const subsystem = "vmware" return &VmwareCollector{ logger: log.With(logger, "collector", subsystem), MemActive: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_active_bytes"), "(MemActiveMB)", nil, nil, ), MemBallooned: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_ballooned_bytes"), "(MemBalloonedMB)", nil, nil, ), MemLimit: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_limit_bytes"), "(MemLimitMB)", nil, nil, ), MemMapped: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_mapped_bytes"), "(MemMappedMB)", nil, nil, ), MemOverhead: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_overhead_bytes"), "(MemOverheadMB)", nil, nil, ), MemReservation: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_reservation_bytes"), "(MemReservationMB)", nil, nil, ), MemShared: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_shared_bytes"), "(MemSharedMB)", nil, nil, ), MemSharedSaved: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_shared_saved_bytes"), "(MemSharedSavedMB)", nil, nil, ), MemShares: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_shares"), "(MemShares)", nil, nil, ), MemSwapped: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_swapped_bytes"), "(MemSwappedMB)", nil, nil, ), MemTargetSize: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_target_size_bytes"), "(MemTargetSizeMB)", nil, nil, ), MemUsed: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "mem_used_bytes"), "(MemUsedMB)", nil, nil, ), CpuLimitMHz: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "cpu_limit_mhz"), "(CpuLimitMHz)", nil, nil, ), CpuReservationMHz: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "cpu_reservation_mhz"), "(CpuReservationMHz)", nil, nil, ), CpuShares: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "cpu_shares"), "(CpuShares)", nil, nil, ), CpuStolenTotal: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "cpu_stolen_seconds_total"), "(CpuStolenMs)", nil, nil, ), CpuTimeTotal: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "cpu_time_seconds_total"), "(CpuTimePercents)", nil, nil, ), EffectiveVMSpeedMHz: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "effective_vm_speed_mhz"), "(EffectiveVMSpeedMHz)", nil, nil, ), HostProcessorSpeedMHz: prometheus.NewDesc( prometheus.BuildFQName(Namespace, subsystem, "host_processor_speed_mhz"), "(HostProcessorSpeedMHz)", nil, nil, ), }, nil } // Collect sends the metric values for each metric // to the provided prometheus Metric channel. func (c *VmwareCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error { if desc, err := c.collectMem(ch); err != nil { _ = level.Error(c.logger).Log("failed collecting vmware memory metrics", "desc", desc, "err", err) return err } if desc, err := c.collectCpu(ch); err != nil { _ = level.Error(c.logger).Log("failed collecting vmware cpu metrics", "desc", desc, "err", err) return err } return nil } type Win32_PerfRawData_vmGuestLib_VMem struct { MemActiveMB uint64 MemBalloonedMB uint64 MemLimitMB uint64 MemMappedMB uint64 MemOverheadMB uint64 MemReservationMB uint64 MemSharedMB uint64 MemSharedSavedMB uint64 MemShares uint64 MemSwappedMB uint64 MemTargetSizeMB uint64 MemUsedMB uint64 } type Win32_PerfRawData_vmGuestLib_VCPU struct { CpuLimitMHz uint64 CpuReservationMHz uint64 CpuShares uint64 CpuStolenMs uint64 CpuTimePercents uint64 EffectiveVMSpeedMHz uint64 HostProcessorSpeedMHz uint64 } func (c *VmwareCollector) collectMem(ch chan<- prometheus.Metric) (*prometheus.Desc, error) { var dst []Win32_PerfRawData_vmGuestLib_VMem q := queryAll(&dst, c.logger) if err := wmi.Query(q, &dst); err != nil { return nil, err } if len(dst) == 0 { return nil, errors.New("WMI query returned empty result set") } ch <- prometheus.MustNewConstMetric( c.MemActive, prometheus.GaugeValue, mbToBytes(dst[0].MemActiveMB), ) ch <- prometheus.MustNewConstMetric( c.MemBallooned, prometheus.GaugeValue, mbToBytes(dst[0].MemBalloonedMB), ) ch <- prometheus.MustNewConstMetric( c.MemLimit, prometheus.GaugeValue, mbToBytes(dst[0].MemLimitMB), ) ch <- prometheus.MustNewConstMetric( c.MemMapped, prometheus.GaugeValue, mbToBytes(dst[0].MemMappedMB), ) ch <- prometheus.MustNewConstMetric( c.MemOverhead, prometheus.GaugeValue, mbToBytes(dst[0].MemOverheadMB), ) ch <- prometheus.MustNewConstMetric( c.MemReservation, prometheus.GaugeValue, mbToBytes(dst[0].MemReservationMB), ) ch <- prometheus.MustNewConstMetric( c.MemShared, prometheus.GaugeValue, mbToBytes(dst[0].MemSharedMB), ) ch <- prometheus.MustNewConstMetric( c.MemSharedSaved, prometheus.GaugeValue, mbToBytes(dst[0].MemSharedSavedMB), ) ch <- prometheus.MustNewConstMetric( c.MemShares, prometheus.GaugeValue, float64(dst[0].MemShares), ) ch <- prometheus.MustNewConstMetric( c.MemSwapped, prometheus.GaugeValue, mbToBytes(dst[0].MemSwappedMB), ) ch <- prometheus.MustNewConstMetric( c.MemTargetSize, prometheus.GaugeValue, mbToBytes(dst[0].MemTargetSizeMB), ) ch <- prometheus.MustNewConstMetric( c.MemUsed, prometheus.GaugeValue, mbToBytes(dst[0].MemUsedMB), ) return nil, nil } func mbToBytes(mb uint64) float64 { return float64(mb * 1024 * 1024) } func (c *VmwareCollector) collectCpu(ch chan<- prometheus.Metric) (*prometheus.Desc, error) { var dst []Win32_PerfRawData_vmGuestLib_VCPU q := queryAll(&dst, c.logger) if err := wmi.Query(q, &dst); err != nil { return nil, err } if len(dst) == 0 { return nil, errors.New("WMI query returned empty result set") } ch <- prometheus.MustNewConstMetric( c.CpuLimitMHz, prometheus.GaugeValue, float64(dst[0].CpuLimitMHz), ) ch <- prometheus.MustNewConstMetric( c.CpuReservationMHz, prometheus.GaugeValue, float64(dst[0].CpuReservationMHz), ) ch <- prometheus.MustNewConstMetric( c.CpuShares, prometheus.GaugeValue, float64(dst[0].CpuShares), ) ch <- prometheus.MustNewConstMetric( c.CpuStolenTotal, prometheus.CounterValue, float64(dst[0].CpuStolenMs)*ticksToSecondsScaleFactor, ) ch <- prometheus.MustNewConstMetric( c.CpuTimeTotal, prometheus.CounterValue, float64(dst[0].CpuTimePercents)*ticksToSecondsScaleFactor, ) ch <- prometheus.MustNewConstMetric( c.EffectiveVMSpeedMHz, prometheus.GaugeValue, float64(dst[0].EffectiveVMSpeedMHz), ) ch <- prometheus.MustNewConstMetric( c.HostProcessorSpeedMHz, prometheus.GaugeValue, float64(dst[0].HostProcessorSpeedMHz), ) return nil, nil }