mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-25 22:26:37 +00:00
make enabled collectors configurable (based on code from node_exporter)
This commit is contained in:
159
exporter.go
159
exporter.go
@@ -2,76 +2,161 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/martinlindhe/wmi_exporter/collector"
|
||||
"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
|
||||
// exporter to extracts metrics out of. It also ensures that the collection
|
||||
// is done in a thread-safe manner, the necessary requirement stated by
|
||||
// prometheus. It also implements a prometheus.Collector interface in order
|
||||
// to register it correctly.
|
||||
type WmiExporter struct {
|
||||
mu sync.Mutex
|
||||
collectors []prometheus.Collector
|
||||
// WmiCollector implements the prometheus.Collector interface.
|
||||
type WmiCollector struct {
|
||||
collectors map[string]collector.Collector
|
||||
}
|
||||
|
||||
// Verify that the WmiExporter implements the prometheus.Collector interface.
|
||||
var _ prometheus.Collector = &WmiExporter{}
|
||||
const (
|
||||
defaultCollectors = "logical_disk,os"
|
||||
)
|
||||
|
||||
// NewWmiExporter creates an instance to WmiExporter and returns a reference
|
||||
// to it. We can choose to enable a collector to extract stats out of by adding
|
||||
// it to the list of collectors.
|
||||
func NewWmiExporter() *WmiExporter {
|
||||
return &WmiExporter{
|
||||
collectors: []prometheus.Collector{
|
||||
collector.NewOSCollector(),
|
||||
collector.NewLogicalDiskCollector(),
|
||||
collector.NewIISCollector(),
|
||||
var (
|
||||
scrapeDurations = prometheus.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Namespace: collector.Namespace,
|
||||
Subsystem: "exporter",
|
||||
Name: "scrape_duration_seconds",
|
||||
Help: "wmi_exporter: Duration of a scrape job.",
|
||||
},
|
||||
}
|
||||
}
|
||||
[]string{"collector", "result"},
|
||||
)
|
||||
)
|
||||
|
||||
// Describe sends all the descriptors of the collectors included to
|
||||
// the provided channel.
|
||||
func (c *WmiExporter) Describe(ch chan<- *prometheus.Desc) {
|
||||
for _, cc := range c.collectors {
|
||||
cc.Describe(ch)
|
||||
}
|
||||
func (coll WmiCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||
scrapeDurations.Describe(ch)
|
||||
}
|
||||
|
||||
// Collect sends the collected metrics from each of the collectors to
|
||||
// prometheus. Collect could be called several times concurrently
|
||||
// and thus its run is protected by a single mutex.
|
||||
func (c *WmiExporter) Collect(ch chan<- prometheus.Metric) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for _, cc := range c.collectors {
|
||||
cc.Collect(ch)
|
||||
func (coll WmiCollector) Collect(ch chan<- prometheus.Metric) {
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(len(coll.collectors))
|
||||
for name, c := range coll.collectors {
|
||||
go func(name string, c collector.Collector) {
|
||||
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() {
|
||||
var (
|
||||
addr = flag.String("telemetry.addr", ":9182", "host:port for WMI exporter")
|
||||
metricsPath = flag.String("telemetry.path", "/metrics", "URL path for surfacing collected metrics")
|
||||
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.")
|
||||
printCollectors = flag.Bool("collectors.print", false, "If true, print available collectors and exit.")
|
||||
)
|
||||
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.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, *metricsPath, http.StatusMovedPermanently)
|
||||
})
|
||||
|
||||
log.Printf("Starting WMI exporter on %q", *addr)
|
||||
if err := http.ListenAndServe(*addr, nil); err != nil {
|
||||
log.Infoln("Starting WMI exporter", version.Info())
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user