mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-17 10:16:35 +00:00
Compare commits
10 Commits
v0.7.0
...
v0.7.999-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daa6f3d111 | ||
|
|
85fdfb44b8 | ||
|
|
33879449a2 | ||
|
|
462a136673 | ||
|
|
d5e39892cf | ||
|
|
ec0d863c29 | ||
|
|
afc3655a41 | ||
|
|
e25e96a62e | ||
|
|
23d92cfcae | ||
|
|
1258703f23 |
@@ -40,12 +40,13 @@ after_build:
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
$BuildVersion = Get-Content VERSION
|
||||||
# The MSI version is not semver compliant, so just take the numerical parts
|
# The MSI version is not semver compliant, so just take the numerical parts
|
||||||
$Version = $env:APPVEYOR_REPO_TAG_NAME -replace '^v?([0-9\.]+).*$','$1'
|
$MSIVersion = $env:APPVEYOR_REPO_TAG_NAME -replace '^v?([0-9\.]+).*$','$1'
|
||||||
foreach($Arch in "amd64","386") {
|
foreach($Arch in "amd64","386") {
|
||||||
Write-Verbose "Building wmi_exporter $Version msi for $Arch"
|
Write-Verbose "Building wmi_exporter $MSIVersion msi for $Arch"
|
||||||
.\installer\build.ps1 -PathToExecutable .\output\$Arch\wmi_exporter-$Version-$Arch.exe -Version $Version -Arch "$Arch"
|
.\installer\build.ps1 -PathToExecutable .\output\$Arch\wmi_exporter-$BuildVersion-$Arch.exe -Version $MSIVersion -Arch "$Arch"
|
||||||
Move-Item installer\Output\wmi_exporter-$Version-$Arch.msi output\$Arch\
|
Move-Item installer\Output\wmi_exporter-$MSIVersion-$Arch.msi output\$Arch\
|
||||||
}
|
}
|
||||||
- promu checksum output\
|
- promu checksum output\
|
||||||
|
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ func NewADCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *ADCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *ADCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting ad metrics:", desc, err)
|
log.Error("failed collecting ad metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
39
collector/collector.go
Normal file
39
collector/collector.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leoluk/perflib_exporter/perflib"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ...
|
||||||
|
const (
|
||||||
|
// TODO: Make package-local
|
||||||
|
Namespace = "wmi"
|
||||||
|
|
||||||
|
// Conversion factors
|
||||||
|
ticksToSecondsScaleFactor = 1 / 1e7
|
||||||
|
windowsEpoch = 116444736000000000
|
||||||
|
)
|
||||||
|
|
||||||
|
// Factories ...
|
||||||
|
var Factories = make(map[string]func() (Collector, error))
|
||||||
|
|
||||||
|
// Collector is the interface a collector has to implement.
|
||||||
|
type Collector interface {
|
||||||
|
// Get new metrics and expose them via prometheus registry.
|
||||||
|
Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScrapeContext struct {
|
||||||
|
perfObjects map[string]*perflib.PerfObject
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareScrapeContext creates a ScrapeContext to be used during a single scrape
|
||||||
|
func PrepareScrapeContext() (*ScrapeContext, error) {
|
||||||
|
objs, err := getPerflibSnapshot()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ScrapeContext{objs}, nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build windows
|
// +build windows,cgo
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ func NewContainerMetricsCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *ContainerMetricsCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *ContainerMetricsCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting ContainerMetricsCollector metrics:", desc, err)
|
log.Error("failed collecting ContainerMetricsCollector metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
409
collector/cpu.go
409
collector/cpu.go
@@ -3,29 +3,104 @@
|
|||||||
package collector
|
package collector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/StackExchange/wmi"
|
"golang.org/x/sys/windows/registry"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/common/log"
|
"github.com/prometheus/common/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Factories["cpu"] = NewCPUCollector
|
Factories["cpu"] = newCPUCollector
|
||||||
}
|
}
|
||||||
|
|
||||||
// A CPUCollector is a Prometheus collector for WMI Win32_PerfRawData_PerfOS_Processor metrics
|
// A function to get Windows version from registry
|
||||||
type CPUCollector struct {
|
func getWindowsVersion() float64 {
|
||||||
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Couldn't open registry", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
err = k.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Failed to close registry key: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
currentv, _, err := k.GetStringValue("CurrentVersion")
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Couldn't open registry to determine current Windows version:", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
currentv_flt, err := strconv.ParseFloat(currentv, 64)
|
||||||
|
|
||||||
|
log.Debugf("Detected Windows version %f\n", currentv_flt)
|
||||||
|
|
||||||
|
return currentv_flt
|
||||||
|
}
|
||||||
|
|
||||||
|
type cpuCollectorBasic struct {
|
||||||
CStateSecondsTotal *prometheus.Desc
|
CStateSecondsTotal *prometheus.Desc
|
||||||
TimeTotal *prometheus.Desc
|
TimeTotal *prometheus.Desc
|
||||||
InterruptsTotal *prometheus.Desc
|
InterruptsTotal *prometheus.Desc
|
||||||
DPCsTotal *prometheus.Desc
|
DPCsTotal *prometheus.Desc
|
||||||
}
|
}
|
||||||
|
type cpuCollectorFull struct {
|
||||||
|
CStateSecondsTotal *prometheus.Desc
|
||||||
|
TimeTotal *prometheus.Desc
|
||||||
|
InterruptsTotal *prometheus.Desc
|
||||||
|
DPCsTotal *prometheus.Desc
|
||||||
|
ClockInterruptsTotal *prometheus.Desc
|
||||||
|
IdleBreakEventsTotal *prometheus.Desc
|
||||||
|
ParkingStatus *prometheus.Desc
|
||||||
|
ProcessorFrequencyMHz *prometheus.Desc
|
||||||
|
ProcessorMaxFrequencyMHz *prometheus.Desc
|
||||||
|
ProcessorPerformance *prometheus.Desc
|
||||||
|
}
|
||||||
|
|
||||||
// NewCPUCollector constructs a new CPUCollector
|
// newCPUCollector constructs a new cpuCollector, appropriate for the running OS
|
||||||
func NewCPUCollector() (Collector, error) {
|
func newCPUCollector() (Collector, error) {
|
||||||
const subsystem = "cpu"
|
const subsystem = "cpu"
|
||||||
return &CPUCollector{
|
|
||||||
|
version := getWindowsVersion()
|
||||||
|
// Windows version by number https://docs.microsoft.com/en-us/windows/desktop/sysinfo/operating-system-version
|
||||||
|
// For Windows 2008 or earlier Windows version is 6.0 or lower, where we only have the older "Processor" counters
|
||||||
|
// For Windows 2008 R2 or later Windows version is 6.1 or higher, so we can use "ProcessorInformation" counters
|
||||||
|
// Value 6.05 was selected just to split between Windows versions
|
||||||
|
if version < 6.05 {
|
||||||
|
return &cpuCollectorBasic{
|
||||||
|
CStateSecondsTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, "cstate_seconds_total"),
|
||||||
|
"Time spent in low-power idle state",
|
||||||
|
[]string{"core", "state"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
TimeTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, "time_total"),
|
||||||
|
"Time that processor spent in different modes (idle, user, system, ...)",
|
||||||
|
[]string{"core", "mode"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
InterruptsTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, "interrupts_total"),
|
||||||
|
"Total number of received and serviced hardware interrupts",
|
||||||
|
[]string{"core"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
DPCsTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, "dpcs_total"),
|
||||||
|
"Total number of received and serviced deferred procedure calls (DPCs)",
|
||||||
|
[]string{"core"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cpuCollectorFull{
|
||||||
CStateSecondsTotal: prometheus.NewDesc(
|
CStateSecondsTotal: prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(Namespace, subsystem, "cstate_seconds_total"),
|
prometheus.BuildFQName(Namespace, subsystem, "cstate_seconds_total"),
|
||||||
"Time spent in low-power idle state",
|
"Time spent in low-power idle state",
|
||||||
@@ -38,7 +113,6 @@ func NewCPUCollector() (Collector, error) {
|
|||||||
[]string{"core", "mode"},
|
[]string{"core", "mode"},
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
|
|
||||||
InterruptsTotal: prometheus.NewDesc(
|
InterruptsTotal: prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(Namespace, subsystem, "interrupts_total"),
|
prometheus.BuildFQName(Namespace, subsystem, "interrupts_total"),
|
||||||
"Total number of received and serviced hardware interrupts",
|
"Total number of received and serviced hardware interrupts",
|
||||||
@@ -51,164 +125,273 @@ func NewCPUCollector() (Collector, error) {
|
|||||||
[]string{"core"},
|
[]string{"core"},
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
|
ClockInterruptsTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, "clock_interrupts_total"),
|
||||||
|
"Total number of received and serviced clock tick interrupts",
|
||||||
|
[]string{"core"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
IdleBreakEventsTotal: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, "idle_break_events_total"),
|
||||||
|
"Total number of time processor was woken from idle",
|
||||||
|
[]string{"core"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
ParkingStatus: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, "parking_status"),
|
||||||
|
"Parking Status represents whether a processor is parked or not",
|
||||||
|
[]string{"core"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
ProcessorFrequencyMHz: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, "core_frequency_mhz"),
|
||||||
|
"Core frequency in megahertz",
|
||||||
|
[]string{"core"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
ProcessorPerformance: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, "processor_performance"),
|
||||||
|
"Processor Performance is the average performance of the processor while it is executing instructions, as a percentage of the nominal performance of the processor. On some processors, Processor Performance may exceed 100%",
|
||||||
|
[]string{"core"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
type perflibProcessor struct {
|
||||||
// to the provided prometheus Metric channel.
|
Name string
|
||||||
func (c *CPUCollector) Collect(ch chan<- prometheus.Metric) error {
|
C1Transitions float64 `perflib:"C1 Transitions/sec"`
|
||||||
if desc, err := c.collect(ch); err != nil {
|
C2Transitions float64 `perflib:"C2 Transitions/sec"`
|
||||||
log.Error("failed collecting cpu metrics:", desc, err)
|
C3Transitions float64 `perflib:"C3 Transitions/sec"`
|
||||||
|
DPCRate float64 `perflib:"DPC Rate"`
|
||||||
|
DPCsQueued float64 `perflib:"DPCs Queued/sec"`
|
||||||
|
Interrupts float64 `perflib:"Interrupts/sec"`
|
||||||
|
PercentC2Time float64 `perflib:"% C1 Time"`
|
||||||
|
PercentC3Time float64 `perflib:"% C2 Time"`
|
||||||
|
PercentC1Time float64 `perflib:"% C3 Time"`
|
||||||
|
PercentDPCTime float64 `perflib:"% DPC Time"`
|
||||||
|
PercentIdleTime float64 `perflib:"% Idle Time"`
|
||||||
|
PercentInterruptTime float64 `perflib:"% Interrupt Time"`
|
||||||
|
PercentPrivilegedTime float64 `perflib:"% Privileged Time"`
|
||||||
|
PercentProcessorTime float64 `perflib:"% Processor Time"`
|
||||||
|
PercentUserTime float64 `perflib:"% User Time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cpuCollectorBasic) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
|
data := make([]perflibProcessor, 0)
|
||||||
|
err := unmarshalObject(ctx.perfObjects["Processor"], &data)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win32_PerfRawData_PerfOS_Processor docs:
|
for _, cpu := range data {
|
||||||
// - https://msdn.microsoft.com/en-us/library/aa394317(v=vs.90).aspx
|
if strings.Contains(strings.ToLower(cpu.Name), "_total") {
|
||||||
type Win32_PerfRawData_PerfOS_Processor struct {
|
|
||||||
Name string
|
|
||||||
C1TransitionsPersec uint64
|
|
||||||
C2TransitionsPersec uint64
|
|
||||||
C3TransitionsPersec uint64
|
|
||||||
DPCRate uint32
|
|
||||||
DPCsQueuedPersec uint32
|
|
||||||
InterruptsPersec uint32
|
|
||||||
PercentC1Time uint64
|
|
||||||
PercentC2Time uint64
|
|
||||||
PercentC3Time uint64
|
|
||||||
PercentDPCTime uint64
|
|
||||||
PercentIdleTime uint64
|
|
||||||
PercentInterruptTime uint64
|
|
||||||
PercentPrivilegedTime uint64
|
|
||||||
PercentProcessorTime uint64
|
|
||||||
PercentUserTime uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTE: This is an alternative class, but it is not as widely available. Decide which to use
|
|
||||||
type Win32_PerfRawData_Counters_ProcessorInformation struct {
|
|
||||||
Name string
|
|
||||||
AverageIdleTime uint64
|
|
||||||
C1TransitionsPersec uint64
|
|
||||||
C2TransitionsPersec uint64
|
|
||||||
C3TransitionsPersec uint64
|
|
||||||
ClockInterruptsPersec uint64
|
|
||||||
DPCRate uint64
|
|
||||||
DPCsQueuedPersec uint64
|
|
||||||
IdleBreakEventsPersec uint64
|
|
||||||
InterruptsPersec uint64
|
|
||||||
ParkingStatus uint64
|
|
||||||
PercentC1Time uint64
|
|
||||||
PercentC2Time uint64
|
|
||||||
PercentC3Time uint64
|
|
||||||
PercentDPCTime uint64
|
|
||||||
PercentIdleTime uint64
|
|
||||||
PercentInterruptTime uint64
|
|
||||||
PercentofMaximumFrequency uint64
|
|
||||||
PercentPerformanceLimit uint64
|
|
||||||
PercentPriorityTime uint64
|
|
||||||
PercentPrivilegedTime uint64
|
|
||||||
PercentPrivilegedUtility uint64
|
|
||||||
PercentProcessorPerformance uint64
|
|
||||||
PercentProcessorTime uint64
|
|
||||||
PercentProcessorUtility uint64
|
|
||||||
PercentUserTime uint64
|
|
||||||
PerformanceLimitFlags uint64
|
|
||||||
ProcessorFrequency uint64
|
|
||||||
ProcessorStateFlags uint64
|
|
||||||
}*/
|
|
||||||
|
|
||||||
func (c *CPUCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
|
|
||||||
var dst []Win32_PerfRawData_PerfOS_Processor
|
|
||||||
q := queryAll(&dst)
|
|
||||||
if err := wmi.Query(q, &dst); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, data := range dst {
|
|
||||||
if strings.Contains(data.Name, "_Total") {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
core := cpu.Name
|
||||||
core := data.Name
|
|
||||||
|
|
||||||
// These are only available from Win32_PerfRawData_Counters_ProcessorInformation, which is only available from Win2008R2+
|
|
||||||
/*ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.ProcessorFrequency,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
float64(data.ProcessorFrequency),
|
|
||||||
socket, core,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.MaximumFrequency,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
float64(data.PercentofMaximumFrequency)/100*float64(data.ProcessorFrequency),
|
|
||||||
socket, core,
|
|
||||||
)*/
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.CStateSecondsTotal,
|
c.CStateSecondsTotal,
|
||||||
prometheus.GaugeValue,
|
prometheus.CounterValue,
|
||||||
float64(data.PercentC1Time)*ticksToSecondsScaleFactor,
|
cpu.PercentC1Time,
|
||||||
core, "c1",
|
core, "c1",
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.CStateSecondsTotal,
|
c.CStateSecondsTotal,
|
||||||
prometheus.GaugeValue,
|
prometheus.CounterValue,
|
||||||
float64(data.PercentC2Time)*ticksToSecondsScaleFactor,
|
cpu.PercentC2Time,
|
||||||
core, "c2",
|
core, "c2",
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.CStateSecondsTotal,
|
c.CStateSecondsTotal,
|
||||||
prometheus.GaugeValue,
|
prometheus.CounterValue,
|
||||||
float64(data.PercentC3Time)*ticksToSecondsScaleFactor,
|
cpu.PercentC3Time,
|
||||||
core, "c3",
|
core, "c3",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.TimeTotal,
|
c.TimeTotal,
|
||||||
prometheus.GaugeValue,
|
prometheus.CounterValue,
|
||||||
float64(data.PercentIdleTime)*ticksToSecondsScaleFactor,
|
cpu.PercentIdleTime,
|
||||||
core, "idle",
|
core, "idle",
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.TimeTotal,
|
c.TimeTotal,
|
||||||
prometheus.GaugeValue,
|
prometheus.CounterValue,
|
||||||
float64(data.PercentInterruptTime)*ticksToSecondsScaleFactor,
|
cpu.PercentInterruptTime,
|
||||||
core, "interrupt",
|
core, "interrupt",
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.TimeTotal,
|
c.TimeTotal,
|
||||||
prometheus.GaugeValue,
|
prometheus.CounterValue,
|
||||||
float64(data.PercentDPCTime)*ticksToSecondsScaleFactor,
|
cpu.PercentDPCTime,
|
||||||
core, "dpc",
|
core, "dpc",
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.TimeTotal,
|
c.TimeTotal,
|
||||||
prometheus.GaugeValue,
|
prometheus.CounterValue,
|
||||||
float64(data.PercentPrivilegedTime)*ticksToSecondsScaleFactor,
|
cpu.PercentPrivilegedTime,
|
||||||
core, "privileged",
|
core, "privileged",
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.TimeTotal,
|
c.TimeTotal,
|
||||||
prometheus.GaugeValue,
|
prometheus.CounterValue,
|
||||||
float64(data.PercentUserTime)*ticksToSecondsScaleFactor,
|
cpu.PercentUserTime,
|
||||||
core, "user",
|
core, "user",
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.InterruptsTotal,
|
c.InterruptsTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
float64(data.InterruptsPersec),
|
cpu.Interrupts,
|
||||||
core,
|
core,
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.DPCsTotal,
|
c.DPCsTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
float64(data.DPCsQueuedPersec),
|
cpu.DPCsQueued,
|
||||||
core,
|
core,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type perflibProcessorInformation struct {
|
||||||
|
Name string
|
||||||
|
C1TimeSeconds float64 `perflib:"% C1 Time"`
|
||||||
|
C2TimeSeconds float64 `perflib:"% C2 Time"`
|
||||||
|
C3TimeSeconds float64 `perflib:"% C3 Time"`
|
||||||
|
C1TransitionsTotal float64 `perflib:"C1 Transitions/sec"`
|
||||||
|
C2TransitionsTotal float64 `perflib:"C2 Transitions/sec"`
|
||||||
|
C3TransitionsTotal float64 `perflib:"C3 Transitions/sec"`
|
||||||
|
ClockInterruptsTotal float64 `perflib:"Clock Interrupts/sec"`
|
||||||
|
DPCsQueuedTotal float64 `perflib:"DPCs Queued/sec"`
|
||||||
|
DPCTimeSeconds float64 `perflib:"% DPC Time"`
|
||||||
|
IdleBreakEventsTotal float64 `perflib:"Idle Break Events/sec"`
|
||||||
|
IdleTimeSeconds float64 `perflib:"% Idle Time"`
|
||||||
|
InterruptsTotal float64 `perflib:"Interrupts/sec"`
|
||||||
|
InterruptTimeSeconds float64 `perflib:"% Interrupt Time"`
|
||||||
|
ParkingStatus float64 `perflib:"Parking Status"`
|
||||||
|
PerformanceLimitPercent float64 `perflib:"% Performance Limit"`
|
||||||
|
PriorityTimeSeconds float64 `perflib:"% Priority Time"`
|
||||||
|
PrivilegedTimeSeconds float64 `perflib:"% Privileged Time"`
|
||||||
|
PrivilegedUtilitySeconds float64 `perflib:"% Privileged Utility"`
|
||||||
|
ProcessorFrequencyMHz float64 `perflib:"Processor Frequency"`
|
||||||
|
ProcessorPerformance float64 `perflib:"% Processor Performance"`
|
||||||
|
ProcessorTimeSeconds float64 `perflib:"% Processor Time"`
|
||||||
|
ProcessorUtilityRate float64 `perflib:"% Processor Utility"`
|
||||||
|
UserTimeSeconds float64 `perflib:"% User Time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cpuCollectorFull) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
|
data := make([]perflibProcessorInformation, 0)
|
||||||
|
err := unmarshalObject(ctx.perfObjects["Processor Information"], &data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cpu := range data {
|
||||||
|
if strings.Contains(strings.ToLower(cpu.Name), "_total") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
core := cpu.Name
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.CStateSecondsTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.C1TimeSeconds,
|
||||||
|
core, "c1",
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.CStateSecondsTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.C2TimeSeconds,
|
||||||
|
core, "c2",
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.CStateSecondsTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.C3TimeSeconds,
|
||||||
|
core, "c3",
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.TimeTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.IdleTimeSeconds,
|
||||||
|
core, "idle",
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.TimeTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.InterruptTimeSeconds,
|
||||||
|
core, "interrupt",
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.TimeTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.DPCTimeSeconds,
|
||||||
|
core, "dpc",
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.TimeTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.PrivilegedTimeSeconds,
|
||||||
|
core, "privileged",
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.TimeTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.UserTimeSeconds,
|
||||||
|
core, "user",
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.InterruptsTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.InterruptsTotal,
|
||||||
|
core,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.DPCsTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.DPCsQueuedTotal,
|
||||||
|
core,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ClockInterruptsTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.ClockInterruptsTotal,
|
||||||
|
core,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.IdleBreakEventsTotal,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
cpu.IdleBreakEventsTotal,
|
||||||
|
core,
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ParkingStatus,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
cpu.ParkingStatus,
|
||||||
|
core,
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ProcessorFrequencyMHz,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
cpu.ProcessorFrequencyMHz,
|
||||||
|
core,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ProcessorPerformance,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
cpu.ProcessorPerformance,
|
||||||
|
core,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func NewCSCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *CSCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *CSCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting cs metrics:", desc, err)
|
log.Error("failed collecting cs metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ func NewDNSCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *DNSCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *DNSCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting dns metrics:", desc, err)
|
log.Error("failed collecting dns metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -597,7 +597,7 @@ func NewHyperVCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *HyperVCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *HyperVCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collectVmHealth(ch); err != nil {
|
if desc, err := c.collectVmHealth(ch); err != nil {
|
||||||
log.Error("failed collecting hyperV health status metrics:", desc, err)
|
log.Error("failed collecting hyperV health status metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -818,7 +818,7 @@ func NewIISCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *IISCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *IISCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting iis metrics:", desc, err)
|
log.Error("failed collecting iis metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ func NewLogicalDiskCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *LogicalDiskCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *LogicalDiskCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting logical_disk metrics:", desc, err)
|
log.Error("failed collecting logical_disk metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ func NewMemoryCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *MemoryCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *MemoryCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting memory metrics:", desc, err)
|
log.Error("failed collecting memory metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ type Win32_PerfRawData_MSMQ_MSMQQueueCollector struct {
|
|||||||
func NewMSMQCollector() (Collector, error) {
|
func NewMSMQCollector() (Collector, error) {
|
||||||
const subsystem = "msmq"
|
const subsystem = "msmq"
|
||||||
|
|
||||||
if *msmqWhereClause != "" {
|
if *msmqWhereClause == "" {
|
||||||
log.Warn("No where-clause specified for msmq collector. This will generate a very large number of metrics!")
|
log.Warn("No where-clause specified for msmq collector. This will generate a very large number of metrics!")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ func NewMSMQCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Win32_PerfRawData_MSMQ_MSMQQueueCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *Win32_PerfRawData_MSMQ_MSMQQueueCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting msmq metrics:", desc, err)
|
log.Error("failed collecting msmq metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1687,7 +1687,7 @@ func (c *MSSQLCollector) execute(name string, fn mssqlCollectorFunc, ch chan<- p
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *MSSQLCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *MSSQLCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
|
|
||||||
enabled := mssqlExpandEnabledCollectors(*mssqlEnabledCollectors)
|
enabled := mssqlExpandEnabledCollectors(*mssqlEnabledCollectors)
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func NewNetworkCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *NetworkCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *NetworkCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting net metrics:", desc, err)
|
log.Error("failed collecting net metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func NewNETFramework_NETCLRExceptionsCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *NETFramework_NETCLRExceptionsCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *NETFramework_NETCLRExceptionsCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting win32_perfrawdata_netframework_netclrexceptions metrics:", desc, err)
|
log.Error("failed collecting win32_perfrawdata_netframework_netclrexceptions metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func NewNETFramework_NETCLRInteropCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *NETFramework_NETCLRInteropCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *NETFramework_NETCLRInteropCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting win32_perfrawdata_netframework_netclrinterop metrics:", desc, err)
|
log.Error("failed collecting win32_perfrawdata_netframework_netclrinterop metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func NewNETFramework_NETCLRJitCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *NETFramework_NETCLRJitCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *NETFramework_NETCLRJitCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting win32_perfrawdata_netframework_netclrjit metrics:", desc, err)
|
log.Error("failed collecting win32_perfrawdata_netframework_netclrjit metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ func NewNETFramework_NETCLRLoadingCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *NETFramework_NETCLRLoadingCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *NETFramework_NETCLRLoadingCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting win32_perfrawdata_netframework_netclrloading metrics:", desc, err)
|
log.Error("failed collecting win32_perfrawdata_netframework_netclrloading metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func NewNETFramework_NETCLRLocksAndThreadsCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *NETFramework_NETCLRLocksAndThreadsCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *NETFramework_NETCLRLocksAndThreadsCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting win32_perfrawdata_netframework_netclrlocksandthreads metrics:", desc, err)
|
log.Error("failed collecting win32_perfrawdata_netframework_netclrlocksandthreads metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ func NewNETFramework_NETCLRMemoryCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *NETFramework_NETCLRMemoryCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *NETFramework_NETCLRMemoryCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting win32_perfrawdata_netframework_netclrmemory metrics:", desc, err)
|
log.Error("failed collecting win32_perfrawdata_netframework_netclrmemory metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func NewNETFramework_NETCLRRemotingCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *NETFramework_NETCLRRemotingCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *NETFramework_NETCLRRemotingCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting win32_perfrawdata_netframework_netclrremoting metrics:", desc, err)
|
log.Error("failed collecting win32_perfrawdata_netframework_netclrremoting metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func NewNETFramework_NETCLRSecurityCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *NETFramework_NETCLRSecurityCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *NETFramework_NETCLRSecurityCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting win32_perfrawdata_netframework_netclrsecurity metrics:", desc, err)
|
log.Error("failed collecting win32_perfrawdata_netframework_netclrsecurity metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ func NewOSCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *OSCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *OSCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting os metrics:", desc, err)
|
log.Error("failed collecting os metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
89
collector/perflib.go
Normal file
89
collector/perflib.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
perflibCollector "github.com/leoluk/perflib_exporter/collector"
|
||||||
|
"github.com/leoluk/perflib_exporter/perflib"
|
||||||
|
"github.com/prometheus/common/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getPerflibSnapshot() (map[string]*perflib.PerfObject, error) {
|
||||||
|
objects, err := perflib.QueryPerformanceData("Global")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
indexed := make(map[string]*perflib.PerfObject)
|
||||||
|
for _, obj := range objects {
|
||||||
|
indexed[obj.Name] = obj
|
||||||
|
}
|
||||||
|
return indexed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalObject(obj *perflib.PerfObject, vs interface{}) error {
|
||||||
|
if obj == nil {
|
||||||
|
return fmt.Errorf("counter not found")
|
||||||
|
}
|
||||||
|
rv := reflect.ValueOf(vs)
|
||||||
|
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
||||||
|
return fmt.Errorf("%v is nil or not a pointer to slice", reflect.TypeOf(vs))
|
||||||
|
}
|
||||||
|
ev := rv.Elem()
|
||||||
|
if ev.Kind() != reflect.Slice {
|
||||||
|
return fmt.Errorf("%v is not slice", reflect.TypeOf(vs))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure sufficient length
|
||||||
|
if ev.Cap() < len(obj.Instances) {
|
||||||
|
nvs := reflect.MakeSlice(ev.Type(), len(obj.Instances), len(obj.Instances))
|
||||||
|
ev.Set(nvs)
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx, instance := range obj.Instances {
|
||||||
|
target := ev.Index(idx)
|
||||||
|
rt := target.Type()
|
||||||
|
|
||||||
|
counters := make(map[string]*perflib.PerfCounter, len(instance.Counters))
|
||||||
|
for _, ctr := range instance.Counters {
|
||||||
|
if ctr.Def.IsBaseValue && !ctr.Def.IsNanosecondCounter {
|
||||||
|
counters[ctr.Def.Name+"_Base"] = ctr
|
||||||
|
} else {
|
||||||
|
counters[ctr.Def.Name] = ctr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < target.NumField(); i++ {
|
||||||
|
f := rt.Field(i)
|
||||||
|
tag := f.Tag.Get("perflib")
|
||||||
|
if tag == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ctr, found := counters[tag]
|
||||||
|
if !found {
|
||||||
|
log.Debugf("missing counter %q, has %v", tag, counters)
|
||||||
|
return fmt.Errorf("could not find counter %q on instance", tag)
|
||||||
|
}
|
||||||
|
if !target.Field(i).CanSet() {
|
||||||
|
return fmt.Errorf("tagged field %v cannot be written to", f)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ctr.Def.CounterType {
|
||||||
|
case perflibCollector.PERF_ELAPSED_TIME:
|
||||||
|
target.Field(i).SetFloat(float64(ctr.Value-windowsEpoch) / float64(obj.Frequency))
|
||||||
|
case perflibCollector.PERF_100NSEC_TIMER, perflibCollector.PERF_PRECISION_100NS_TIMER:
|
||||||
|
target.Field(i).SetFloat(float64(ctr.Value) * ticksToSecondsScaleFactor)
|
||||||
|
default:
|
||||||
|
target.Field(i).SetFloat(float64(ctr.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if instance.Name != "" && target.FieldByName("Name").CanSet() {
|
||||||
|
target.FieldByName("Name").SetString(instance.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -135,7 +135,7 @@ func NewProcessCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *ProcessCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *ProcessCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting process metrics:", desc, err)
|
log.Error("failed collecting process metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func NewserviceCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *serviceCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *serviceCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting service metrics:", desc, err)
|
log.Error("failed collecting service metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func NewSystemCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *SystemCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *SystemCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting system metrics:", desc, err)
|
log.Error("failed collecting system metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ func NewTCPCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *TCPCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *TCPCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collect(ch); err != nil {
|
if desc, err := c.collect(ch); err != nil {
|
||||||
log.Error("failed collecting tcp metrics:", desc, err)
|
log.Error("failed collecting tcp metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ func (cr carriageReturnFilteringReader) Read(p []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update implements the Collector interface.
|
// Update implements the Collector interface.
|
||||||
func (c *textFileCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *textFileCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
error := 0.0
|
error := 0.0
|
||||||
mtimes := map[string]time.Time{}
|
mtimes := map[string]time.Time{}
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ func NewVmwareCollector() (Collector, error) {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *VmwareCollector) Collect(ch chan<- prometheus.Metric) error {
|
func (c *VmwareCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error {
|
||||||
if desc, err := c.collectMem(ch); err != nil {
|
if desc, err := c.collectMem(ch); err != nil {
|
||||||
log.Error("failed collecting vmware memory metrics:", desc, err)
|
log.Error("failed collecting vmware memory metrics:", desc, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -4,27 +4,9 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"github.com/prometheus/common/log"
|
"github.com/prometheus/common/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ...
|
|
||||||
const (
|
|
||||||
Namespace = "wmi"
|
|
||||||
|
|
||||||
// Conversion factors
|
|
||||||
ticksToSecondsScaleFactor = 1 / 1e7
|
|
||||||
)
|
|
||||||
|
|
||||||
// Factories ...
|
|
||||||
var Factories = make(map[string]func() (Collector, error))
|
|
||||||
|
|
||||||
// Collector is the interface a collector has to implement.
|
|
||||||
type Collector interface {
|
|
||||||
// Get new metrics and expose them via prometheus registry.
|
|
||||||
Collect(ch chan<- prometheus.Metric) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func className(src interface{}) string {
|
func className(src interface{}) string {
|
||||||
s := reflect.Indirect(reflect.ValueOf(src))
|
s := reflect.Indirect(reflect.ValueOf(src))
|
||||||
t := s.Type()
|
t := s.Type()
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
The container collector exposes metrics about containers running on system
|
The container collector exposes metrics about containers running on system
|
||||||
|
|
||||||
|
|||
|
||||||
|
-|-
|
||||||
Metric name prefix | `container`
|
Metric name prefix | `container`
|
||||||
Enabled by default? | No
|
Enabled by default? | No
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ The cpu collector exposes metrics about CPU usage
|
|||||||
|||
|
|||
|
||||||
-|-
|
-|-
|
||||||
Metric name prefix | `cpu`
|
Metric name prefix | `cpu`
|
||||||
Classes | [`Win32_PerfRawData_PerfOS_Processor`](https://msdn.microsoft.com/en-us/library/aa394317(v=vs.90).aspx)
|
Data source | Perflib
|
||||||
|
Counters | `ProcessorInformation` (Windows Server 2008R2 and later) `Processor` (older versions)
|
||||||
Enabled by default? | Yes
|
Enabled by default? | Yes
|
||||||
|
|
||||||
## Flags
|
## Flags
|
||||||
@@ -13,6 +14,7 @@ Enabled by default? | Yes
|
|||||||
None
|
None
|
||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
These metrics are available on all versions of Windows:
|
||||||
|
|
||||||
Name | Description | Type | Labels
|
Name | Description | Type | Labels
|
||||||
-----|-------------|------|-------
|
-----|-------------|------|-------
|
||||||
@@ -21,6 +23,16 @@ Name | Description | Type | Labels
|
|||||||
`wmi_cpu_interrupts_total` | Total number of received and serviced hardware interrupts | counter | `core`
|
`wmi_cpu_interrupts_total` | Total number of received and serviced hardware interrupts | counter | `core`
|
||||||
`wmi_cpu_dpcs_total` | Total number of received and serviced deferred procedure calls (DPCs) | counter | `core`
|
`wmi_cpu_dpcs_total` | Total number of received and serviced deferred procedure calls (DPCs) | counter | `core`
|
||||||
|
|
||||||
|
These metrics are only exposed on Windows Server 2008R2 and later:
|
||||||
|
|
||||||
|
Name | Description | Type | Labels
|
||||||
|
-----|-------------|------|-------
|
||||||
|
`wmi_cpu_clock_interrupts_total` | Total number of received and serviced clock tick interrupts | `core`
|
||||||
|
`wmi_cpu_idle_break_events_total` | Total number of time processor was woken from idle | `core`
|
||||||
|
`wmi_cpu_parking_status` | Parking Status represents whether a processor is parked or not | `gauge`
|
||||||
|
`wmi_cpu_core_frequency_mhz` | Core frequency in megahertz | `gauge`
|
||||||
|
`wmi_cpu_processor_performance` | Processor Performance is the average performance of the processor while it is executing instructions, as a percentage of the nominal performance of the processor. On some processors, Processor Performance may exceed 100% | `gauge`
|
||||||
|
|
||||||
### Example metric
|
### Example metric
|
||||||
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
The memory collector exposes metrics about system memory usage
|
The memory collector exposes metrics about system memory usage
|
||||||
|
|
||||||
|
|||
|
||||||
|
-|-
|
||||||
Metric name prefix | `memory`
|
Metric name prefix | `memory`
|
||||||
Classes | `Win32_PerfRawData_PerfOS_Memory`
|
Classes | `Win32_PerfRawData_PerfOS_Memory`
|
||||||
Enabled by default? | Yes
|
Enabled by default? | Yes
|
||||||
|
|||||||
97
exporter.go
97
exporter.go
@@ -23,7 +23,8 @@ import (
|
|||||||
|
|
||||||
// WmiCollector implements the prometheus.Collector interface.
|
// WmiCollector implements the prometheus.Collector interface.
|
||||||
type WmiCollector struct {
|
type WmiCollector struct {
|
||||||
collectors map[string]collector.Collector
|
maxScrapeDuration time.Duration
|
||||||
|
collectors map[string]collector.Collector
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -45,6 +46,12 @@ var (
|
|||||||
[]string{"collector"},
|
[]string{"collector"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
scrapeTimeoutDesc = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(collector.Namespace, "exporter", "collector_timeout"),
|
||||||
|
"wmi_exporter: Whether the collector timed out.",
|
||||||
|
[]string{"collector"},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
// This can be removed when client_golang exposes this on Windows
|
// This can be removed when client_golang exposes this on Windows
|
||||||
// (See https://github.com/prometheus/client_golang/issues/376)
|
// (See https://github.com/prometheus/client_golang/issues/376)
|
||||||
@@ -65,15 +72,48 @@ func (coll WmiCollector) Describe(ch chan<- *prometheus.Desc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the collected metrics from each of the collectors to
|
// Collect sends the collected metrics from each of the collectors to
|
||||||
// prometheus. Collect could be called several times concurrently
|
// prometheus.
|
||||||
// and thus its run is protected by a single mutex.
|
|
||||||
func (coll WmiCollector) Collect(ch chan<- prometheus.Metric) {
|
func (coll WmiCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
scrapeContext, err := collector.PrepareScrapeContext()
|
||||||
|
if err != nil {
|
||||||
|
ch <- prometheus.NewInvalidMetric(scrapeSuccessDesc, fmt.Errorf("failed to prepare scrape: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remainingCollectors := make(map[string]bool)
|
||||||
|
for name := range coll.collectors {
|
||||||
|
remainingCollectors[name] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
metricsBuffer := make(chan prometheus.Metric)
|
||||||
|
allDone := make(chan struct{})
|
||||||
|
stopped := false
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case m := <-metricsBuffer:
|
||||||
|
if !stopped {
|
||||||
|
ch <- m
|
||||||
|
}
|
||||||
|
case <-allDone:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(coll.collectors))
|
wg.Add(len(coll.collectors))
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(allDone)
|
||||||
|
close(metricsBuffer)
|
||||||
|
}()
|
||||||
|
|
||||||
for name, c := range coll.collectors {
|
for name, c := range coll.collectors {
|
||||||
go func(name string, c collector.Collector) {
|
go func(name string, c collector.Collector) {
|
||||||
execute(name, c, ch)
|
execute(name, c, scrapeContext, metricsBuffer)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
|
delete(remainingCollectors, name)
|
||||||
}(name, c)
|
}(name, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +122,33 @@ func (coll WmiCollector) Collect(ch chan<- prometheus.Metric) {
|
|||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
startTime,
|
startTime,
|
||||||
)
|
)
|
||||||
wg.Wait()
|
|
||||||
|
select {
|
||||||
|
case <-allDone:
|
||||||
|
stopped = true
|
||||||
|
return
|
||||||
|
case <-time.After(coll.maxScrapeDuration):
|
||||||
|
stopped = true
|
||||||
|
remainingCollectorNames := make([]string, 0, len(remainingCollectors))
|
||||||
|
for rc := range remainingCollectors {
|
||||||
|
remainingCollectorNames = append(remainingCollectorNames, rc)
|
||||||
|
}
|
||||||
|
log.Warn("Collection timed out, still waiting for ", remainingCollectorNames)
|
||||||
|
for name := range remainingCollectors {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
scrapeSuccessDesc,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
0.0,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
scrapeTimeoutDesc,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
1.0,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterAvailableCollectors(collectors string) string {
|
func filterAvailableCollectors(collectors string) string {
|
||||||
@@ -96,9 +162,9 @@ func filterAvailableCollectors(collectors string) string {
|
|||||||
return strings.Join(availableCollectors, ",")
|
return strings.Join(availableCollectors, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
func execute(name string, c collector.Collector, ch chan<- prometheus.Metric) {
|
func execute(name string, c collector.Collector, ctx *collector.ScrapeContext, ch chan<- prometheus.Metric) {
|
||||||
begin := time.Now()
|
begin := time.Now()
|
||||||
err := c.Collect(ch)
|
err := c.Collect(ctx, ch)
|
||||||
duration := time.Since(begin)
|
duration := time.Since(begin)
|
||||||
var success float64
|
var success float64
|
||||||
|
|
||||||
@@ -121,6 +187,12 @@ func execute(name string, c collector.Collector, ch chan<- prometheus.Metric) {
|
|||||||
success,
|
success,
|
||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
scrapeTimeoutDesc,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
0.0,
|
||||||
|
name,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func expandEnabledCollectors(enabled string) []string {
|
func expandEnabledCollectors(enabled string) []string {
|
||||||
@@ -192,6 +264,10 @@ func main() {
|
|||||||
"collectors.print",
|
"collectors.print",
|
||||||
"If true, print available collectors and exit.",
|
"If true, print available collectors and exit.",
|
||||||
).Bool()
|
).Bool()
|
||||||
|
maxScrapeDuration = kingpin.Flag(
|
||||||
|
"scrape.max-duration",
|
||||||
|
"Time after which collectors are aborted during a scrape",
|
||||||
|
).Default("30s").Duration()
|
||||||
)
|
)
|
||||||
|
|
||||||
log.AddFlags(kingpin.CommandLine)
|
log.AddFlags(kingpin.CommandLine)
|
||||||
@@ -236,8 +312,11 @@ func main() {
|
|||||||
|
|
||||||
log.Infof("Enabled collectors: %v", strings.Join(keys(collectors), ", "))
|
log.Infof("Enabled collectors: %v", strings.Join(keys(collectors), ", "))
|
||||||
|
|
||||||
nodeCollector := WmiCollector{collectors: collectors}
|
exporter := WmiCollector{
|
||||||
prometheus.MustRegister(nodeCollector)
|
collectors: collectors,
|
||||||
|
maxScrapeDuration: *maxScrapeDuration,
|
||||||
|
}
|
||||||
|
prometheus.MustRegister(exporter)
|
||||||
|
|
||||||
http.Handle(*metricsPath, promhttp.Handler())
|
http.Handle(*metricsPath, promhttp.Handler())
|
||||||
http.HandleFunc("/health", healthCheck)
|
http.HandleFunc("/health", healthCheck)
|
||||||
|
|||||||
21
vendor/github.com/leoluk/perflib_exporter/LICENSE
generated
vendored
Normal file
21
vendor/github.com/leoluk/perflib_exporter/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2018 Leopold Schabel / The perflib_exporter authors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
184
vendor/github.com/leoluk/perflib_exporter/collector/collector.go
generated
vendored
Normal file
184
vendor/github.com/leoluk/perflib_exporter/collector/collector.go
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/leoluk/perflib_exporter/perflib"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/common/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ...
|
||||||
|
const (
|
||||||
|
Namespace = "perflib"
|
||||||
|
|
||||||
|
// Conversion factors
|
||||||
|
hundredNsToSecondsScaleFactor = 1 / 1e7
|
||||||
|
)
|
||||||
|
|
||||||
|
// Collector is the interface a collector has to implement.
|
||||||
|
type Collector interface {
|
||||||
|
// Get new metrics and expose them via prometheus registry.
|
||||||
|
Collect(ch chan<- prometheus.Metric) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CounterKey struct {
|
||||||
|
ObjectIndex uint
|
||||||
|
CounterIndex uint
|
||||||
|
CounterType uint32 // This is a bit mask
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCounterKey(object *perflib.PerfObject, def *perflib.PerfCounterDef) CounterKey {
|
||||||
|
return CounterKey{object.NameIndex, def.NameIndex, def.CounterType}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PerflibCollector struct {
|
||||||
|
perflibQuery string
|
||||||
|
perflibDescs map[CounterKey]*prometheus.Desc
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPerflibCollector(query string) (c PerflibCollector) {
|
||||||
|
c.perflibQuery = query
|
||||||
|
|
||||||
|
objects, err := perflib.QueryPerformanceData(c.perflibQuery)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Number of objects: %d", len(objects))
|
||||||
|
|
||||||
|
c.perflibDescs = make(map[CounterKey]*prometheus.Desc)
|
||||||
|
|
||||||
|
for _, object := range objects {
|
||||||
|
for _, def := range object.CounterDefs {
|
||||||
|
desc := descFromCounterDef(*object, *def)
|
||||||
|
|
||||||
|
key := NewCounterKey(object, def)
|
||||||
|
c.perflibDescs[key] = desc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c PerflibCollector) Collect(ch chan<- prometheus.Metric) (err error) {
|
||||||
|
// TODO QueryPerformanceData timing metric
|
||||||
|
objects, err := perflib.QueryPerformanceData(c.perflibQuery)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// TODO - we shouldn't panic if a single call fails
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Number of objects: %d", len(objects))
|
||||||
|
|
||||||
|
for _, object := range objects {
|
||||||
|
n := object.NameIndex
|
||||||
|
|
||||||
|
for _, instance := range object.Instances {
|
||||||
|
name := instance.Name
|
||||||
|
|
||||||
|
// _Total metrics do not fit into the Prometheus model - we try to merge similar
|
||||||
|
// metrics and give them labels, so you'd sum() them instead. Having a _Total label
|
||||||
|
// would make
|
||||||
|
if strings.HasSuffix(name, "_Total") || strings.HasPrefix(name, "Total") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, counter := range instance.Counters {
|
||||||
|
if IsDefPromotedLabel(n, counter.Def.NameIndex) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if counter == nil {
|
||||||
|
log.Debugf("nil counter for %s -> %s", object.Name, instance.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if counter.Def.NameIndex == 0 {
|
||||||
|
log.Debugf("null counter index for %s -> %s", object.Name, instance.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if counter.Def.Name == "" {
|
||||||
|
log.Debugf("no counter name for %s -> %s", object.Name, instance.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if counter.Def.Name == "No name" {
|
||||||
|
log.Debugf("no name counter %s -> %s -> %s", object.Name, instance.Name, counter.Def.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
key := NewCounterKey(object, counter.Def)
|
||||||
|
|
||||||
|
desc, ok := c.perflibDescs[key]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
log.Debugf("missing metric description for counter %s -> %s -> %s", object.Name, instance.Name, counter.Def.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
labels := []string{name}
|
||||||
|
|
||||||
|
if len(object.Instances) == 1 {
|
||||||
|
labels = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if HasPromotedLabels(n) {
|
||||||
|
labels = append(labels, PromotedLabelValuesForInstance(n, instance)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - Label merging needs to be fixed for [230] Process
|
||||||
|
//if HasMergedLabels(n) {
|
||||||
|
// _, value := MergedMetricForInstance(n, counter.Def.NameIndex)
|
||||||
|
//
|
||||||
|
// // Null string in definition means we should skip this metric (it's probably a sum)
|
||||||
|
// if value == "" {
|
||||||
|
// log.Debugf("Skipping %d -> %s (empty merge label)", n, counter.Def.NameIndex)
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// labels = append(labels, value)
|
||||||
|
//}
|
||||||
|
|
||||||
|
valueType, err := GetPrometheusValueType(counter.Def.CounterType)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// TODO - Is this too verbose? There will always be counter types we don't support
|
||||||
|
log.Debug(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
value := float64(counter.Value)
|
||||||
|
|
||||||
|
if counter.Def.IsNanosecondCounter {
|
||||||
|
value = value * hundredNsToSecondsScaleFactor
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsElapsedTime(counter.Def.CounterType) {
|
||||||
|
// convert from Windows timestamp (1 jan 1601) to unix timestamp (1 jan 1970)
|
||||||
|
value = float64(counter.Value-116444736000000000) / float64(object.Frequency)
|
||||||
|
}
|
||||||
|
|
||||||
|
metric := prometheus.MustNewConstMetric(
|
||||||
|
desc,
|
||||||
|
valueType,
|
||||||
|
value,
|
||||||
|
labels...,
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- metric
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*ch <- prometheus.MustNewConstMetric(
|
||||||
|
prometheus.NewDesc(),
|
||||||
|
prometheus.CounterValue,
|
||||||
|
float64(0),
|
||||||
|
"ds_client",
|
||||||
|
)*/
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
90
vendor/github.com/leoluk/perflib_exporter/collector/mangle.go
generated
vendored
Normal file
90
vendor/github.com/leoluk/perflib_exporter/collector/mangle.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/leoluk/perflib_exporter/perflib"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func manglePerflibName(s string) string {
|
||||||
|
s = strings.ToLower(s)
|
||||||
|
s = strings.Replace(s, " ", "_", -1)
|
||||||
|
s = strings.Replace(s, ".", "", -1)
|
||||||
|
s = strings.Replace(s, "(", "", -1)
|
||||||
|
s = strings.Replace(s, ")", "", -1)
|
||||||
|
s = strings.Replace(s, "+", "", -1)
|
||||||
|
s = strings.Replace(s, "-", "", -1)
|
||||||
|
s = strings.Replace(s, ",", "", -1)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func manglePerflibCounterName(s string) string {
|
||||||
|
s = manglePerflibName(s)
|
||||||
|
|
||||||
|
s = strings.Replace(s, "total_", "", -1)
|
||||||
|
s = strings.Replace(s, "_total", "", -1)
|
||||||
|
s = strings.Replace(s, "/second", "", -1)
|
||||||
|
s = strings.Replace(s, "/sec", "", -1)
|
||||||
|
s = strings.Replace(s, "_%", "", -1)
|
||||||
|
s = strings.Replace(s, "%_", "", -1)
|
||||||
|
s = strings.Replace(s, "/", "_per_", -1)
|
||||||
|
s = strings.Replace(s, "&", "and", -1)
|
||||||
|
s = strings.Replace(s, "#_of_", "", -1)
|
||||||
|
s = strings.Replace(s, ":", "", -1)
|
||||||
|
s = strings.Replace(s, "__", "_", -1)
|
||||||
|
|
||||||
|
s = strings.Trim(s, " _")
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakePrometheusLabel(def *perflib.PerfCounterDef) (s string) {
|
||||||
|
s = manglePerflibCounterName(def.Name)
|
||||||
|
|
||||||
|
if len(s) > 0 {
|
||||||
|
if IsCounter(def.CounterType) {
|
||||||
|
s += "_total"
|
||||||
|
} else if IsBaseValue(def.CounterType) && !strings.HasSuffix(s, "_base") {
|
||||||
|
s += "_max"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func pdhNameFromCounterDef(obj perflib.PerfObject, def perflib.PerfCounterDef) string {
|
||||||
|
return fmt.Sprintf(`\%s(*)\%s`, obj.Name, def.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func descFromCounterDef(obj perflib.PerfObject, def perflib.PerfCounterDef) *prometheus.Desc {
|
||||||
|
subsystem := manglePerflibName(obj.Name)
|
||||||
|
counterName := MakePrometheusLabel(&def)
|
||||||
|
|
||||||
|
labels := []string{"name"}
|
||||||
|
|
||||||
|
if len(obj.Instances) == 1 {
|
||||||
|
labels = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if HasPromotedLabels(obj.NameIndex) {
|
||||||
|
labels = append(labels, PromotedLabelsForObject(obj.NameIndex)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - Label merging needs to be fixed for [230] Process
|
||||||
|
//if HasMergedLabels(obj.NameIndex) {
|
||||||
|
// s, labelsForObject := MergedLabelsForInstance(obj.NameIndex, def.NameIndex)
|
||||||
|
// counterName = s
|
||||||
|
// labels = append(labels, labelsForObject)
|
||||||
|
//}
|
||||||
|
|
||||||
|
return prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(Namespace, subsystem, counterName),
|
||||||
|
fmt.Sprintf("perflib metric: %s (see /dump for docs) [%d]",
|
||||||
|
pdhNameFromCounterDef(obj, def), def.NameIndex),
|
||||||
|
labels,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
91
vendor/github.com/leoluk/perflib_exporter/collector/mapper.go
generated
vendored
Normal file
91
vendor/github.com/leoluk/perflib_exporter/collector/mapper.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PERF_COUNTER_RAWCOUNT_HEX = 0x00000000
|
||||||
|
PERF_COUNTER_LARGE_RAWCOUNT_HEX = 0x00000100
|
||||||
|
PERF_COUNTER_TEXT = 0x00000b00
|
||||||
|
PERF_COUNTER_RAWCOUNT = 0x00010000
|
||||||
|
PERF_COUNTER_LARGE_RAWCOUNT = 0x00010100
|
||||||
|
PERF_DOUBLE_RAW = 0x00012000
|
||||||
|
PERF_COUNTER_DELTA = 0x00400400
|
||||||
|
PERF_COUNTER_LARGE_DELTA = 0x00400500
|
||||||
|
PERF_SAMPLE_COUNTER = 0x00410400
|
||||||
|
PERF_COUNTER_QUEUELEN_TYPE = 0x00450400
|
||||||
|
PERF_COUNTER_LARGE_QUEUELEN_TYPE = 0x00450500
|
||||||
|
PERF_COUNTER_100NS_QUEUELEN_TYPE = 0x00550500
|
||||||
|
PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE = 0x00650500
|
||||||
|
PERF_COUNTER_COUNTER = 0x10410400
|
||||||
|
PERF_COUNTER_BULK_COUNT = 0x10410500
|
||||||
|
PERF_RAW_FRACTION = 0x20020400
|
||||||
|
PERF_LARGE_RAW_FRACTION = 0x20020500
|
||||||
|
PERF_COUNTER_TIMER = 0x20410500
|
||||||
|
PERF_PRECISION_SYSTEM_TIMER = 0x20470500
|
||||||
|
PERF_100NSEC_TIMER = 0x20510500
|
||||||
|
PERF_PRECISION_100NS_TIMER = 0x20570500
|
||||||
|
PERF_OBJ_TIME_TIMER = 0x20610500
|
||||||
|
PERF_PRECISION_OBJECT_TIMER = 0x20670500
|
||||||
|
PERF_SAMPLE_FRACTION = 0x20c20400
|
||||||
|
PERF_COUNTER_TIMER_INV = 0x21410500
|
||||||
|
PERF_100NSEC_TIMER_INV = 0x21510500
|
||||||
|
PERF_COUNTER_MULTI_TIMER = 0x22410500
|
||||||
|
PERF_100NSEC_MULTI_TIMER = 0x22510500
|
||||||
|
PERF_COUNTER_MULTI_TIMER_INV = 0x23410500
|
||||||
|
PERF_100NSEC_MULTI_TIMER_INV = 0x23510500
|
||||||
|
PERF_AVERAGE_TIMER = 0x30020400
|
||||||
|
PERF_ELAPSED_TIME = 0x30240500
|
||||||
|
PERF_COUNTER_NODATA = 0x40000200
|
||||||
|
PERF_AVERAGE_BULK = 0x40020500
|
||||||
|
PERF_SAMPLE_BASE = 0x40030401
|
||||||
|
PERF_AVERAGE_BASE = 0x40030402
|
||||||
|
PERF_RAW_BASE = 0x40030403
|
||||||
|
PERF_PRECISION_TIMESTAMP = 0x40030500
|
||||||
|
PERF_LARGE_RAW_BASE = 0x40030503
|
||||||
|
PERF_COUNTER_MULTI_BASE = 0x42030500
|
||||||
|
PERF_COUNTER_HISTOGRAM_TYPE = 0x80000000
|
||||||
|
)
|
||||||
|
|
||||||
|
var supportedCounterTypes = map[uint32]prometheus.ValueType{
|
||||||
|
PERF_COUNTER_RAWCOUNT_HEX: prometheus.GaugeValue,
|
||||||
|
PERF_COUNTER_LARGE_RAWCOUNT_HEX: prometheus.GaugeValue,
|
||||||
|
PERF_COUNTER_RAWCOUNT: prometheus.GaugeValue,
|
||||||
|
PERF_COUNTER_LARGE_RAWCOUNT: prometheus.GaugeValue,
|
||||||
|
PERF_COUNTER_DELTA: prometheus.CounterValue,
|
||||||
|
PERF_COUNTER_COUNTER: prometheus.CounterValue,
|
||||||
|
PERF_COUNTER_BULK_COUNT: prometheus.CounterValue,
|
||||||
|
PERF_RAW_FRACTION: prometheus.GaugeValue,
|
||||||
|
PERF_LARGE_RAW_FRACTION: prometheus.GaugeValue,
|
||||||
|
PERF_100NSEC_TIMER: prometheus.CounterValue,
|
||||||
|
PERF_PRECISION_100NS_TIMER: prometheus.CounterValue,
|
||||||
|
PERF_SAMPLE_FRACTION: prometheus.GaugeValue,
|
||||||
|
PERF_100NSEC_TIMER_INV: prometheus.CounterValue,
|
||||||
|
PERF_ELAPSED_TIME: prometheus.GaugeValue,
|
||||||
|
PERF_SAMPLE_BASE: prometheus.GaugeValue,
|
||||||
|
PERF_RAW_BASE: prometheus.GaugeValue,
|
||||||
|
PERF_LARGE_RAW_BASE: prometheus.GaugeValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsCounter(counterType uint32) bool {
|
||||||
|
return supportedCounterTypes[counterType] == prometheus.CounterValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBaseValue(counterType uint32) bool {
|
||||||
|
return counterType == PERF_SAMPLE_BASE || counterType == PERF_RAW_BASE || counterType == PERF_LARGE_RAW_BASE
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsElapsedTime(counterType uint32) bool {
|
||||||
|
return counterType == PERF_ELAPSED_TIME
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPrometheusValueType(counterType uint32) (prometheus.ValueType, error) {
|
||||||
|
val, ok := supportedCounterTypes[counterType]
|
||||||
|
if !ok {
|
||||||
|
return 0, fmt.Errorf("counter type %#08x is not supported", counterType)
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
38
vendor/github.com/leoluk/perflib_exporter/collector/merge.go
generated
vendored
Normal file
38
vendor/github.com/leoluk/perflib_exporter/collector/merge.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package collector
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var mergedDefinitions = map[uint]map[string]map[uint]string{
|
||||||
|
230: {
|
||||||
|
"processor_time_total": {
|
||||||
|
0: "mode",
|
||||||
|
6: "", // Processor Time (drop)
|
||||||
|
142: "user", // User Time
|
||||||
|
144: "privileged", // Privileged Time
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if a given object has merge definitions
|
||||||
|
func HasMergedLabels(index uint) bool {
|
||||||
|
_, ok := mergedDefinitions[index]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a list of merged label names for an instance
|
||||||
|
func MergedLabelsForInstance(objIndex uint, def uint) (name string, labelName string) {
|
||||||
|
return MergedMetricForInstance(objIndex, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return merged metric name and label value for an instance
|
||||||
|
func MergedMetricForInstance(objIndex uint, def uint) (name string, label string) {
|
||||||
|
for k, v := range mergedDefinitions[objIndex] {
|
||||||
|
for n := range v {
|
||||||
|
if def == n {
|
||||||
|
return k, v[n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("No merge definition for obj %d, inst %d", objIndex, def))
|
||||||
|
}
|
||||||
56
vendor/github.com/leoluk/perflib_exporter/collector/promote.go
generated
vendored
Normal file
56
vendor/github.com/leoluk/perflib_exporter/collector/promote.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/leoluk/perflib_exporter/perflib"
|
||||||
|
)
|
||||||
|
|
||||||
|
var labelPromotionLabels = map[uint][]string{
|
||||||
|
230: {
|
||||||
|
"process_id",
|
||||||
|
"creating_process_id",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var labelPromotionValues = map[uint][]uint{
|
||||||
|
230: {
|
||||||
|
784, // process_id
|
||||||
|
1410, // creating_process_id
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a list of promoted labels for an object
|
||||||
|
func PromotedLabelsForObject(index uint) []string {
|
||||||
|
return labelPromotionLabels[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a list of label values for a given object and instance
|
||||||
|
func PromotedLabelValuesForInstance(index uint, instance *perflib.PerfInstance) []string {
|
||||||
|
values := make([]string, len(labelPromotionValues[index]))
|
||||||
|
|
||||||
|
for _, c := range instance.Counters {
|
||||||
|
for i, v := range labelPromotionValues[index] {
|
||||||
|
if c.Def.NameIndex == v {
|
||||||
|
values[i] = strconv.Itoa(int(c.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if a given object has label promotion definitions
|
||||||
|
func HasPromotedLabels(index uint) bool {
|
||||||
|
_, ok := labelPromotionLabels[index]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if a given definition is a promoted label for an object
|
||||||
|
func IsDefPromotedLabel(objIndex uint, def uint) bool {
|
||||||
|
for _, v := range labelPromotionValues[objIndex] {
|
||||||
|
if v == def {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
75
vendor/github.com/leoluk/perflib_exporter/perflib/nametable.go
generated
vendored
Normal file
75
vendor/github.com/leoluk/perflib_exporter/perflib/nametable.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package perflib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type nameTableLookuper interface {
|
||||||
|
LookupName() string
|
||||||
|
LookupHelp() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *perfObjectType) LookupName() string {
|
||||||
|
return counterNameTable.LookupString(p.ObjectNameTitleIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *perfObjectType) LookupHelp() string {
|
||||||
|
return helpNameTable.LookupString(p.ObjectHelpTitleIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
type NameTable struct {
|
||||||
|
byIndex map[uint32]string
|
||||||
|
byString map[string]uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NameTable) LookupString(index uint32) string {
|
||||||
|
return t.byIndex[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NameTable) LookupIndex(str string) uint32 {
|
||||||
|
return t.byString[str]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query a perflib name table from the registry. Specify the type and the language
|
||||||
|
// code (i.e. "Counter 009" or "Help 009") for English language.
|
||||||
|
func QueryNameTable(tableName string) *NameTable {
|
||||||
|
nameTable := new(NameTable)
|
||||||
|
nameTable.byIndex = make(map[uint32]string)
|
||||||
|
|
||||||
|
buffer, err := queryRawData(tableName)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
r := bytes.NewReader(buffer)
|
||||||
|
for {
|
||||||
|
index, err := readUTF16String(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
desc, err := readUTF16String(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
indexInt, _ := strconv.Atoi(index)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprint("Invalid index ", index))
|
||||||
|
}
|
||||||
|
|
||||||
|
nameTable.byIndex[uint32(indexInt)] = desc
|
||||||
|
}
|
||||||
|
|
||||||
|
nameTable.byString = make(map[string]uint32)
|
||||||
|
|
||||||
|
for k, v := range nameTable.byIndex {
|
||||||
|
nameTable.byString[v] = k
|
||||||
|
}
|
||||||
|
|
||||||
|
return nameTable
|
||||||
|
}
|
||||||
460
vendor/github.com/leoluk/perflib_exporter/perflib/perflib.go
generated
vendored
Normal file
460
vendor/github.com/leoluk/perflib_exporter/perflib/perflib.go
generated
vendored
Normal file
@@ -0,0 +1,460 @@
|
|||||||
|
/*
|
||||||
|
Go bindings for the HKEY_PERFORMANCE_DATA perflib / Performance Counters interface.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
|
||||||
|
HKEY_PERFORMANCE_DATA is a low-level alternative to the higher-level PDH library and WMI.
|
||||||
|
It operates on blocks of counters and only returns raw values without calculating rates
|
||||||
|
or formatting them, which is exactly what you want for, say, a Prometheus exporter
|
||||||
|
(not so much for a GUI like Windows Performance Monitor).
|
||||||
|
|
||||||
|
Its overhead is much lower than the high-level libraries.
|
||||||
|
|
||||||
|
It operates on the same set of perflib providers as PDH and WMI. See this document
|
||||||
|
for more details on the relationship between the different libraries:
|
||||||
|
https://msdn.microsoft.com/en-us/library/windows/desktop/aa371643(v=vs.85).aspx
|
||||||
|
|
||||||
|
Example C++ source code:
|
||||||
|
https://msdn.microsoft.com/de-de/library/windows/desktop/aa372138(v=vs.85).aspx
|
||||||
|
|
||||||
|
For now, the API is not stable and is probably going to change in future
|
||||||
|
perflib_exporter releases. If you want to use this library, send the author an email
|
||||||
|
so we can discuss your requirements and stabilize the API.
|
||||||
|
|
||||||
|
Names
|
||||||
|
|
||||||
|
Counter names and help texts are resolved by looking up an index in a name table.
|
||||||
|
Since Microsoft loves internalization, both names and help texts can be requested
|
||||||
|
any locally available language.
|
||||||
|
|
||||||
|
The library automatically loads the name tables and resolves all identifiers
|
||||||
|
in English ("Name" and "HelpText" struct members). You can manually resolve
|
||||||
|
identifiers in a different language by using the NameTable API.
|
||||||
|
|
||||||
|
Performance Counters intro
|
||||||
|
|
||||||
|
Windows has a system-wide performance counter mechanism. Most performance counters
|
||||||
|
are stored as actual counters, not gauges (with some exceptions).
|
||||||
|
There's additional metadata which defines how the counter should be presented to the user
|
||||||
|
(for example, as a calculated rate). This library disregards all of the display metadata.
|
||||||
|
|
||||||
|
At the top level, there's a number of performance counter objects.
|
||||||
|
Each object has counter definitions, which contain the metadata for a particular
|
||||||
|
counter, and either zero or multiple instances. We hide the fact that there are
|
||||||
|
objects with no instances, and simply return a single null instance.
|
||||||
|
|
||||||
|
There's one counter per counter definition and instance (or the object itself, if
|
||||||
|
there are no instances).
|
||||||
|
|
||||||
|
Behind the scenes, every perflib DLL provides one or more objects.
|
||||||
|
Perflib has a registry where DLLs are dynamically registered and
|
||||||
|
unregistered. Some third party applications like VMWare provide their own counters,
|
||||||
|
but this is, sadly, a rare occurrence.
|
||||||
|
|
||||||
|
Different Windows releases have different numbers of counters.
|
||||||
|
|
||||||
|
Objects and counters are identified by well-known indices.
|
||||||
|
|
||||||
|
Here's an example object with one instance:
|
||||||
|
|
||||||
|
4320 WSMan Quota Statistics [7 counters, 1 instance(s)]
|
||||||
|
`-- "WinRMService"
|
||||||
|
`-- Total Requests/Second [4322] = 59
|
||||||
|
`-- User Quota Violations/Second [4324] = 0
|
||||||
|
`-- System Quota Violations/Second [4326] = 0
|
||||||
|
`-- Active Shells [4328] = 0
|
||||||
|
`-- Active Operations [4330] = 0
|
||||||
|
`-- Active Users [4332] = 0
|
||||||
|
`-- Process ID [4334] = 928
|
||||||
|
|
||||||
|
All "per second" metrics are counters, the rest are gauges.
|
||||||
|
|
||||||
|
Another example, with no instance:
|
||||||
|
|
||||||
|
4600 Network QoS Policy [6 counters, 1 instance(s)]
|
||||||
|
`-- (default)
|
||||||
|
`-- Packets transmitted [4602] = 1744
|
||||||
|
`-- Packets transmitted/sec [4604] = 4852
|
||||||
|
`-- Bytes transmitted [4606] = 4853
|
||||||
|
`-- Bytes transmitted/sec [4608] = 180388626632
|
||||||
|
`-- Packets dropped [4610] = 0
|
||||||
|
`-- Packets dropped/sec [4612] = 0
|
||||||
|
|
||||||
|
You can access the same values using PowerShell's Get-Counter cmdlet
|
||||||
|
or the Performance Monitor.
|
||||||
|
|
||||||
|
> Get-Counter '\WSMan Quota Statistics(WinRMService)\Process ID'
|
||||||
|
|
||||||
|
Timestamp CounterSamples
|
||||||
|
--------- --------------
|
||||||
|
1/28/2018 10:18:00 PM \\DEV\wsman quota statistics(winrmservice)\process id :
|
||||||
|
928
|
||||||
|
|
||||||
|
> (Get-Counter '\Process(Idle)\% Processor Time').CounterSamples[0] | Format-List *
|
||||||
|
[..detailed output...]
|
||||||
|
|
||||||
|
Data for some of the objects is also available through WMI:
|
||||||
|
|
||||||
|
> Get-CimInstance Win32_PerfRawData_Counters_WSManQuotaStatistics
|
||||||
|
|
||||||
|
Name : WinRMService
|
||||||
|
[...]
|
||||||
|
ActiveOperations : 0
|
||||||
|
ActiveShells : 0
|
||||||
|
ActiveUsers : 0
|
||||||
|
ProcessID : 928
|
||||||
|
SystemQuotaViolationsPerSecond : 0
|
||||||
|
TotalRequestsPerSecond : 59
|
||||||
|
UserQuotaViolationsPerSecond : 0
|
||||||
|
|
||||||
|
*/
|
||||||
|
package perflib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: There's a LittleEndian field in the PERF header - we ought to check it
|
||||||
|
var bo = binary.LittleEndian
|
||||||
|
|
||||||
|
var counterNameTable NameTable
|
||||||
|
var helpNameTable NameTable
|
||||||
|
|
||||||
|
// Top-level performance object (like "Process").
|
||||||
|
type PerfObject struct {
|
||||||
|
Name string
|
||||||
|
// Same index you pass to QueryPerformanceData
|
||||||
|
NameIndex uint
|
||||||
|
HelpText string
|
||||||
|
HelpTextIndex uint
|
||||||
|
Instances []*PerfInstance
|
||||||
|
CounterDefs []*PerfCounterDef
|
||||||
|
|
||||||
|
Frequency int64
|
||||||
|
|
||||||
|
rawData *perfObjectType
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each object can have multiple instances. For example,
|
||||||
|
// In case the object has no instances, we return one single PerfInstance with an empty name.
|
||||||
|
type PerfInstance struct {
|
||||||
|
// *not* resolved using a name table
|
||||||
|
Name string
|
||||||
|
Counters []*PerfCounter
|
||||||
|
|
||||||
|
rawData *perfInstanceDefinition
|
||||||
|
rawCounterBlock *perfCounterBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
type PerfCounterDef struct {
|
||||||
|
Name string
|
||||||
|
NameIndex uint
|
||||||
|
HelpText string
|
||||||
|
HelpTextIndex uint
|
||||||
|
|
||||||
|
// For debugging - subject to removal. CounterType is a perflib
|
||||||
|
// implementation detail (see perflib.h) and should not be used outside
|
||||||
|
// of this package. We export it so we can show it on /dump.
|
||||||
|
CounterType uint32
|
||||||
|
|
||||||
|
// PERF_TYPE_COUNTER (otherwise, it's a gauge)
|
||||||
|
IsCounter bool
|
||||||
|
// PERF_COUNTER_BASE (base value of a multi-value fraction)
|
||||||
|
IsBaseValue bool
|
||||||
|
// PERF_TIMER_100NS
|
||||||
|
IsNanosecondCounter bool
|
||||||
|
|
||||||
|
rawData *perfCounterDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
type PerfCounter struct {
|
||||||
|
Value int64
|
||||||
|
Def *PerfCounterDef
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error value returned by RegQueryValueEx if the buffer isn't sufficiently large
|
||||||
|
const errorMoreData = syscall.Errno(234)
|
||||||
|
|
||||||
|
var (
|
||||||
|
bufLenGlobal = uint32(400000)
|
||||||
|
bufLenCostly = uint32(2000000)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Queries the performance counter buffer using RegQueryValueEx, returning raw bytes. See:
|
||||||
|
// https://msdn.microsoft.com/de-de/library/windows/desktop/aa373219(v=vs.85).aspx
|
||||||
|
func queryRawData(query string) ([]byte, error) {
|
||||||
|
var (
|
||||||
|
valType uint32
|
||||||
|
buffer []byte
|
||||||
|
bufLen uint32
|
||||||
|
)
|
||||||
|
|
||||||
|
switch query {
|
||||||
|
case "Global":
|
||||||
|
bufLen = bufLenGlobal
|
||||||
|
case "Costly":
|
||||||
|
bufLen = bufLenCostly
|
||||||
|
default:
|
||||||
|
// TODO: depends on the number of values requested
|
||||||
|
// need make an educated guess
|
||||||
|
numCounters := len(strings.Split(query, " "))
|
||||||
|
bufLen = uint32(150000 * numCounters)
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = make([]byte, bufLen)
|
||||||
|
|
||||||
|
name, err := syscall.UTF16PtrFromString(query)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to encode query string: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
bufLen := uint32(len(buffer))
|
||||||
|
|
||||||
|
err := syscall.RegQueryValueEx(
|
||||||
|
syscall.HKEY_PERFORMANCE_DATA,
|
||||||
|
name,
|
||||||
|
nil,
|
||||||
|
&valType,
|
||||||
|
(*byte)(unsafe.Pointer(&buffer[0])),
|
||||||
|
&bufLen)
|
||||||
|
|
||||||
|
if err == errorMoreData {
|
||||||
|
newBuffer := make([]byte, len(buffer)+16384)
|
||||||
|
copy(newBuffer, buffer)
|
||||||
|
buffer = newBuffer
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
|
if errno, ok := err.(syscall.Errno); ok {
|
||||||
|
return nil, fmt.Errorf("ReqQueryValueEx failed: %v errno %d", err, uint(errno))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = buffer[:bufLen]
|
||||||
|
|
||||||
|
switch query {
|
||||||
|
case "Global":
|
||||||
|
if bufLen > bufLenGlobal {
|
||||||
|
bufLenGlobal = bufLen
|
||||||
|
}
|
||||||
|
case "Costly":
|
||||||
|
if bufLen > bufLenCostly {
|
||||||
|
bufLenCostly = bufLen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Initialize global name tables
|
||||||
|
// TODO: profiling, add option to disable name tables if necessary
|
||||||
|
// Not sure if we should resolve the names at all or just have the caller do it on demand
|
||||||
|
// (for many use cases the index is sufficient)
|
||||||
|
|
||||||
|
counterNameTable = *QueryNameTable("Counter 009")
|
||||||
|
helpNameTable = *QueryNameTable("Help 009")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Query all performance counters that match a given query.
|
||||||
|
|
||||||
|
The query can be any of the following:
|
||||||
|
|
||||||
|
- "Global" (all performance counters except those Windows marked as costly)
|
||||||
|
|
||||||
|
- "Costly" (only the costly ones)
|
||||||
|
|
||||||
|
- One or more object indices, separated by spaces ("238 2 5")
|
||||||
|
|
||||||
|
Many objects have dependencies - if you query one of them, you often get back
|
||||||
|
more than you asked for.
|
||||||
|
*/
|
||||||
|
func QueryPerformanceData(query string) ([]*PerfObject, error) {
|
||||||
|
buffer, err := queryRawData(query)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r := bytes.NewReader(buffer)
|
||||||
|
|
||||||
|
// Read global header
|
||||||
|
|
||||||
|
header := new(perfDataBlock)
|
||||||
|
err = header.BinaryReadFrom(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for "PERF" signature
|
||||||
|
if header.Signature != [4]uint16{80, 69, 82, 70} {
|
||||||
|
panic("Invalid performance block header")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the performance data
|
||||||
|
|
||||||
|
numObjects := int(header.NumObjectTypes)
|
||||||
|
objects := make([]*PerfObject, numObjects)
|
||||||
|
|
||||||
|
objOffset := int64(header.HeaderLength)
|
||||||
|
|
||||||
|
for i := 0; i < numObjects; i++ {
|
||||||
|
r.Seek(objOffset, io.SeekStart)
|
||||||
|
|
||||||
|
obj := new(perfObjectType)
|
||||||
|
obj.BinaryReadFrom(r)
|
||||||
|
|
||||||
|
numCounterDefs := int(obj.NumCounters)
|
||||||
|
numInstances := int(obj.NumInstances)
|
||||||
|
|
||||||
|
// Perf objects can have no instances. The perflib differentiates
|
||||||
|
// between objects with instances and without, but we just create
|
||||||
|
// an empty instance in order to simplify the interface.
|
||||||
|
if numInstances <= 0 {
|
||||||
|
numInstances = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
instances := make([]*PerfInstance, numInstances)
|
||||||
|
counterDefs := make([]*PerfCounterDef, numCounterDefs)
|
||||||
|
|
||||||
|
objects[i] = &PerfObject{
|
||||||
|
Name: obj.LookupName(),
|
||||||
|
NameIndex: uint(obj.ObjectNameTitleIndex),
|
||||||
|
HelpText: obj.LookupHelp(),
|
||||||
|
HelpTextIndex: uint(obj.ObjectHelpTitleIndex),
|
||||||
|
Instances: instances,
|
||||||
|
CounterDefs: counterDefs,
|
||||||
|
Frequency: obj.PerfFreq,
|
||||||
|
rawData: obj,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < numCounterDefs; i++ {
|
||||||
|
def := new(perfCounterDefinition)
|
||||||
|
def.BinaryReadFrom(r)
|
||||||
|
|
||||||
|
counterDefs[i] = &PerfCounterDef{
|
||||||
|
Name: def.LookupName(),
|
||||||
|
NameIndex: uint(def.CounterNameTitleIndex),
|
||||||
|
HelpText: def.LookupHelp(),
|
||||||
|
HelpTextIndex: uint(def.CounterHelpTitleIndex),
|
||||||
|
rawData: def,
|
||||||
|
|
||||||
|
CounterType: def.CounterType,
|
||||||
|
|
||||||
|
IsCounter: def.CounterType&0x400 == 0x400,
|
||||||
|
IsBaseValue: def.CounterType&0x00030000 == 0x00030000,
|
||||||
|
IsNanosecondCounter: def.CounterType&0x00100000 == 0x00100000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.NumInstances <= 0 {
|
||||||
|
blockOffset := objOffset + int64(obj.DefinitionLength)
|
||||||
|
r.Seek(blockOffset, io.SeekStart)
|
||||||
|
|
||||||
|
_, counters := parseCounterBlock(buffer, r, blockOffset, counterDefs)
|
||||||
|
|
||||||
|
instances[0] = &PerfInstance{
|
||||||
|
Name: "",
|
||||||
|
Counters: counters,
|
||||||
|
rawData: nil,
|
||||||
|
rawCounterBlock: nil,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
instOffset := objOffset + int64(obj.DefinitionLength)
|
||||||
|
|
||||||
|
for i := 0; i < numInstances; i++ {
|
||||||
|
r.Seek(instOffset, io.SeekStart)
|
||||||
|
|
||||||
|
inst := new(perfInstanceDefinition)
|
||||||
|
inst.BinaryReadFrom(r)
|
||||||
|
|
||||||
|
name, _ := readUTF16StringAtPos(r, instOffset+int64(inst.NameOffset), inst.NameLength)
|
||||||
|
pos := instOffset + int64(inst.ByteLength)
|
||||||
|
offset, counters := parseCounterBlock(buffer, r, pos, counterDefs)
|
||||||
|
|
||||||
|
instances[i] = &PerfInstance{
|
||||||
|
Name: name,
|
||||||
|
Counters: counters,
|
||||||
|
rawData: inst,
|
||||||
|
}
|
||||||
|
|
||||||
|
instOffset = pos + offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next perfObjectType
|
||||||
|
objOffset += int64(obj.TotalByteLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
return objects, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCounterBlock(b []byte, r io.ReadSeeker, pos int64, defs []*PerfCounterDef) (int64, []*PerfCounter) {
|
||||||
|
r.Seek(pos, io.SeekStart)
|
||||||
|
block := new(perfCounterBlock)
|
||||||
|
block.BinaryReadFrom(r)
|
||||||
|
|
||||||
|
counters := make([]*PerfCounter, len(defs))
|
||||||
|
|
||||||
|
for i, def := range defs {
|
||||||
|
valueOffset := pos + int64(def.rawData.CounterOffset)
|
||||||
|
value := convertCounterValue(def.rawData, b, valueOffset)
|
||||||
|
|
||||||
|
counters[i] = &PerfCounter{
|
||||||
|
Value: value,
|
||||||
|
Def: def,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(block.ByteLength), counters
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertCounterValue(counterDef *perfCounterDefinition, buffer []byte, valueOffset int64) (value int64) {
|
||||||
|
/*
|
||||||
|
We can safely ignore the type since we're not interested in anything except the raw value.
|
||||||
|
We also ignore all of the other attributes (timestamp, presentation, multi counter values...)
|
||||||
|
|
||||||
|
See also: winperf.h.
|
||||||
|
|
||||||
|
Here's the most common value for CounterType:
|
||||||
|
|
||||||
|
65536 32bit counter
|
||||||
|
65792 64bit counter
|
||||||
|
272696320 32bit rate
|
||||||
|
272696576 64bit rate
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch counterDef.CounterSize {
|
||||||
|
case 4:
|
||||||
|
value = int64(bo.Uint32(buffer[valueOffset:(valueOffset + 4)]))
|
||||||
|
case 8:
|
||||||
|
value = int64(bo.Uint64(buffer[valueOffset:(valueOffset + 8)]))
|
||||||
|
default:
|
||||||
|
value = int64(bo.Uint32(buffer[valueOffset:(valueOffset + 4)]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort slice of objects by index. This is useful for displaying
|
||||||
|
// a human-readable list or dump, but unnecessary otherwise.
|
||||||
|
func SortObjects(p []*PerfObject) {
|
||||||
|
sort.Slice(p, func(i, j int) bool {
|
||||||
|
return p[i].NameIndex < p[j].NameIndex
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
180
vendor/github.com/leoluk/perflib_exporter/perflib/raw_types.go
generated
vendored
Normal file
180
vendor/github.com/leoluk/perflib_exporter/perflib/raw_types.go
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
package perflib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type binaryReaderFrom interface {
|
||||||
|
BinaryReadFrom(r io.Reader) error
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://msdn.microsoft.com/de-de/library/windows/desktop/aa373157(v=vs.85).aspx
|
||||||
|
|
||||||
|
typedef struct _PERF_DATA_BLOCK {
|
||||||
|
WCHAR Signature[4];
|
||||||
|
DWORD LittleEndian;
|
||||||
|
DWORD Version;
|
||||||
|
DWORD Revision;
|
||||||
|
DWORD TotalByteLength;
|
||||||
|
DWORD HeaderLength;
|
||||||
|
DWORD NumObjectTypes;
|
||||||
|
DWORD DefaultObject;
|
||||||
|
SYSTEMTIME SystemTime;
|
||||||
|
LARGE_INTEGER PerfTime;
|
||||||
|
LARGE_INTEGER PerfFreq;
|
||||||
|
LARGE_INTEGER PerfTime100nSec;
|
||||||
|
DWORD SystemNameLength;
|
||||||
|
DWORD SystemNameOffset;
|
||||||
|
} PERF_DATA_BLOCK;
|
||||||
|
*/
|
||||||
|
|
||||||
|
type perfDataBlock struct {
|
||||||
|
Signature [4]uint16
|
||||||
|
LittleEndian uint32
|
||||||
|
Version uint32
|
||||||
|
Revision uint32
|
||||||
|
TotalByteLength uint32
|
||||||
|
HeaderLength uint32
|
||||||
|
NumObjectTypes uint32
|
||||||
|
DefaultObject int32
|
||||||
|
SystemTime syscall.Systemtime
|
||||||
|
_ uint32 // TODO
|
||||||
|
PerfTime int64
|
||||||
|
PerfFreq int64
|
||||||
|
PerfTime100nSec int64
|
||||||
|
SystemNameLength uint32
|
||||||
|
SystemNameOffset uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *perfDataBlock) BinaryReadFrom(r io.Reader) error {
|
||||||
|
return binary.Read(r, bo, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://msdn.microsoft.com/en-us/library/windows/desktop/aa373160(v=vs.85).aspx
|
||||||
|
|
||||||
|
typedef struct _PERF_OBJECT_TYPE {
|
||||||
|
DWORD TotalByteLength;
|
||||||
|
DWORD DefinitionLength;
|
||||||
|
DWORD HeaderLength;
|
||||||
|
DWORD ObjectNameTitleIndex;
|
||||||
|
LPWSTR ObjectNameTitle;
|
||||||
|
DWORD ObjectHelpTitleIndex;
|
||||||
|
LPWSTR ObjectHelpTitle;
|
||||||
|
DWORD DetailLevel;
|
||||||
|
DWORD NumCounters;
|
||||||
|
DWORD DefaultCounter;
|
||||||
|
DWORD NumInstances;
|
||||||
|
DWORD CodePage;
|
||||||
|
LARGE_INTEGER PerfTime;
|
||||||
|
LARGE_INTEGER PerfFreq;
|
||||||
|
} PERF_OBJECT_TYPE;
|
||||||
|
*/
|
||||||
|
|
||||||
|
type perfObjectType struct {
|
||||||
|
TotalByteLength uint32
|
||||||
|
DefinitionLength uint32
|
||||||
|
HeaderLength uint32
|
||||||
|
ObjectNameTitleIndex uint32
|
||||||
|
ObjectNameTitle uint32
|
||||||
|
ObjectHelpTitleIndex uint32
|
||||||
|
ObjectHelpTitle uint32
|
||||||
|
DetailLevel uint32
|
||||||
|
NumCounters uint32
|
||||||
|
DefaultCounter int32
|
||||||
|
NumInstances int32
|
||||||
|
CodePage uint32
|
||||||
|
PerfTime int64
|
||||||
|
PerfFreq int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *perfObjectType) BinaryReadFrom(r io.Reader) error {
|
||||||
|
return binary.Read(r, bo, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://msdn.microsoft.com/en-us/library/windows/desktop/aa373150(v=vs.85).aspx
|
||||||
|
|
||||||
|
typedef struct _PERF_COUNTER_DEFINITION {
|
||||||
|
DWORD ByteLength;
|
||||||
|
DWORD CounterNameTitleIndex;
|
||||||
|
LPWSTR CounterNameTitle;
|
||||||
|
DWORD CounterHelpTitleIndex;
|
||||||
|
LPWSTR CounterHelpTitle;
|
||||||
|
LONG DefaultScale;
|
||||||
|
DWORD DetailLevel;
|
||||||
|
DWORD CounterType;
|
||||||
|
DWORD CounterSize;
|
||||||
|
DWORD CounterOffset;
|
||||||
|
} PERF_COUNTER_DEFINITION;
|
||||||
|
*/
|
||||||
|
|
||||||
|
type perfCounterDefinition struct {
|
||||||
|
ByteLength uint32
|
||||||
|
CounterNameTitleIndex uint32
|
||||||
|
CounterNameTitle uint32
|
||||||
|
CounterHelpTitleIndex uint32
|
||||||
|
CounterHelpTitle uint32
|
||||||
|
DefaultScale int32
|
||||||
|
DetailLevel uint32
|
||||||
|
CounterType uint32
|
||||||
|
CounterSize uint32
|
||||||
|
CounterOffset uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *perfCounterDefinition) BinaryReadFrom(r io.Reader) error {
|
||||||
|
return binary.Read(r, bo, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *perfCounterDefinition) LookupName() string {
|
||||||
|
return counterNameTable.LookupString(p.CounterNameTitleIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *perfCounterDefinition) LookupHelp() string {
|
||||||
|
return helpNameTable.LookupString(p.CounterHelpTitleIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://msdn.microsoft.com/en-us/library/windows/desktop/aa373147(v=vs.85).aspx
|
||||||
|
|
||||||
|
typedef struct _PERF_COUNTER_BLOCK {
|
||||||
|
DWORD ByteLength;
|
||||||
|
} PERF_COUNTER_BLOCK;
|
||||||
|
*/
|
||||||
|
|
||||||
|
type perfCounterBlock struct {
|
||||||
|
ByteLength uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *perfCounterBlock) BinaryReadFrom(r io.Reader) error {
|
||||||
|
return binary.Read(r, bo, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://msdn.microsoft.com/en-us/library/windows/desktop/aa373159(v=vs.85).aspx
|
||||||
|
|
||||||
|
typedef struct _PERF_INSTANCE_DEFINITION {
|
||||||
|
DWORD ByteLength;
|
||||||
|
DWORD ParentObjectTitleIndex;
|
||||||
|
DWORD ParentObjectInstance;
|
||||||
|
DWORD UniqueID;
|
||||||
|
DWORD NameOffset;
|
||||||
|
DWORD NameLength;
|
||||||
|
} PERF_INSTANCE_DEFINITION;
|
||||||
|
*/
|
||||||
|
|
||||||
|
type perfInstanceDefinition struct {
|
||||||
|
ByteLength uint32
|
||||||
|
ParentObjectTitleIndex uint32
|
||||||
|
ParentObjectInstance uint32
|
||||||
|
UniqueID uint32
|
||||||
|
NameOffset uint32
|
||||||
|
NameLength uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *perfInstanceDefinition) BinaryReadFrom(r io.Reader) error {
|
||||||
|
return binary.Read(r, bo, p)
|
||||||
|
}
|
||||||
49
vendor/github.com/leoluk/perflib_exporter/perflib/utf16.go
generated
vendored
Normal file
49
vendor/github.com/leoluk/perflib_exporter/perflib/utf16.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package perflib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Read an unterminated UTF16 string at a given position, specifying its length
|
||||||
|
func readUTF16StringAtPos(r io.ReadSeeker, absPos int64, length uint32) (string, error) {
|
||||||
|
value := make([]uint16, length/2)
|
||||||
|
_, err := r.Seek(absPos, io.SeekStart)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = binary.Read(r, bo, value)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return syscall.UTF16ToString(value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads a null-terminated UTF16 string at the current offset
|
||||||
|
func readUTF16String(r io.Reader) (string, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
b := make([]byte, 2)
|
||||||
|
out := make([]uint16, 0, 100)
|
||||||
|
|
||||||
|
for i := 0; err == nil; i += 2 {
|
||||||
|
_, err = r.Read(b)
|
||||||
|
|
||||||
|
if b[0] == 0 && b[1] == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
out = append(out, bo.Uint16(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return syscall.UTF16ToString(out), nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user