Conditional query for wmi fields added in IIS 8

This commit is contained in:
Calle Pettersson
2017-07-15 13:56:09 +01:00
parent e8cfeef26c
commit f4195aa435
2 changed files with 180 additions and 90 deletions

View File

@@ -9,15 +9,50 @@ package collector
import ( import (
"flag" "flag"
"fmt" "fmt"
"log"
"regexp" "regexp"
"golang.org/x/sys/windows/registry"
"github.com/StackExchange/wmi" "github.com/StackExchange/wmi"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log"
) )
func init() { func init() {
Factories["iis"] = NewIISCollector Factories["iis"] = NewIISCollector
iis_version = getIISVersion()
}
type simple_version struct {
major uint64
minor uint64
}
func getIISVersion() simple_version {
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\InetStp\`, registry.QUERY_VALUE)
if err != nil {
log.Warnf("Couldn't open registry to determine IIS version: %v\n", err)
return simple_version{}
}
defer k.Close()
major, _, err := k.GetIntegerValue("MajorVersion")
if err != nil {
log.Warnf("Couldn't open registry to determine IIS version: %v\n", err)
return simple_version{}
}
minor, _, err := k.GetIntegerValue("MinorVersion")
if err != nil {
log.Warnf("Couldn't open registry to determine IIS version: %v\n", err)
return simple_version{}
}
log.Debugf("Detected IIS %d.%d\n", major, minor)
return simple_version{
major: major,
minor: minor,
}
} }
var ( var (
@@ -25,6 +60,8 @@ var (
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.")
appWhitelist = flag.String("collector.iis.app-whitelist", ".+", "Regexp of apps to whitelist. App name must both match whitelist and not match blacklist to be included.") appWhitelist = flag.String("collector.iis.app-whitelist", ".+", "Regexp of apps to whitelist. App name must both match whitelist and not match blacklist to be included.")
appBlacklist = flag.String("collector.iis.app-blacklist", "", "Regexp of apps to blacklist. App name must both match whitelist and not match blacklist to be included.") appBlacklist = flag.String("collector.iis.app-blacklist", "", "Regexp of apps to blacklist. App name must both match whitelist and not match blacklist to be included.")
iis_version = simple_version{}
) )
type IISCollector struct { type IISCollector struct {
@@ -778,7 +815,7 @@ func NewIISCollector() (Collector, error) {
// 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(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.Errorf("[ERROR] failed collecting iis metrics:", desc, err)
return err return err
} }
return nil return nil
@@ -851,41 +888,45 @@ type Win32_PerfRawData_APPPOOLCountersProvider_APPPOOLWAS struct {
type Win32_PerfRawData_W3SVCW3WPCounterProvider_W3SVCW3WP struct { type Win32_PerfRawData_W3SVCW3WPCounterProvider_W3SVCW3WP struct {
Name string Name string
ActiveFlushedEntries uint64 ActiveFlushedEntries uint64
CurrentFileCacheMemoryUsage uint64 CurrentFileCacheMemoryUsage uint64
CurrentFilesCached uint64 CurrentFilesCached uint64
CurrentMetadataCached uint64 CurrentMetadataCached uint64
CurrentURIsCached uint64 CurrentURIsCached uint64
FileCacheFlushes uint64 FileCacheFlushes uint64
FileCacheHits uint64 FileCacheHits uint64
FileCacheMisses uint64 FileCacheMisses uint64
MaximumFileCacheMemoryUsage uint64 MaximumFileCacheMemoryUsage uint64
MetadataCacheFlushes uint64 MetadataCacheFlushes uint64
MetadataCacheHits uint64 MetadataCacheHits uint64
MetadataCacheMisses uint64 MetadataCacheMisses uint64
OutputCacheCurrentFlushedItems uint64 OutputCacheCurrentFlushedItems uint64
OutputCacheCurrentItems uint64 OutputCacheCurrentItems uint64
OutputCacheCurrentMemoryUsage uint64 OutputCacheCurrentMemoryUsage uint64
OutputCacheHitsPersec uint64 OutputCacheHitsPersec uint64
OutputCacheMissesPersec uint64 OutputCacheMissesPersec uint64
OutputCacheTotalFlushedItems uint64 OutputCacheTotalFlushedItems uint64
OutputCacheTotalFlushes uint64 OutputCacheTotalFlushes uint64
OutputCacheTotalHits uint64 OutputCacheTotalHits uint64
OutputCacheTotalMisses uint64 OutputCacheTotalMisses uint64
TotalFilesCached uint64 TotalFilesCached uint64
TotalFlushedFiles uint64 TotalFlushedFiles uint64
TotalFlushedMetadata uint64 TotalFlushedMetadata uint64
TotalFlushedURIs uint64 TotalFlushedURIs uint64
TotalMetadataCached uint64 TotalMetadataCached uint64
TotalURIsCached uint64 TotalURIsCached uint64
URICacheFlushes uint64 URICacheFlushes uint64
URICacheHits uint64 URICacheHits uint64
URICacheMisses uint64 URICacheMisses uint64
ActiveThreadsCount uint64 ActiveThreadsCount uint64
TotalThreads uint64 TotalThreads uint64
MaximumThreadsCount uint64 MaximumThreadsCount uint64
TotalHTTPRequestsServed uint64 TotalHTTPRequestsServed uint64
ActiveRequests uint64 ActiveRequests uint64
}
type Win32_PerfRawData_W3SVCW3WPCounterProvider_W3SVCW3WP_IIS8 struct {
Name string
Percent401HTTPResponseSent uint64 Percent401HTTPResponseSent uint64
Percent403HTTPResponseSent uint64 Percent403HTTPResponseSent uint64
Percent404HTTPResponseSent uint64 Percent404HTTPResponseSent uint64
@@ -1567,64 +1608,80 @@ func (c *IISCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, e
float64(app.ActiveRequests), float64(app.ActiveRequests),
name, name,
) )
}
ch <- prometheus.MustNewConstMetric( if iis_version.major >= 8 {
c.RequestErrorsTotal, var dst_worker_iis8 []Win32_PerfRawData_W3SVCW3WPCounterProvider_W3SVCW3WP_IIS8
prometheus.CounterValue, q = createQuery(&dst_worker_iis8, "Win32_PerfRawData_W3SVCW3WPCounterProvider_W3SVCW3WP", "")
float64(app.Percent401HTTPResponseSent), if err := wmi.Query(q, &dst_worker_iis8); err != nil {
name, return nil, err
"401", }
) for _, app := range dst_worker_iis8 {
ch <- prometheus.MustNewConstMetric( // Extract the apppool name from the format <PID>_<NAME>
c.RequestErrorsTotal, name := workerProcessNameExtractor.ReplaceAllString(app.Name, "$1")
prometheus.CounterValue, if name == "_Total" ||
float64(app.Percent403HTTPResponseSent), c.appBlacklistPattern.MatchString(name) ||
name, !c.appWhitelistPattern.MatchString(name) {
"403", continue
) }
ch <- prometheus.MustNewConstMetric(
c.RequestErrorsTotal,
prometheus.CounterValue,
float64(app.Percent404HTTPResponseSent),
name,
"404",
)
ch <- prometheus.MustNewConstMetric(
c.RequestErrorsTotal,
prometheus.CounterValue,
float64(app.Percent500HTTPResponseSent),
name,
"500",
)
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.WebSocketRequestsActive, c.RequestErrorsTotal,
prometheus.CounterValue, prometheus.CounterValue,
float64(app.WebSocketActiveRequests), float64(app.Percent401HTTPResponseSent),
name, name,
) "401",
)
ch <- prometheus.MustNewConstMetric(
c.RequestErrorsTotal,
prometheus.CounterValue,
float64(app.Percent403HTTPResponseSent),
name,
"403",
)
ch <- prometheus.MustNewConstMetric(
c.RequestErrorsTotal,
prometheus.CounterValue,
float64(app.Percent404HTTPResponseSent),
name,
"404",
)
ch <- prometheus.MustNewConstMetric(
c.RequestErrorsTotal,
prometheus.CounterValue,
float64(app.Percent500HTTPResponseSent),
name,
"500",
)
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.WebSocketConnectionAttempts, c.WebSocketRequestsActive,
prometheus.CounterValue, prometheus.CounterValue,
float64(app.WebSocketConnectionAttemptsPerSec), float64(app.WebSocketActiveRequests),
name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.WebSocketConnectionsAccepted, c.WebSocketConnectionAttempts,
prometheus.CounterValue, prometheus.CounterValue,
float64(app.WebSocketConnectionsAcceptedPerSec), float64(app.WebSocketConnectionAttemptsPerSec),
name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.WebSocketConnectionsRejected, c.WebSocketConnectionsAccepted,
prometheus.CounterValue, prometheus.CounterValue,
float64(app.WebSocketConnectionsRejectedPerSec), float64(app.WebSocketConnectionsAcceptedPerSec),
name, name,
) )
ch <- prometheus.MustNewConstMetric(
c.WebSocketConnectionsRejected,
prometheus.CounterValue,
float64(app.WebSocketConnectionsRejectedPerSec),
name,
)
}
} }
var dst_cache []Win32_PerfRawData_W3SVC_WebServiceCache var dst_cache []Win32_PerfRawData_W3SVC_WebServiceCache

View File

@@ -1,6 +1,12 @@
package collector package collector
import "github.com/prometheus/client_golang/prometheus" import (
"bytes"
"reflect"
"strings"
"github.com/prometheus/client_golang/prometheus"
)
// ... // ...
const ( const (
@@ -18,3 +24,30 @@ type Collector interface {
// Get new metrics and expose them via prometheus registry. // Get new metrics and expose them via prometheus registry.
Collect(ch chan<- prometheus.Metric) (err error) Collect(ch chan<- prometheus.Metric) (err error)
} }
// This is adapted from StackExchange/wmi/wmi.go, and lets us change the class
// name being queried for:
// CreateQuery returns a WQL query string that queries all columns of src. where
// is an optional string that is appended to the query, to be used with WHERE
// clauses. In such a case, the "WHERE" string should appear at the beginning.
func createQuery(src interface{}, class, where string) string {
var b bytes.Buffer
b.WriteString("SELECT ")
s := reflect.Indirect(reflect.ValueOf(src))
t := s.Type()
if s.Kind() == reflect.Slice {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return ""
}
var fields []string
for i := 0; i < t.NumField(); i++ {
fields = append(fields, t.Field(i).Name)
}
b.WriteString(strings.Join(fields, ", "))
b.WriteString(" FROM ")
b.WriteString(class)
b.WriteString(" " + where)
return b.String()
}