make enabled collectors configurable (based on code from node_exporter)

This commit is contained in:
Martin Lindhe
2016-09-01 16:04:43 +02:00
parent 2af46d9313
commit d8f62e07c2
5 changed files with 206 additions and 131 deletions

View File

@@ -13,6 +13,10 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
func init() {
Factories["iis"] = NewIISCollector
}
var ( var (
siteWhitelist = flag.String("collector.iis.site-whitelist", ".+", "Regexp of sites to whitelist. Site name must both match whitelist and not match blacklist to be included.") siteWhitelist = flag.String("collector.iis.site-whitelist", ".+", "Regexp of sites to whitelist. Site name must both match whitelist and not match blacklist to be included.")
siteBlacklist = flag.String("collector.iis.site-blacklist", "", "Regexp of sites to blacklist. Site name must both match whitelist and not match blacklist to be included.") siteBlacklist = flag.String("collector.iis.site-blacklist", "", "Regexp of sites to blacklist. Site name must both match whitelist and not match blacklist to be included.")
@@ -48,43 +52,43 @@ type IISCollector struct {
} }
// NewIISCollector ... // NewIISCollector ...
func NewIISCollector() *IISCollector { func NewIISCollector() (Collector, error) {
const subsystem = "iis" const subsystem = "iis"
return &IISCollector{ return &IISCollector{
// Gauges // Gauges
CurrentAnonymousUsers: prometheus.NewDesc( CurrentAnonymousUsers: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "current_anonymous_users"), prometheus.BuildFQName(Namespace, subsystem, "current_anonymous_users"),
"Number of users who currently have an anonymous connection using the Web service (WebService.CurrentAnonymousUsers)", "Number of users who currently have an anonymous connection using the Web service (WebService.CurrentAnonymousUsers)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
CurrentBlockedAsyncIORequests: prometheus.NewDesc( CurrentBlockedAsyncIORequests: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "current_blocked_async_io_requests"), prometheus.BuildFQName(Namespace, subsystem, "current_blocked_async_io_requests"),
"Current requests temporarily blocked due to bandwidth throttling settings (WebService.CurrentBlockedAsyncIORequests)", "Current requests temporarily blocked due to bandwidth throttling settings (WebService.CurrentBlockedAsyncIORequests)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
CurrentCGIRequests: prometheus.NewDesc( CurrentCGIRequests: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "current_cgi_requests"), prometheus.BuildFQName(Namespace, subsystem, "current_cgi_requests"),
"Current number of CGI requests being simultaneously processed by the Web service (WebService.CurrentCGIRequests)", "Current number of CGI requests being simultaneously processed by the Web service (WebService.CurrentCGIRequests)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
CurrentConnections: prometheus.NewDesc( CurrentConnections: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "current_connections"), prometheus.BuildFQName(Namespace, subsystem, "current_connections"),
"Current number of connections established with the Web service (WebService.CurrentConnections)", "Current number of connections established with the Web service (WebService.CurrentConnections)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
CurrentISAPIExtensionRequests: prometheus.NewDesc( CurrentISAPIExtensionRequests: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "current_isapi_extension_requests"), prometheus.BuildFQName(Namespace, subsystem, "current_isapi_extension_requests"),
"Current number of ISAPI requests being simultaneously processed by the Web service (WebService.CurrentISAPIExtensionRequests)", "Current number of ISAPI requests being simultaneously processed by the Web service (WebService.CurrentISAPIExtensionRequests)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
CurrentNonAnonymousUsers: prometheus.NewDesc( CurrentNonAnonymousUsers: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "current_non_anonymous_users"), prometheus.BuildFQName(Namespace, subsystem, "current_non_anonymous_users"),
"Number of users who currently have a non-anonymous connection using the Web service (WebService.CurrentNonAnonymousUsers)", "Number of users who currently have a non-anonymous connection using the Web service (WebService.CurrentNonAnonymousUsers)",
[]string{"site"}, []string{"site"},
nil, nil,
@@ -92,91 +96,91 @@ func NewIISCollector() *IISCollector {
// Counters // Counters
TotalBytesReceived: prometheus.NewDesc( TotalBytesReceived: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "received_bytes_total"), prometheus.BuildFQName(Namespace, subsystem, "received_bytes_total"),
"Number of data bytes that have been received by the Web service (WebService.TotalBytesReceived)", "Number of data bytes that have been received by the Web service (WebService.TotalBytesReceived)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalBytesSent: prometheus.NewDesc( TotalBytesSent: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "sent_bytes_total"), prometheus.BuildFQName(Namespace, subsystem, "sent_bytes_total"),
"Number of data bytes that have been sent by the Web service (WebService.TotalBytesSent)", "Number of data bytes that have been sent by the Web service (WebService.TotalBytesSent)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalAnonymousUsers: prometheus.NewDesc( TotalAnonymousUsers: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "anonymous_users_total"), prometheus.BuildFQName(Namespace, subsystem, "anonymous_users_total"),
"Total number of users who established an anonymous connection with the Web service (WebService.TotalAnonymousUsers)", "Total number of users who established an anonymous connection with the Web service (WebService.TotalAnonymousUsers)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalBlockedAsyncIORequests: prometheus.NewDesc( TotalBlockedAsyncIORequests: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "blocked_async_io_requests_total"), prometheus.BuildFQName(Namespace, subsystem, "blocked_async_io_requests_total"),
"Total requests temporarily blocked due to bandwidth throttling settings (WebService.TotalBlockedAsyncIORequests)", "Total requests temporarily blocked due to bandwidth throttling settings (WebService.TotalBlockedAsyncIORequests)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalCGIRequests: prometheus.NewDesc( TotalCGIRequests: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "cgi_requests_total"), prometheus.BuildFQName(Namespace, subsystem, "cgi_requests_total"),
"Total CGI requests is the total number of CGI requests (WebService.TotalCGIRequests)", "Total CGI requests is the total number of CGI requests (WebService.TotalCGIRequests)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalConnectionAttemptsAllInstances: prometheus.NewDesc( TotalConnectionAttemptsAllInstances: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "connection_attempts_all_instances_total"), prometheus.BuildFQName(Namespace, subsystem, "connection_attempts_all_instances_total"),
"Number of connections that have been attempted using the Web service (WebService.TotalConnectionAttemptsAllInstances)", "Number of connections that have been attempted using the Web service (WebService.TotalConnectionAttemptsAllInstances)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalRequests: prometheus.NewDesc( TotalRequests: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "requests_total"), prometheus.BuildFQName(Namespace, subsystem, "requests_total"),
"Number of HTTP requests (WebService.TotalRequests)", "Number of HTTP requests (WebService.TotalRequests)",
[]string{"site", "method"}, []string{"site", "method"},
nil, nil,
), ),
TotalFilesReceived: prometheus.NewDesc( TotalFilesReceived: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "files_received_total"), prometheus.BuildFQName(Namespace, subsystem, "files_received_total"),
"Number of files received by the Web service (WebService.TotalFilesReceived)", "Number of files received by the Web service (WebService.TotalFilesReceived)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalFilesSent: prometheus.NewDesc( TotalFilesSent: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "files_sent_total"), prometheus.BuildFQName(Namespace, subsystem, "files_sent_total"),
"Number of files sent by the Web service (WebService.TotalFilesSent)", "Number of files sent by the Web service (WebService.TotalFilesSent)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalISAPIExtensionRequests: prometheus.NewDesc( TotalISAPIExtensionRequests: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "ipapi_extension_requests_total"), prometheus.BuildFQName(Namespace, subsystem, "ipapi_extension_requests_total"),
"ISAPI Extension Requests received (WebService.TotalISAPIExtensionRequests)", "ISAPI Extension Requests received (WebService.TotalISAPIExtensionRequests)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalLockedErrors: prometheus.NewDesc( TotalLockedErrors: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "locked_errors_total"), prometheus.BuildFQName(Namespace, subsystem, "locked_errors_total"),
"Number of requests that couldn't be satisfied by the server because the requested resource was locked (WebService.TotalLockedErrors)", "Number of requests that couldn't be satisfied by the server because the requested resource was locked (WebService.TotalLockedErrors)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalLogonAttempts: prometheus.NewDesc( TotalLogonAttempts: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "logon_attempts_total"), prometheus.BuildFQName(Namespace, subsystem, "logon_attempts_total"),
"Number of logons attempts to the Web Service (WebService.TotalLogonAttempts)", "Number of logons attempts to the Web Service (WebService.TotalLogonAttempts)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalNonAnonymousUsers: prometheus.NewDesc( TotalNonAnonymousUsers: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "non_anonymous_users_total"), prometheus.BuildFQName(Namespace, subsystem, "non_anonymous_users_total"),
"Number of users who established a non-anonymous connection with the Web service (WebService.TotalNonAnonymousUsers)", "Number of users who established a non-anonymous connection with the Web service (WebService.TotalNonAnonymousUsers)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalNotFoundErrors: prometheus.NewDesc( TotalNotFoundErrors: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "not_found_errors_total"), prometheus.BuildFQName(Namespace, subsystem, "not_found_errors_total"),
"Number of requests that couldn't be satisfied by the server because the requested document could not be found (WebService.TotalNotFoundErrors)", "Number of requests that couldn't be satisfied by the server because the requested document could not be found (WebService.TotalNotFoundErrors)",
[]string{"site"}, []string{"site"},
nil, nil,
), ),
TotalRejectedAsyncIORequests: prometheus.NewDesc( TotalRejectedAsyncIORequests: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "rejected_async_io_requests_total"), prometheus.BuildFQName(Namespace, subsystem, "rejected_async_io_requests_total"),
"Requests rejected due to bandwidth throttling settings (WebService.TotalRejectedAsyncIORequests)", "Requests rejected due to bandwidth throttling settings (WebService.TotalRejectedAsyncIORequests)",
[]string{"site"}, []string{"site"},
nil, nil,
@@ -184,22 +188,17 @@ func NewIISCollector() *IISCollector {
siteWhitelistPattern: regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *siteWhitelist)), siteWhitelistPattern: regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *siteWhitelist)),
siteBlacklistPattern: regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *siteBlacklist)), siteBlacklistPattern: regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *siteBlacklist)),
} }, nil
} }
// 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) { func (c *IISCollector) Collect(ch chan<- prometheus.Metric) error {
if desc, err := c.collect(ch); err != nil { if desc, err := c.collect(ch); err != nil {
log.Println("[ERROR] failed collecting iis metrics:", desc, err) log.Println("[ERROR] failed collecting iis metrics:", desc, err)
return return err
} }
} return nil
// Describe sends the descriptors of each metric over to the provided channel.
// The corresponding metric values are sent separately.
func (c *IISCollector) Describe(ch chan<- *prometheus.Desc) {
} }
type Win32_PerfRawData_W3SVC_WebService struct { type Win32_PerfRawData_W3SVC_WebService struct {

View File

@@ -14,6 +14,10 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
func init() {
Factories["logical_disk"] = NewLogicalDiskCollector
}
const ( const (
ticksToSecondsScaleFactor = 1 / 1e7 ticksToSecondsScaleFactor = 1 / 1e7
) )
@@ -42,82 +46,82 @@ type LogicalDiskCollector struct {
} }
// NewLogicalDiskCollector ... // NewLogicalDiskCollector ...
func NewLogicalDiskCollector() *LogicalDiskCollector { func NewLogicalDiskCollector() (Collector, error) {
const subsystem = "logical_disk" const subsystem = "logical_disk"
return &LogicalDiskCollector{ return &LogicalDiskCollector{
RequestsQueued: prometheus.NewDesc( RequestsQueued: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "requests_queued"), prometheus.BuildFQName(Namespace, subsystem, "requests_queued"),
"The number of requests queued to the disk (LogicalDisk.CurrentDiskQueueLength)", "The number of requests queued to the disk (LogicalDisk.CurrentDiskQueueLength)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
ReadBytesTotal: prometheus.NewDesc( ReadBytesTotal: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "read_bytes_total"), prometheus.BuildFQName(Namespace, subsystem, "read_bytes_total"),
"The number of bytes transferred from the disk during read operations (LogicalDisk.DiskReadBytesPerSec)", "The number of bytes transferred from the disk during read operations (LogicalDisk.DiskReadBytesPerSec)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
ReadsTotal: prometheus.NewDesc( ReadsTotal: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "reads_total"), prometheus.BuildFQName(Namespace, subsystem, "reads_total"),
"The number of read operations on the disk (LogicalDisk.DiskReadsPerSec)", "The number of read operations on the disk (LogicalDisk.DiskReadsPerSec)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
WriteBytesTotal: prometheus.NewDesc( WriteBytesTotal: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "write_bytes_total"), prometheus.BuildFQName(Namespace, subsystem, "write_bytes_total"),
"The number of bytes transferred to the disk during write operations (LogicalDisk.DiskWriteBytesPerSec)", "The number of bytes transferred to the disk during write operations (LogicalDisk.DiskWriteBytesPerSec)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
WritesTotal: prometheus.NewDesc( WritesTotal: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "writes_total"), prometheus.BuildFQName(Namespace, subsystem, "writes_total"),
"The number of write operations on the disk (LogicalDisk.DiskWritesPerSec)", "The number of write operations on the disk (LogicalDisk.DiskWritesPerSec)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
ReadTime: prometheus.NewDesc( ReadTime: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "read_seconds_total"), prometheus.BuildFQName(Namespace, subsystem, "read_seconds_total"),
"Seconds that the disk was busy servicing read requests (LogicalDisk.PercentDiskReadTime)", "Seconds that the disk was busy servicing read requests (LogicalDisk.PercentDiskReadTime)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
WriteTime: prometheus.NewDesc( WriteTime: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "write_seconds_total"), prometheus.BuildFQName(Namespace, subsystem, "write_seconds_total"),
"Seconds that the disk was busy servicing write requests (LogicalDisk.PercentDiskWriteTime)", "Seconds that the disk was busy servicing write requests (LogicalDisk.PercentDiskWriteTime)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
FreeSpace: prometheus.NewDesc( FreeSpace: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "free_bytes"), prometheus.BuildFQName(Namespace, subsystem, "free_bytes"),
"Free space in bytes (LogicalDisk.PercentFreeSpace)", "Free space in bytes (LogicalDisk.PercentFreeSpace)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
TotalSpace: prometheus.NewDesc( TotalSpace: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "size_bytes"), prometheus.BuildFQName(Namespace, subsystem, "size_bytes"),
"Total space in bytes (LogicalDisk.PercentFreeSpace_Base)", "Total space in bytes (LogicalDisk.PercentFreeSpace_Base)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
IdleTime: prometheus.NewDesc( IdleTime: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "idle_seconds_total"), prometheus.BuildFQName(Namespace, subsystem, "idle_seconds_total"),
"Seconds that the disk was idle (LogicalDisk.PercentIdleTime)", "Seconds that the disk was idle (LogicalDisk.PercentIdleTime)",
[]string{"volume"}, []string{"volume"},
nil, nil,
), ),
SplitIOs: prometheus.NewDesc( SplitIOs: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, subsystem, "split_ios_total"), prometheus.BuildFQName(Namespace, subsystem, "split_ios_total"),
"The number of I/Os to the disk were split into multiple I/Os (LogicalDisk.SplitIOPerSec)", "The number of I/Os to the disk were split into multiple I/Os (LogicalDisk.SplitIOPerSec)",
[]string{"volume"}, []string{"volume"},
nil, nil,
@@ -125,33 +129,17 @@ func NewLogicalDiskCollector() *LogicalDiskCollector {
volumeWhitelistPattern: regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *volumeWhitelist)), volumeWhitelistPattern: regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *volumeWhitelist)),
volumeBlacklistPattern: regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *volumeBlacklist)), volumeBlacklistPattern: regexp.MustCompile(fmt.Sprintf("^(?:%s)$", *volumeBlacklist)),
} }, nil
} }
// 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) { func (c *LogicalDiskCollector) Collect(ch chan<- prometheus.Metric) error {
if desc, err := c.collect(ch); err != nil { if desc, err := c.collect(ch); err != nil {
log.Println("[ERROR] failed collecting logical_disk metrics:", desc, err) log.Println("[ERROR] failed collecting logical_disk metrics:", desc, err)
return return err
} }
} return nil
// Describe sends the descriptors of each metric over to the provided channel.
// The corresponding metric values are sent separately.
func (c *LogicalDiskCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.RequestsQueued
ch <- c.ReadBytesTotal
ch <- c.ReadsTotal
ch <- c.WriteBytesTotal
ch <- c.WritesTotal
ch <- c.ReadTime
ch <- c.WriteTime
ch <- c.FreeSpace
ch <- c.TotalSpace
ch <- c.IdleTime
ch <- c.SplitIOs
} }
type Win32_PerfRawData_PerfDisk_LogicalDisk struct { type Win32_PerfRawData_PerfDisk_LogicalDisk struct {

View File

@@ -10,6 +10,10 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
func init() {
Factories["os"] = NewOSCollector
}
// A OSCollector is a Prometheus collector for WMI Win32_OperatingSystem metrics // A OSCollector is a Prometheus collector for WMI Win32_OperatingSystem metrics
type OSCollector struct { type OSCollector struct {
PhysicalMemoryFreeBytes *prometheus.Desc PhysicalMemoryFreeBytes *prometheus.Desc
@@ -25,105 +29,92 @@ type OSCollector struct {
} }
// NewOSCollector ... // NewOSCollector ...
func NewOSCollector() *OSCollector { func NewOSCollector() (Collector, error) {
const subsystem = "os"
return &OSCollector{ return &OSCollector{
PagingMaxBytes: prometheus.NewDesc( PagingMaxBytes: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "paging_max_bytes"), prometheus.BuildFQName(Namespace, subsystem, "paging_max_bytes"),
"SizeStoredInPagingFiles", "SizeStoredInPagingFiles",
nil, nil,
nil, nil,
), ),
PagingFreeBytes: prometheus.NewDesc( PagingFreeBytes: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "paging_free_bytes"), prometheus.BuildFQName(Namespace, subsystem, "paging_free_bytes"),
"FreeSpaceInPagingFiles", "FreeSpaceInPagingFiles",
nil, nil,
nil, nil,
), ),
PhysicalMemoryFreeBytes: prometheus.NewDesc( PhysicalMemoryFreeBytes: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "physical_memory_free_bytes"), prometheus.BuildFQName(Namespace, subsystem, "physical_memory_free_bytes"),
"FreePhysicalMemory", "FreePhysicalMemory",
nil, nil,
nil, nil,
), ),
Processes: prometheus.NewDesc( Processes: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "processes"), prometheus.BuildFQName(Namespace, subsystem, "processes"),
"NumberOfProcesses", "NumberOfProcesses",
nil, nil,
nil, nil,
), ),
ProcessesMax: prometheus.NewDesc( ProcessesMax: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "processes_max"), prometheus.BuildFQName(Namespace, subsystem, "processes_max"),
"MaxNumberOfProcesses", "MaxNumberOfProcesses",
nil, nil,
nil, nil,
), ),
ProcessMemoryMaxBytes: prometheus.NewDesc( ProcessMemoryMaxBytes: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "process_memory_max_bytes"), prometheus.BuildFQName(Namespace, subsystem, "process_memory_max_bytes"),
"MaxProcessMemorySize", "MaxProcessMemorySize",
nil, nil,
nil, nil,
), ),
Users: prometheus.NewDesc( Users: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "users"), prometheus.BuildFQName(Namespace, subsystem, "users"),
"NumberOfUsers", "NumberOfUsers",
nil, nil,
nil, nil,
), ),
VirtualMemoryBytes: prometheus.NewDesc( VirtualMemoryBytes: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "virtual_memory_bytes"), prometheus.BuildFQName(Namespace, subsystem, "virtual_memory_bytes"),
"TotalVirtualMemorySize", "TotalVirtualMemorySize",
nil, nil,
nil, nil,
), ),
VisibleMemoryBytes: prometheus.NewDesc( VisibleMemoryBytes: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "visible_memory_bytes"), prometheus.BuildFQName(Namespace, subsystem, "visible_memory_bytes"),
"TotalVisibleMemorySize", "TotalVisibleMemorySize",
nil, nil,
nil, nil,
), ),
VirtualMemoryFreeBytes: prometheus.NewDesc( VirtualMemoryFreeBytes: prometheus.NewDesc(
prometheus.BuildFQName(wmiNamespace, "os", "virtual_memory_free_bytes"), prometheus.BuildFQName(Namespace, subsystem, "virtual_memory_free_bytes"),
"FreeVirtualMemory", "FreeVirtualMemory",
nil, nil,
nil, nil,
), ),
} }, nil
} }
// 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) { func (c *OSCollector) Collect(ch chan<- prometheus.Metric) error {
if desc, err := c.collect(ch); err != nil { if desc, err := c.collect(ch); err != nil {
log.Println("[ERROR] failed collecting os metrics:", desc, err) log.Println("[ERROR] failed collecting os metrics:", desc, err)
return return err
} }
} return nil
// Describe sends the descriptors of each metric over to the provided channel.
// The corresponding metric values are sent separately.
func (c *OSCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.PhysicalMemoryFreeBytes
ch <- c.PagingFreeBytes
ch <- c.VirtualMemoryFreeBytes
ch <- c.ProcessesMax
ch <- c.ProcessMemoryMaxBytes
ch <- c.Processes
ch <- c.Users
ch <- c.PagingMaxBytes
ch <- c.VirtualMemoryBytes
ch <- c.VisibleMemoryBytes
} }
type Win32_OperatingSystem struct { type Win32_OperatingSystem struct {

View File

@@ -1,5 +1,17 @@
package collector package collector
import "github.com/prometheus/client_golang/prometheus"
// ...
const ( const (
wmiNamespace = "wmi" Namespace = "wmi"
) )
// 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)
}

View File

@@ -2,76 +2,161 @@ package main
import ( import (
"flag" "flag"
"log" "fmt"
"net/http" "net/http"
"os"
"sort"
"strings"
"sync" "sync"
"time"
"github.com/martinlindhe/wmi_exporter/collector" "github.com/martinlindhe/wmi_exporter/collector"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log"
"github.com/prometheus/common/version"
) )
// WmiExporter wraps all the WMI collectors and provides a single global // WmiCollector implements the prometheus.Collector interface.
// exporter to extracts metrics out of. It also ensures that the collection type WmiCollector struct {
// is done in a thread-safe manner, the necessary requirement stated by collectors map[string]collector.Collector
// prometheus. It also implements a prometheus.Collector interface in order
// to register it correctly.
type WmiExporter struct {
mu sync.Mutex
collectors []prometheus.Collector
} }
// Verify that the WmiExporter implements the prometheus.Collector interface. const (
var _ prometheus.Collector = &WmiExporter{} defaultCollectors = "logical_disk,os"
)
// NewWmiExporter creates an instance to WmiExporter and returns a reference var (
// to it. We can choose to enable a collector to extract stats out of by adding scrapeDurations = prometheus.NewSummaryVec(
// it to the list of collectors. prometheus.SummaryOpts{
func NewWmiExporter() *WmiExporter { Namespace: collector.Namespace,
return &WmiExporter{ Subsystem: "exporter",
collectors: []prometheus.Collector{ Name: "scrape_duration_seconds",
collector.NewOSCollector(), Help: "wmi_exporter: Duration of a scrape job.",
collector.NewLogicalDiskCollector(),
collector.NewIISCollector(),
}, },
} []string{"collector", "result"},
} )
)
// Describe sends all the descriptors of the collectors included to // Describe sends all the descriptors of the collectors included to
// the provided channel. // the provided channel.
func (c *WmiExporter) Describe(ch chan<- *prometheus.Desc) { func (coll WmiCollector) Describe(ch chan<- *prometheus.Desc) {
for _, cc := range c.collectors { scrapeDurations.Describe(ch)
cc.Describe(ch)
}
} }
// 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. Collect could be called several times concurrently
// and thus its run is protected by a single mutex. // and thus its run is protected by a single mutex.
func (c *WmiExporter) Collect(ch chan<- prometheus.Metric) { func (coll WmiCollector) Collect(ch chan<- prometheus.Metric) {
c.mu.Lock() wg := sync.WaitGroup{}
defer c.mu.Unlock() wg.Add(len(coll.collectors))
for name, c := range coll.collectors {
for _, cc := range c.collectors { go func(name string, c collector.Collector) {
cc.Collect(ch) execute(name, c, ch)
wg.Done()
}(name, c)
} }
wg.Wait()
scrapeDurations.Collect(ch)
}
func filterAvailableCollectors(collectors string) string {
var availableCollectors []string
for _, c := range strings.Split(collectors, ",") {
_, ok := collector.Factories[c]
if ok {
availableCollectors = append(availableCollectors, c)
}
}
return strings.Join(availableCollectors, ",")
}
func execute(name string, c collector.Collector, ch chan<- prometheus.Metric) {
begin := time.Now()
err := c.Collect(ch)
duration := time.Since(begin)
var result string
if err != nil {
log.Errorf("ERROR: %s collector failed after %fs: %s", name, duration.Seconds(), err)
result = "error"
} else {
log.Debugf("OK: %s collector succeeded after %fs.", name, duration.Seconds())
result = "success"
}
scrapeDurations.WithLabelValues(name, result).Observe(duration.Seconds())
}
func loadCollectors(list string) (map[string]collector.Collector, error) {
collectors := map[string]collector.Collector{}
for _, name := range strings.Split(list, ",") {
fn, ok := collector.Factories[name]
if !ok {
return nil, fmt.Errorf("collector '%s' not available", name)
}
c, err := fn()
if err != nil {
return nil, err
}
collectors[name] = c
}
return collectors, nil
}
func init() {
prometheus.MustRegister(version.NewCollector("wmi_exporter"))
} }
func main() { func main() {
var ( var (
addr = flag.String("telemetry.addr", ":9182", "host:port for WMI exporter") showVersion = flag.Bool("version", false, "Print version information.")
metricsPath = flag.String("telemetry.path", "/metrics", "URL path for surfacing collected metrics") 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.")
printCollectors = flag.Bool("collectors.print", false, "If true, print available collectors and exit.")
) )
flag.Parse() flag.Parse()
prometheus.MustRegister(NewWmiExporter()) if *showVersion {
fmt.Fprintln(os.Stdout, version.Print("wmi_exporter"))
os.Exit(0)
}
if *printCollectors {
collectorNames := make(sort.StringSlice, 0, len(collector.Factories))
for n := range collector.Factories {
collectorNames = append(collectorNames, n)
}
collectorNames.Sort()
fmt.Printf("Available collectors:\n")
for _, n := range collectorNames {
fmt.Printf(" - %s\n", n)
}
return
}
collectors, err := loadCollectors(*enabledCollectors)
if err != nil {
log.Fatalf("Couldn't load collectors: %s", err)
}
log.Infof("Enabled collectors:")
for n := range collectors {
log.Infof(" - %s", n)
}
nodeCollector := WmiCollector{collectors: collectors}
prometheus.MustRegister(nodeCollector)
http.Handle(*metricsPath, prometheus.Handler()) http.Handle(*metricsPath, prometheus.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, *metricsPath, http.StatusMovedPermanently) http.Redirect(w, r, *metricsPath, http.StatusMovedPermanently)
}) })
log.Printf("Starting WMI exporter on %q", *addr) log.Infoln("Starting WMI exporter", version.Info())
if err := http.ListenAndServe(*addr, nil); err != nil { log.Infoln("Build context", version.BuildContext())
log.Infoln("Listening on", *listenAddress)
if err := http.ListenAndServe(*listenAddress, nil); err != nil {
log.Fatalf("cannot start WMI exporter: %s", err) log.Fatalf("cannot start WMI exporter: %s", err)
} }
} }