Compare commits

...

15 Commits

Author SHA1 Message Date
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
8 changed files with 227 additions and 21 deletions

View File

@@ -16,6 +16,7 @@ iis | [Win32_PerfRawData_W3SVC_WebService](https://msdn.microsoft.com/en-us/libr
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.

View File

@@ -4,12 +4,17 @@ 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
@@ -19,17 +24,21 @@ build_script:
- 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

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

@@ -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=1504735&FileTime=130906491728530000&Build=21040" "$sourceDir\wix-binaries.zip"
mkdir -Force WiX | Out-Null
Expand-Archive -Path "${sourceDir}\wix-binaries.zip" -DestinationPath WiX -Force

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]}}