Compare commits

..

25 Commits

Author SHA1 Message Date
Calle Pettersson
a41b9de37c Fix WiX download url 2017-03-17 19:23:03 +01:00
jimliming
745f0a6f61 updating Win32_PerfRawData_Tcpip_NetworkInterface to uint64 (#61) 2017-03-17 19:12:47 +01:00
Martin Lindhe
8ca60af43a Merge pull request #59 from martinlindhe/additional-collectors
Add [defaults] placeholder support to collectors.enabled
2017-03-04 12:56:10 +01:00
Calle Pettersson
a66f0b5475 Add [defaults] placeholder support to collectors.enabled 2017-03-04 12:44:47 +01:00
Martin Lindhe
25b8dba6df Merge pull request #58 from martinlindhe/expose-all-service-states
Always expose all possible service states/start modes
2017-03-04 11:12:31 +01:00
Calle Pettersson
f5365c96f6 Always expose all possible service states/start modes 2017-03-04 10:38:40 +01:00
Martin Lindhe
a05febe069 install.ps1: fix wix download url 2017-03-04 09:13:38 +01:00
Martin Lindhe
47dc455dc2 Merge pull request #56 from martinlindhe/service-collector
Add Win32_Service collector
2017-03-03 17:01:13 +01:00
Calle Pettersson
9ea0c95ca5 Add support for generating collectors from remote systems 2017-03-03 14:55:11 +01:00
Calle Pettersson
91374a75f2 Add Win32_Service collector 2017-03-03 14:51:24 +01:00
Calle Pettersson
b4ca3412dd Fix arch name typo 2016-12-25 07:55:42 +01:00
Martin Lindhe
7fdbdad140 Merge pull request #48 from martinlindhe/x86-builds 2016-12-24 17:48:01 +01:00
Calle Pettersson
e65b785995 Remove rdp-debug 2016-12-22 07:45:09 +01:00
Calle Pettersson
8482814343 Add arch-specific go-bin directory to path 2016-12-22 06:54:46 +01:00
Calle Pettersson
8df4ea3f51 Debug x86 build failure 2016-12-22 06:45:58 +01:00
Calle Pettersson
f60211aba3 Compile for both x86 and amd64 2016-12-20 18:51:56 +01:00
Martin Lindhe
2808da68d8 Merge pull request #41 from martinlindhe/fix_system_uptime
system: fix uptime calculation
2016-11-16 08:38:21 +01:00
Martin Lindhe
a3f44f60c5 system: fix uptime calculation, fixes #40 2016-11-15 09:07:04 +01:00
Martin Lindhe
5925816a9a Merge pull request #42 from martinlindhe/dns-server-collector
Add DNS server collector
2016-11-15 08:44:38 +01:00
Calle Pettersson
0beff465c0 Add DNS server collector 2016-11-15 06:37:52 +01:00
Martin Lindhe
b40d60b8a4 fix comments 2016-11-14 08:55:51 +01:00
Martin Lindhe
a1910c3963 Merge pull request #39 from martinlindhe/setup-gitversion
Setup GitVersion
2016-10-18 20:13:13 +02:00
Calle Pettersson
4c39660624 Setup GitVersion 2016-10-18 16:37:30 +02:00
Martin Lindhe
2fce1541d8 README: for roadmap, link to issues rather than TODO wiki 2016-10-14 14:32:11 +02:00
Martin Lindhe
66b6145835 README: remove experimental banner 2016-10-14 14:31:03 +02:00
12 changed files with 734 additions and 30 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
*.exe
VERSION

View File

@@ -4,8 +4,6 @@
Prometheus exporter for Windows machines, using the WMI (Windows Management Instrumentation).
**EXPERIMENTAL, use at your own risk!**
## Collectors
@@ -13,10 +11,12 @@ Name | Description | Enabled by default
---------|-------------|--------------------
cpu | [Win32_PerfRawData_PerfOS_Processor](https://msdn.microsoft.com/en-us/library/aa394317(v=vs.90).aspx) metrics (cpu usage) | ✓
cs | [Win32_ComputerSystem](https://msdn.microsoft.com/en-us/library/aa394102) metrics (system properties, num cpus/total memory) | ✓
dns | [Win32_PerfRawData_DNS_DNS](https://technet.microsoft.com/en-us/library/cc977686.aspx) metrics (DNS Server) |
iis | [Win32_PerfRawData_W3SVC_WebService](https://msdn.microsoft.com/en-us/library/aa394345) IIS metrics |
logical_disk | [Win32_PerfRawData_PerfDisk_LogicalDisk](https://msdn.microsoft.com/en-us/windows/hardware/aa394307(v=vs.71)) metrics (disk I/O) | ✓
net | [Win32_PerfRawData_Tcpip_NetworkInterface](https://technet.microsoft.com/en-us/security/aa394340(v=vs.80)) metrics (network interface I/O) | ✓
os | [Win32_OperatingSystem](https://msdn.microsoft.com/en-us/library/aa394239) metrics (memory, processes, users) | ✓
service | [Win32_Service](https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx) metrics (service states) | ✓
system | Win32_PerfRawData_PerfOS_System metrics (system calls) | ✓
The HELP texts shows the WMI data source, please see MSDN documentation for details.
@@ -41,7 +41,7 @@ msiexec /i <path-to-msi-file> ENABLED_COLLECTORS=os,iis LISTEN_PORT=5000
## Roadmap
See [Wiki](https://github.com/martinlindhe/wmi_exporter/wiki/TODO)
See [open issues](https://github.com/martinlindhe/wmi_exporter/issues)
## Usage

View File

@@ -1 +0,0 @@
0.1.0

View File

@@ -4,30 +4,41 @@ os: Windows Server 2012 R2
environment:
GOPATH: c:\gopath
matrix:
- MSI_ARCH: amd64
GOARCH: amd64
- MSI_ARCH: 386
GOARCH: 386
clone_folder: c:\gopath\src\github.com\martinlindhe\wmi_exporter
install:
- go version
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- set PATH=%GOPATH%\bin;c:\go\bin;%GOPATH%\bin\windows_%GOARCH%;%PATH%
- go get -u github.com/kardianos/govendor
- go get -u github.com/prometheus/promu
- choco install gitversion.portable -y
build_script:
- ps: gitversion /output json /showvariable FullSemVer | Set-Content VERSION -PassThru
- govendor test -v +local
- promu build -v .
- ps: |
$ErrorActionPreference = "Stop"
if($env:APPVEYOR_REPO_TAG -eq "True") {
# The MSI version is not semver compliant, so just take the numerical parts
$Version = $env:APPVEYOR_REPO_TAG_NAME -replace '^v?([0-9\.]+).*$','$1'
Write-Verbose "Setting msi version to $Version"
.\installer\build.ps1 -PathToExecutable .\wmi_exporter.exe -Version $Version -Arch "amd64"
Push-AppveyorArtifact installer\Output\wmi_exporter-$Version-amd64.msi -DeploymentName Installer
.\installer\build.ps1 -PathToExecutable .\wmi_exporter.exe -Version $Version -Arch "$env:MSI_ARCH"
Push-AppveyorArtifact installer\Output\wmi_exporter-$Version-$env:MSI_ARCH.msi -DeploymentName Installer
}
after_build:
- 7z a wmi_exporter-%MSI_ARCH%.zip wmi_exporter.exe
artifacts:
- name: Executable
path: wmi_exporter.exe
path: 'wmi_exporter-*.zip'
deploy:
- provider: GitHub

492
collector/dns.go Normal file
View File

@@ -0,0 +1,492 @@
// returns data points from Win32_PerfRawData_DNS_DNS
// https://msdn.microsoft.com/en-us/library/ms803992.aspx?f=255&MSPPError=-2147217396
// https://technet.microsoft.com/en-us/library/cc977686.aspx
package collector
import (
"log"
"github.com/StackExchange/wmi"
"github.com/prometheus/client_golang/prometheus"
)
func init() {
Factories["dns"] = NewDNSCollector
}
// A DNSCollector is a Prometheus collector for WMI Win32_PerfRawData_DNS_DNS metrics
type DNSCollector struct {
ZoneTransferRequestsReceived *prometheus.Desc
ZoneTransferRequestsSent *prometheus.Desc
ZoneTransferResponsesReceived *prometheus.Desc
ZoneTransferSuccessReceived *prometheus.Desc
ZoneTransferSuccessSent *prometheus.Desc
ZoneTransferFailures *prometheus.Desc
MemoryUsedBytes *prometheus.Desc
DynamicUpdatesQueued *prometheus.Desc
DynamicUpdatesReceived *prometheus.Desc
DynamicUpdatesFailures *prometheus.Desc
NotifyReceived *prometheus.Desc
NotifySent *prometheus.Desc
SecureUpdateFailures *prometheus.Desc
SecureUpdateReceived *prometheus.Desc
Queries *prometheus.Desc
Responses *prometheus.Desc
RecursiveQueries *prometheus.Desc
RecursiveQueryFailures *prometheus.Desc
RecursiveQuerySendTimeouts *prometheus.Desc
WinsQueries *prometheus.Desc
WinsResponses *prometheus.Desc
UnmatchedResponsesReceived *prometheus.Desc
}
// NewDNSCollector ...
func NewDNSCollector() (Collector, error) {
const subsystem = "dns"
return &DNSCollector{
ZoneTransferRequestsReceived: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "zone_transfer_requests_received_total"),
"Number of zone transfer requests (AXFR/IXFR) received by the master DNS server",
[]string{"qtype"},
nil,
),
ZoneTransferRequestsSent: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "zone_transfer_requests_sent_total"),
"Number of zone transfer requests (AXFR/IXFR) sent by the secondary DNS server",
[]string{"qtype"},
nil,
),
ZoneTransferResponsesReceived: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "zone_transfer_response_received_total"),
"Number of zone transfer responses (AXFR/IXFR) received by the secondary DNS server",
[]string{"qtype"},
nil,
),
ZoneTransferSuccessReceived: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "zone_transfer_success_received_total"),
"Number of successful zone transfers (AXFR/IXFR) received by the secondary DNS server",
[]string{"qtype", "protocol"},
nil,
),
ZoneTransferSuccessSent: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "zone_transfer_success_sent_total"),
"Number of successful zone transfers (AXFR/IXFR) of the master DNS server",
[]string{"qtype"},
nil,
),
ZoneTransferFailures: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "zone_transfer_failures_total"),
"Number of failed zone transfers of the master DNS server",
nil,
nil,
),
MemoryUsedBytes: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "memory_used_bytes_total"),
"Total memory used by DNS server",
[]string{"area"},
nil,
),
DynamicUpdatesQueued: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "dynamic_updates_queued"),
"Number of dynamic updates queued by the DNS server",
nil,
nil,
),
DynamicUpdatesReceived: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "dynamic_updates_received_total"),
"Number of secure update requests received by the DNS server",
[]string{"operation"},
nil,
),
DynamicUpdatesFailures: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "dynamic_updates_failures_total"),
"Number of dynamic updates which timed out or were rejected by the DNS server",
[]string{"reason"},
nil,
),
NotifyReceived: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "notify_received_total"),
"Number of notifies received by the secondary DNS server",
nil,
nil,
),
NotifySent: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "notify_sent_total"),
"Number of notifies sent by the master DNS server",
nil,
nil,
),
SecureUpdateFailures: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "secure_update_failures_total"),
"Number of secure updates that failed on the DNS server",
nil,
nil,
),
SecureUpdateReceived: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "secure_update_received_total"),
"Number of secure update requests received by the DNS server",
nil,
nil,
),
Queries: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "queries_total"),
"Number of queries received by DNS server",
[]string{"protocol"},
nil,
),
Responses: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "responses_total"),
"Number of reponses sent by DNS server",
[]string{"protocol"},
nil,
),
RecursiveQueries: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "recursive_queries_total"),
"Number of recursive queries received by DNS server",
nil,
nil,
),
RecursiveQueryFailures: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "recursive_query_failures_total"),
"Number of recursive query failures",
nil,
nil,
),
RecursiveQuerySendTimeouts: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "recursive_query_send_timeouts_total"),
"Number of recursive query sending timeouts",
nil,
nil,
),
WinsQueries: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "wins_queries_total"),
"Number of WINS lookup requests received by the server",
[]string{"direction"},
nil,
),
WinsResponses: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "wins_responses_total"),
"Number of WINS lookup responses sent by the server",
[]string{"direction"},
nil,
),
UnmatchedResponsesReceived: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "unmatched_responses_total"),
"Number of response packets received by the DNS server that do not match any outstanding remote query",
nil,
nil,
),
}, nil
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *DNSCollector) Collect(ch chan<- prometheus.Metric) error {
if desc, err := c.collect(ch); err != nil {
log.Println("[ERROR] failed collecting dns metrics:", desc, err)
return err
}
return nil
}
type Win32_PerfRawData_DNS_DNS struct {
AXFRRequestReceived uint32
AXFRRequestSent uint32
AXFRResponseReceived uint32
AXFRSuccessReceived uint32
AXFRSuccessSent uint32
CachingMemory uint32
DatabaseNodeMemory uint32
DynamicUpdateNoOperation uint32
DynamicUpdateQueued uint32
DynamicUpdateRejected uint32
DynamicUpdateTimeOuts uint32
DynamicUpdateWrittentoDatabase uint32
IXFRRequestReceived uint32
IXFRRequestSent uint32
IXFRResponseReceived uint32
IXFRSuccessSent uint32
IXFRTCPSuccessReceived uint32
IXFRUDPSuccessReceived uint32
NbstatMemory uint32
NotifyReceived uint32
NotifySent uint32
RecordFlowMemory uint32
RecursiveQueries uint32
RecursiveQueryFailure uint32
RecursiveSendTimeOuts uint32
SecureUpdateFailure uint32
SecureUpdateReceived uint32
TCPMessageMemory uint32
TCPQueryReceived uint32
TCPResponseSent uint32
UDPMessageMemory uint32
UDPQueryReceived uint32
UDPResponseSent uint32
UnmatchedResponsesReceived uint32
WINSLookupReceived uint32
WINSResponseSent uint32
WINSReverseLookupReceived uint32
WINSReverseResponseSent uint32
ZoneTransferFailure uint32
ZoneTransferSOARequestSent uint32
}
func (c *DNSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
var dst []Win32_PerfRawData_DNS_DNS
q := wmi.CreateQuery(&dst, "")
if err := wmi.Query(q, &dst); err != nil {
return nil, err
}
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferRequestsReceived,
prometheus.CounterValue,
float64(dst[0].AXFRRequestReceived),
"full",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferRequestsReceived,
prometheus.CounterValue,
float64(dst[0].IXFRRequestReceived),
"incremental",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferRequestsSent,
prometheus.CounterValue,
float64(dst[0].AXFRRequestSent),
"full",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferRequestsSent,
prometheus.CounterValue,
float64(dst[0].IXFRRequestSent),
"incremental",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferRequestsSent,
prometheus.CounterValue,
float64(dst[0].ZoneTransferSOARequestSent),
"soa",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferResponsesReceived,
prometheus.CounterValue,
float64(dst[0].AXFRResponseReceived),
"full",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferResponsesReceived,
prometheus.CounterValue,
float64(dst[0].IXFRResponseReceived),
"incremental",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferSuccessReceived,
prometheus.CounterValue,
float64(dst[0].AXFRSuccessReceived),
"full",
"tcp",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferSuccessReceived,
prometheus.CounterValue,
float64(dst[0].IXFRTCPSuccessReceived),
"incremental",
"tcp",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferSuccessReceived,
prometheus.CounterValue,
float64(dst[0].IXFRTCPSuccessReceived),
"incremental",
"udp",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferSuccessSent,
prometheus.CounterValue,
float64(dst[0].AXFRSuccessSent),
"full",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferSuccessSent,
prometheus.CounterValue,
float64(dst[0].IXFRSuccessSent),
"incremental",
)
ch <- prometheus.MustNewConstMetric(
c.ZoneTransferFailures,
prometheus.CounterValue,
float64(dst[0].ZoneTransferFailure),
)
ch <- prometheus.MustNewConstMetric(
c.MemoryUsedBytes,
prometheus.GaugeValue,
float64(dst[0].CachingMemory),
"caching",
)
ch <- prometheus.MustNewConstMetric(
c.MemoryUsedBytes,
prometheus.GaugeValue,
float64(dst[0].DatabaseNodeMemory),
"database_node",
)
ch <- prometheus.MustNewConstMetric(
c.MemoryUsedBytes,
prometheus.GaugeValue,
float64(dst[0].NbstatMemory),
"nbstat",
)
ch <- prometheus.MustNewConstMetric(
c.MemoryUsedBytes,
prometheus.GaugeValue,
float64(dst[0].RecordFlowMemory),
"record_flow",
)
ch <- prometheus.MustNewConstMetric(
c.MemoryUsedBytes,
prometheus.GaugeValue,
float64(dst[0].TCPMessageMemory),
"tcp_message",
)
ch <- prometheus.MustNewConstMetric(
c.MemoryUsedBytes,
prometheus.GaugeValue,
float64(dst[0].UDPMessageMemory),
"udp_message",
)
ch <- prometheus.MustNewConstMetric(
c.DynamicUpdatesReceived,
prometheus.CounterValue,
float64(dst[0].DynamicUpdateNoOperation),
"noop",
)
ch <- prometheus.MustNewConstMetric(
c.DynamicUpdatesReceived,
prometheus.CounterValue,
float64(dst[0].DynamicUpdateWrittentoDatabase),
"written",
)
ch <- prometheus.MustNewConstMetric(
c.DynamicUpdatesQueued,
prometheus.GaugeValue,
float64(dst[0].DynamicUpdateQueued),
)
ch <- prometheus.MustNewConstMetric(
c.DynamicUpdatesFailures,
prometheus.CounterValue,
float64(dst[0].DynamicUpdateRejected),
"rejected",
)
ch <- prometheus.MustNewConstMetric(
c.DynamicUpdatesFailures,
prometheus.CounterValue,
float64(dst[0].DynamicUpdateTimeOuts),
"timeout",
)
ch <- prometheus.MustNewConstMetric(
c.NotifyReceived,
prometheus.CounterValue,
float64(dst[0].NotifyReceived),
)
ch <- prometheus.MustNewConstMetric(
c.NotifySent,
prometheus.CounterValue,
float64(dst[0].NotifySent),
)
ch <- prometheus.MustNewConstMetric(
c.RecursiveQueries,
prometheus.CounterValue,
float64(dst[0].RecursiveQueries),
)
ch <- prometheus.MustNewConstMetric(
c.RecursiveQueryFailures,
prometheus.CounterValue,
float64(dst[0].RecursiveQueryFailure),
)
ch <- prometheus.MustNewConstMetric(
c.RecursiveQuerySendTimeouts,
prometheus.CounterValue,
float64(dst[0].RecursiveSendTimeOuts),
)
ch <- prometheus.MustNewConstMetric(
c.Queries,
prometheus.CounterValue,
float64(dst[0].TCPQueryReceived),
"tcp",
)
ch <- prometheus.MustNewConstMetric(
c.Queries,
prometheus.CounterValue,
float64(dst[0].UDPQueryReceived),
"udp",
)
ch <- prometheus.MustNewConstMetric(
c.Responses,
prometheus.CounterValue,
float64(dst[0].TCPResponseSent),
"tcp",
)
ch <- prometheus.MustNewConstMetric(
c.Responses,
prometheus.CounterValue,
float64(dst[0].UDPResponseSent),
"udp",
)
ch <- prometheus.MustNewConstMetric(
c.UnmatchedResponsesReceived,
prometheus.CounterValue,
float64(dst[0].UnmatchedResponsesReceived),
)
ch <- prometheus.MustNewConstMetric(
c.WinsQueries,
prometheus.CounterValue,
float64(dst[0].WINSLookupReceived),
"forward",
)
ch <- prometheus.MustNewConstMetric(
c.WinsQueries,
prometheus.CounterValue,
float64(dst[0].WINSReverseLookupReceived),
"reverse",
)
ch <- prometheus.MustNewConstMetric(
c.WinsResponses,
prometheus.CounterValue,
float64(dst[0].WINSResponseSent),
"forward",
)
ch <- prometheus.MustNewConstMetric(
c.WinsResponses,
prometheus.CounterValue,
float64(dst[0].WINSReverseResponseSent),
"reverse",
)
ch <- prometheus.MustNewConstMetric(
c.SecureUpdateFailures,
prometheus.CounterValue,
float64(dst[0].SecureUpdateFailure),
)
ch <- prometheus.MustNewConstMetric(
c.SecureUpdateReceived,
prometheus.CounterValue,
float64(dst[0].SecureUpdateReceived),
)
return nil, nil
}

View File

@@ -138,18 +138,18 @@ func mangleNetworkName(name string) string {
}
type Win32_PerfRawData_Tcpip_NetworkInterface struct {
BytesReceivedPerSec uint32
BytesSentPerSec uint32
BytesReceivedPerSec uint64
BytesSentPerSec uint64
BytesTotalPerSec uint64
Name string
PacketsOutboundDiscarded uint32
PacketsOutboundErrors uint32
PacketsPerSec uint32
PacketsReceivedDiscarded uint32
PacketsReceivedErrors uint32
PacketsReceivedPerSec uint32
PacketsReceivedUnknown uint32
PacketsSentPerSec uint32
PacketsOutboundDiscarded uint64
PacketsOutboundErrors uint64
PacketsPerSec uint64
PacketsReceivedDiscarded uint64
PacketsReceivedErrors uint64
PacketsReceivedPerSec uint64
PacketsReceivedUnknown uint64
PacketsSentPerSec uint64
}
func (c *NetworkCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {

115
collector/service.go Normal file
View File

@@ -0,0 +1,115 @@
// returns data points from Win32_Service
// https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx - Win32_Service class
package collector
import (
"log"
"strings"
"github.com/StackExchange/wmi"
"github.com/prometheus/client_golang/prometheus"
)
func init() {
Factories["service"] = NewserviceCollector
}
// A serviceCollector is a Prometheus collector for WMI Win32_Service metrics
type serviceCollector struct {
State *prometheus.Desc
StartMode *prometheus.Desc
}
// NewserviceCollector ...
func NewserviceCollector() (Collector, error) {
const subsystem = "service"
return &serviceCollector{
State: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "state"),
"The state of the service (State)",
[]string{"name", "state"},
nil,
),
StartMode: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "start_mode"),
"The start mode of the service (StartMode)",
[]string{"name", "start_mode"},
nil,
),
}, nil
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *serviceCollector) Collect(ch chan<- prometheus.Metric) error {
if desc, err := c.collect(ch); err != nil {
log.Println("[ERROR] failed collecting service metrics:", desc, err)
return err
}
return nil
}
type Win32_Service struct {
Name string
State string
StartMode string
}
var (
allStates = []string{
"stopped",
"start pending",
"stop pending",
"running",
"continue pending",
"pause pending",
"paused",
"unknown",
}
allStartModes = []string{
"boot",
"system",
"auto",
"manual",
"disabled",
}
)
func (c *serviceCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
var dst []Win32_Service
q := wmi.CreateQuery(&dst, "")
if err := wmi.Query(q, &dst); err != nil {
return nil, err
}
for _, service := range dst {
for _, state := range allStates {
isCurrentState := 0.0
if state == strings.ToLower(service.State) {
isCurrentState = 1.0
}
ch <- prometheus.MustNewConstMetric(
c.State,
prometheus.GaugeValue,
isCurrentState,
strings.ToLower(service.Name),
state,
)
}
for _, startMode := range allStartModes {
isCurrentStartMode := 0.0
if startMode == strings.ToLower(service.StartMode) {
isCurrentStartMode = 1.0
}
ch <- prometheus.MustNewConstMetric(
c.StartMode,
prometheus.GaugeValue,
isCurrentStartMode,
strings.ToLower(service.Name),
startMode,
)
}
}
return nil, nil
}

View File

@@ -1,4 +1,5 @@
// returns data points from Win32_PerfRawData_PerfOS_System class (undocumented)
// returns data points from Win32_PerfRawData_PerfOS_System class
// https://web.archive.org/web/20050830140516/http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_perfrawdata_perfos_system.asp
package collector
@@ -13,7 +14,7 @@ func init() {
Factories["system"] = NewSystemCollector
}
// A PerfOSCollector is a Prometheus collector for WMI metrics
// A SystemCollector is a Prometheus collector for WMI metrics
type SystemCollector struct {
ContextSwitchesTotal *prometheus.Desc
ExceptionDispatchesTotal *prometheus.Desc
@@ -54,7 +55,7 @@ func NewSystemCollector() (Collector, error) {
),
SystemUpTime: prometheus.NewDesc(
prometheus.BuildFQName(Namespace, subsystem, "system_up_time"),
"PerfOS_System.SystemUpTime",
"SystemUpTime/Frequency_Object",
nil,
nil,
),
@@ -80,10 +81,12 @@ func (c *SystemCollector) Collect(ch chan<- prometheus.Metric) error {
type Win32_PerfRawData_PerfOS_System struct {
ContextSwitchesPersec uint32
ExceptionDispatchesPersec uint32
Frequency_Object uint64
ProcessorQueueLength uint32
SystemCallsPersec uint32
SystemUpTime uint64
Threads uint32
Timestamp_Object uint64
}
func (c *SystemCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
@@ -91,6 +94,7 @@ func (c *SystemCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc
if err := wmi.Query(wmi.CreateQuery(&dst, ""), &dst); err != nil {
return nil, err
}
ch <- prometheus.MustNewConstMetric(
c.ContextSwitchesTotal,
prometheus.GaugeValue,
@@ -114,7 +118,8 @@ func (c *SystemCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc
ch <- prometheus.MustNewConstMetric(
c.SystemUpTime,
prometheus.GaugeValue,
float64(dst[0].SystemUpTime),
// convert from Windows timestamp (1 jan 1601) to unix timestamp (1 jan 1970)
float64(dst[0].SystemUpTime-116444736000000000)/float64(dst[0].Frequency_Object),
)
ch <- prometheus.MustNewConstMetric(
c.Threads,

View File

@@ -25,8 +25,9 @@ type WmiCollector struct {
}
const (
defaultCollectors = "cpu,cs,logical_disk,net,os,system"
serviceName = "wmi_exporter"
defaultCollectors = "cpu,cs,logical_disk,net,os,service,system"
defaultCollectorsPlaceholder = "[defaults]"
serviceName = "wmi_exporter"
)
var (
@@ -90,9 +91,27 @@ func execute(name string, c collector.Collector, ch chan<- prometheus.Metric) {
scrapeDurations.WithLabelValues(name, result).Observe(duration.Seconds())
}
func expandEnabledCollectors(enabled string) []string {
expanded := strings.Replace(enabled, defaultCollectorsPlaceholder, defaultCollectors, -1)
separated := strings.Split(expanded, ",")
unique := map[string]bool{}
for _, s := range separated {
if s != "" {
unique[s] = true
}
}
result := make([]string, 0, len(unique))
for s, _ := range unique {
result = append(result, s)
}
return result
}
func loadCollectors(list string) (map[string]collector.Collector, error) {
collectors := map[string]collector.Collector{}
for _, name := range strings.Split(list, ",") {
enabled := expandEnabledCollectors(list)
for _, name := range enabled {
fn, ok := collector.Factories[name]
if !ok {
return nil, fmt.Errorf("collector '%s' not available", name)
@@ -115,7 +134,7 @@ func main() {
showVersion = flag.Bool("version", false, "Print version information.")
listenAddress = flag.String("telemetry.addr", ":9182", "host:port for WMI exporter.")
metricsPath = flag.String("telemetry.path", "/metrics", "URL path for surfacing collected metrics.")
enabledCollectors = flag.String("collectors.enabled", filterAvailableCollectors(defaultCollectors), "Comma-separated list of collectors to use.")
enabledCollectors = flag.String("collectors.enabled", filterAvailableCollectors(defaultCollectors), "Comma-separated list of collectors to use. Use '[default]' as a placeholder for all the collectors enabled by default")
printCollectors = flag.Bool("collectors.print", false, "If true, print available collectors and exit.")
)
flag.Parse()

49
exporter_test.go Normal file
View File

@@ -0,0 +1,49 @@
package main
import (
"sort"
"strings"
"testing"
)
type expansionTestCase struct {
input string
expectedOutput []string
}
func TestExpandEnabled(t *testing.T) {
expansionTests := []expansionTestCase{
{"", []string{}},
// Default case
{"cs,os", []string{"cs", "os"}},
// Placeholder expansion
{defaultCollectorsPlaceholder, strings.Split(defaultCollectors, ",")},
// De-duplication
{"cs,cs", []string{"cs"}},
// De-duplicate placeholder
{defaultCollectorsPlaceholder + "," + defaultCollectorsPlaceholder, strings.Split(defaultCollectors, ",")},
// Composite case
{"foo," + defaultCollectorsPlaceholder + ",bar", append(strings.Split(defaultCollectors, ","), "foo", "bar")},
}
for _, testCase := range expansionTests {
output := expandEnabledCollectors(testCase.input)
sort.Strings(output)
success := true
if len(output) != len(testCase.expectedOutput) {
success = false
} else {
sort.Strings(testCase.expectedOutput)
for idx := range output {
if output[idx] != testCase.expectedOutput[idx] {
success = false
break
}
}
}
if !success {
t.Error("For", testCase.input, "expected", testCase.expectedOutput, "got", output)
}
}
}

View File

@@ -45,7 +45,7 @@ mkdir -Force Work,Output | Out-Null
Write-Verbose "Downloading files"
# Somewhat obscure url, points to WiX 3.10 binary release
Write-Verbose "Downloading WiX..."
Get-FileIfNotExists "http://download-codeplex.sec.s-msft.com/Download/Release?ProjectName=wix&DownloadId=1504735&FileTime=130906491728530000&Build=21031" "$sourceDir\wix-binaries.zip"
Get-FileIfNotExists "http://download-codeplex.sec.s-msft.com/Download/Release?ProjectName=wix&DownloadId=1587180&FileTime=131118854877130000&Build=21046" "$sourceDir\wix-binaries.zip"
mkdir -Force WiX | Out-Null
Expand-Archive -Path "${sourceDir}\wix-binaries.zip" -DestinationPath WiX -Force
@@ -58,4 +58,4 @@ Invoke-Expression "WiX\candle.exe -nologo -arch $wixArch $wixOpts -out Work\wmi_
Invoke-Expression "WiX\light.exe -nologo -spdb $wixOpts -out `"Output\wmi_exporter-${Version}-${Arch}.msi`" Work\wmi_exporter.wixobj"
Write-Verbose "Done!"
Pop-Location
Pop-Location

View File

@@ -2,9 +2,22 @@ Param(
[Parameter(Mandatory=$true)]
$Class,
[Parameter(Mandatory=$false)]
$CollectorName = ($Class -replace 'Win32_PerfRawData_Perf','')
$CollectorName = ($Class -replace 'Win32_PerfRawData_Perf',''),
[Parameter(Mandatory=$false)]
$ComputerName = "localhost",
[Parameter(Mandatory=$false)]
$Credential
)
$members = Get-WMIObject $Class `
$ErrorActionPreference = "Stop"
if($Credential -ne $null) {
$wmiObject = Get-WMIObject -ComputerName $ComputerName -Credential $Credential -Class $Class
}
else {
$wmiObject = Get-WMIObject -ComputerName $ComputerName -Class $Class
}
$members = $wmiObject `
| Get-Member -MemberType Properties `
| Where-Object { $_.Definition -Match '^u?int' -and $_.Name -NotMatch '_' } `
| Select-Object Name, @{Name="Type";Expression={$_.Definition.Split(" ")[0]}}