initial commit
This commit is contained in:
commit
dac70ad805
|
@ -0,0 +1 @@
|
||||||
|
/wmi_exporter.exe
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Martin Lindhe
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,20 @@
|
||||||
|
# WMI exporter
|
||||||
|
|
||||||
|
Prometheus exporter for Windows machines, using the WMI (Windows Management Instrumentation).
|
||||||
|
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
EXPERIMENTAL, use at your own risk!
|
||||||
|
|
||||||
|
|
||||||
|
## Collectors
|
||||||
|
|
||||||
|
Name | Description
|
||||||
|
---------|-------------
|
||||||
|
os | Exposes Win32_OperatingSystem statistics (memory, processes, users)
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Under [MIT](LICENSE)
|
|
@ -0,0 +1,128 @@
|
||||||
|
// returns data points from Win32_OperatingSystem
|
||||||
|
|
||||||
|
package collectors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/StackExchange/wmi"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A OSCollector is a Prometheus collector for WMI OperatingSystem metrics
|
||||||
|
type OSCollector struct {
|
||||||
|
FreePhysicalMemory *prometheus.Desc
|
||||||
|
FreeSpaceInPagingFiles *prometheus.Desc
|
||||||
|
FreeVirtualMemory *prometheus.Desc
|
||||||
|
NumberOfProcesses *prometheus.Desc
|
||||||
|
NumberOfUsers *prometheus.Desc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOSCollector ...
|
||||||
|
func NewOSCollector() *OSCollector {
|
||||||
|
|
||||||
|
return &OSCollector{
|
||||||
|
FreePhysicalMemory: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(wmiNamespace, "os", "free_physical_memory"),
|
||||||
|
"Free physical memory.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
|
||||||
|
FreeSpaceInPagingFiles: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(wmiNamespace, "os", "free_space_in_paging_files"),
|
||||||
|
"Free space in paging files.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
|
||||||
|
FreeVirtualMemory: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(wmiNamespace, "os", "free_virtual_memory"),
|
||||||
|
"Free virtual memory.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
|
||||||
|
NumberOfProcesses: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(wmiNamespace, "os", "number_of_processes"),
|
||||||
|
"No. of processes running on the system.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
|
||||||
|
NumberOfUsers: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(wmiNamespace, "os", "number_of_users"),
|
||||||
|
"No. of users logged in.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect sends the metric values for each metric
|
||||||
|
// to the provided prometheus Metric channel.
|
||||||
|
func (c *OSCollector) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
if desc, err := c.collect(ch); err != nil {
|
||||||
|
log.Println("[ERROR] failed collecting process metrics:", desc, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.FreePhysicalMemory
|
||||||
|
ch <- c.FreeSpaceInPagingFiles
|
||||||
|
ch <- c.FreeVirtualMemory
|
||||||
|
ch <- c.NumberOfProcesses
|
||||||
|
ch <- c.NumberOfUsers
|
||||||
|
}
|
||||||
|
|
||||||
|
type Win32_OperatingSystem struct {
|
||||||
|
FreePhysicalMemory uint64
|
||||||
|
FreeSpaceInPagingFiles uint64
|
||||||
|
FreeVirtualMemory uint64
|
||||||
|
NumberOfProcesses uint32
|
||||||
|
NumberOfUsers uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *OSCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
|
||||||
|
var dst []Win32_OperatingSystem
|
||||||
|
q := wmi.CreateQuery(&dst, "")
|
||||||
|
if err := wmi.Query(q, &dst); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.FreePhysicalMemory,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(dst[0].FreePhysicalMemory),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.FreeSpaceInPagingFiles,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(dst[0].FreeSpaceInPagingFiles),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.FreeVirtualMemory,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(dst[0].FreeVirtualMemory),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.NumberOfProcesses,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(dst[0].NumberOfProcesses),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.NumberOfUsers,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(dst[0].NumberOfUsers),
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package collectors
|
||||||
|
|
||||||
|
const (
|
||||||
|
wmiNamespace = "wmi"
|
||||||
|
)
|
|
@ -0,0 +1,75 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/martinlindhe/wmi_exporter/collectors"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the WmiExporter implements the prometheus.Collector interface.
|
||||||
|
var _ prometheus.Collector = &WmiExporter{}
|
||||||
|
|
||||||
|
// 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{
|
||||||
|
collectors.NewOSCollector(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 main() {
|
||||||
|
var (
|
||||||
|
addr = flag.String("telemetry.addr", ":9129", "host:port for WMI exporter")
|
||||||
|
metricsPath = flag.String("telemetry.path", "/metrics", "URL path for surfacing collected metrics")
|
||||||
|
)
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
prometheus.MustRegister(NewWmiExporter())
|
||||||
|
|
||||||
|
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.Fatalf("cannot start WMI exporter: %s", err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue