mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-26 06:36:36 +00:00
Compare commits
3 Commits
v0.30.0-be
...
v0.30.0-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca04ad8fd2 | ||
|
|
fd55ac4894 | ||
|
|
c8eeb595c0 |
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="all" type="GoApplicationRunConfiguration" factoryName="Go Application" folderName="run">
|
<configuration default="false" name="all" type="GoApplicationRunConfiguration" factoryName="Go Application" folderName="run">
|
||||||
<module name="windows_exporter" />
|
<module name="windows_exporter" />
|
||||||
<working_directory value="$PROJECT_DIR$" />
|
<working_directory value="$PROJECT_DIR$" />
|
||||||
<parameters value="--web.listen-address=127.0.0.1:9182 --log.level=debug --collectors.enabled=ad,adcs,adfs,cache,container,cpu,cpu_info,cs,dfsr,dhcp,diskdrive,dns,exchange,filetime,fsrmquota,hyperv,iis,license,logical_disk,logon,memory,mscluster,msmq,mssql,net,netframework,nps,os,pagefile,perfdata,physical_disk,printer,process,remote_fx,scheduled_task,service,smb,smbclient,smtp,system,tcp,terminal_services,textfile,thermalzone,time,udp,update,vmware" />
|
<parameters value="--web.listen-address=127.0.0.1:9182 --log.level=info --collectors.enabled=ad,adcs,adfs,cache,container,cpu,cpu_info,cs,dfsr,dhcp,diskdrive,dns,exchange,filetime,fsrmquota,hyperv,iis,license,logical_disk,logon,memory,mscluster,msmq,mssql,net,netframework,nps,os,pagefile,perfdata,physical_disk,printer,process,remote_fx,scheduled_task,service,smb,smbclient,smtp,system,tcp,terminal_services,thermalzone,time,udp,update,vmware --debug.enabled" />
|
||||||
<sudo value="true" />
|
<sudo value="true" />
|
||||||
<kind value="PACKAGE" />
|
<kind value="PACKAGE" />
|
||||||
<package value="github.com/prometheus-community/windows_exporter/cmd/windows_exporter" />
|
<package value="github.com/prometheus-community/windows_exporter/cmd/windows_exporter" />
|
||||||
|
|||||||
@@ -199,6 +199,14 @@ Windows Server 2012 and 2012R2 are supported as best-effort only, but not guaran
|
|||||||
|
|
||||||
The prometheus metrics will be exposed on [localhost:9182](http://localhost:9182)
|
The prometheus metrics will be exposed on [localhost:9182](http://localhost:9182)
|
||||||
|
|
||||||
|
### HTTP Endpoints
|
||||||
|
|
||||||
|
windows_exporter provides the following HTTP endpoints:
|
||||||
|
|
||||||
|
* `/metrics`: Exposes metrics in the [Prometheus text format](https://prometheus.io/docs/instrumenting/exposition_formats/).
|
||||||
|
* `/health`: Returns 200 OK when the exporter is running.
|
||||||
|
* `/debug/pprof/`: Exposes the [pprof](https://golang.org/pkg/net/http/pprof/) endpoints. Only, if `--debug.enabled` is set.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Enable only service collector and specify a custom query
|
### Enable only service collector and specify a custom query
|
||||||
|
|||||||
@@ -87,10 +87,6 @@ func run() int {
|
|||||||
"web.disable-exporter-metrics",
|
"web.disable-exporter-metrics",
|
||||||
"Exclude metrics about the exporter itself (promhttp_*, process_*, go_*).",
|
"Exclude metrics about the exporter itself (promhttp_*, process_*, go_*).",
|
||||||
).Bool()
|
).Bool()
|
||||||
maxRequests = app.Flag(
|
|
||||||
"telemetry.max-requests",
|
|
||||||
"Maximum number of concurrent requests. 0 to disable.",
|
|
||||||
).Default("5").Int()
|
|
||||||
enabledCollectors = app.Flag(
|
enabledCollectors = app.Flag(
|
||||||
"collectors.enabled",
|
"collectors.enabled",
|
||||||
"Comma-separated list of collectors to use. Use '[defaults]' as a placeholder for all the collectors enabled by default.").
|
"Comma-separated list of collectors to use. Use '[defaults]' as a placeholder for all the collectors enabled by default.").
|
||||||
@@ -109,7 +105,14 @@ func run() int {
|
|||||||
).Default("normal").String()
|
).Default("normal").String()
|
||||||
)
|
)
|
||||||
|
|
||||||
logConfig := &log.Config{}
|
logFile := &log.AllowedFile{}
|
||||||
|
|
||||||
|
_ = logFile.Set("stdout")
|
||||||
|
if windowsservice.IsService {
|
||||||
|
_ = logFile.Set("eventlog")
|
||||||
|
}
|
||||||
|
|
||||||
|
logConfig := &log.Config{File: logFile}
|
||||||
flag.AddFlags(app, logConfig)
|
flag.AddFlags(app, logConfig)
|
||||||
|
|
||||||
app.Version(version.Print("windows_exporter"))
|
app.Version(version.Print("windows_exporter"))
|
||||||
@@ -220,7 +223,6 @@ func run() int {
|
|||||||
mux.Handle("GET "+*metricsPath, httphandler.New(logger, collectors, &httphandler.Options{
|
mux.Handle("GET "+*metricsPath, httphandler.New(logger, collectors, &httphandler.Options{
|
||||||
DisableExporterMetrics: *disableExporterMetrics,
|
DisableExporterMetrics: *disableExporterMetrics,
|
||||||
TimeoutMargin: *timeoutMargin,
|
TimeoutMargin: *timeoutMargin,
|
||||||
MaxRequests: *maxRequests,
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if *debugEnabled {
|
if *debugEnabled {
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
|
<Wix xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"
|
||||||
xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
|
xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<DirectoryRef Id="APPLICATIONFOLDER">
|
<DirectoryRef Id="APPLICATIONFOLDER">
|
||||||
<Component Transitive="yes">
|
<Component Transitive="yes">
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
Start="auto"
|
Start="auto"
|
||||||
Type="ownProcess"
|
Type="ownProcess"
|
||||||
Vital="yes"
|
Vital="yes"
|
||||||
Arguments="--log.file eventlog [ConfigFileFlag] [CollectorsFlag] [ListenFlag] [MetricsPathFlag] [TextfileDirsFlag] [ExtraFlags]">
|
Arguments="[ConfigFileFlag] [CollectorsFlag] [ListenFlag] [MetricsPathFlag] [TextfileDirsFlag] [ExtraFlags]">
|
||||||
<util:ServiceConfig
|
<util:ServiceConfig
|
||||||
ResetPeriodInDays="1"
|
ResetPeriodInDays="1"
|
||||||
FirstFailureActionType="restart"
|
FirstFailureActionType="restart"
|
||||||
|
|||||||
@@ -24,9 +24,9 @@
|
|||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
|
<Wix xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall"
|
||||||
xmlns:fw="http://wixtoolset.org/schemas/v4/wxs/firewall"
|
xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui"
|
||||||
xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
|
xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||||
<Package UpgradeCode="66a6eb5b-1fc2-4b14-a362-5ceec6413308" Name="$(var.ProductName)" Version="$(var.Version)"
|
<Package UpgradeCode="66a6eb5b-1fc2-4b14-a362-5ceec6413308" Name="$(var.ProductName)" Version="$(var.Version)"
|
||||||
Manufacturer="prometheus-community" Language="1033" Scope="perMachine">
|
Manufacturer="prometheus-community" Language="1033" Scope="perMachine">
|
||||||
<SummaryInformation Manufacturer="prometheus-community" Description="$(var.ProductName) $(var.Version) installer" />
|
<SummaryInformation Manufacturer="prometheus-community" Description="$(var.ProductName) $(var.Version) installer" />
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ var _ http.Handler = (*MetricsHTTPHandler)(nil)
|
|||||||
const defaultScrapeTimeout = 10.0
|
const defaultScrapeTimeout = 10.0
|
||||||
|
|
||||||
type MetricsHTTPHandler struct {
|
type MetricsHTTPHandler struct {
|
||||||
metricCollectors *collector.MetricCollectors
|
metricCollectors *collector.Collection
|
||||||
// exporterMetricsRegistry is a separate registry for the metrics about
|
// exporterMetricsRegistry is a separate registry for the metrics about
|
||||||
// the exporter itself.
|
// the exporter itself.
|
||||||
exporterMetricsRegistry *prometheus.Registry
|
exporterMetricsRegistry *prometheus.Registry
|
||||||
@@ -49,15 +49,13 @@ type MetricsHTTPHandler struct {
|
|||||||
type Options struct {
|
type Options struct {
|
||||||
DisableExporterMetrics bool
|
DisableExporterMetrics bool
|
||||||
TimeoutMargin float64
|
TimeoutMargin float64
|
||||||
MaxRequests int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(logger *slog.Logger, metricCollectors *collector.MetricCollectors, options *Options) *MetricsHTTPHandler {
|
func New(logger *slog.Logger, metricCollectors *collector.Collection, options *Options) *MetricsHTTPHandler {
|
||||||
if options == nil {
|
if options == nil {
|
||||||
options = &Options{
|
options = &Options{
|
||||||
DisableExporterMetrics: false,
|
DisableExporterMetrics: false,
|
||||||
TimeoutMargin: 0.5,
|
TimeoutMargin: 0.5,
|
||||||
MaxRequests: 5,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +63,9 @@ func New(logger *slog.Logger, metricCollectors *collector.MetricCollectors, opti
|
|||||||
metricCollectors: metricCollectors,
|
metricCollectors: metricCollectors,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
options: *options,
|
options: *options,
|
||||||
concurrencyCh: make(chan struct{}, options.MaxRequests),
|
|
||||||
|
// We are expose metrics directly from the memory region of the Win32 API. We should not allow more than one request at a time.
|
||||||
|
concurrencyCh: make(chan struct{}, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
if !options.DisableExporterMetrics {
|
if !options.DisableExporterMetrics {
|
||||||
@@ -126,82 +126,48 @@ func (c *MetricsHTTPHandler) getScrapeTimeout(logger *slog.Logger, r *http.Reque
|
|||||||
|
|
||||||
func (c *MetricsHTTPHandler) handlerFactory(logger *slog.Logger, scrapeTimeout time.Duration, requestedCollectors []string) (http.Handler, error) {
|
func (c *MetricsHTTPHandler) handlerFactory(logger *slog.Logger, scrapeTimeout time.Duration, requestedCollectors []string) (http.Handler, error) {
|
||||||
reg := prometheus.NewRegistry()
|
reg := prometheus.NewRegistry()
|
||||||
|
|
||||||
var metricCollectors *collector.MetricCollectors
|
|
||||||
if len(requestedCollectors) == 0 {
|
|
||||||
metricCollectors = c.metricCollectors
|
|
||||||
} else {
|
|
||||||
filteredCollectors := make(collector.Map)
|
|
||||||
|
|
||||||
for _, name := range requestedCollectors {
|
|
||||||
metricCollector, ok := c.metricCollectors.Collectors[name]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("couldn't find collector %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
filteredCollectors[name] = metricCollector
|
|
||||||
}
|
|
||||||
|
|
||||||
metricCollectors = &collector.MetricCollectors{
|
|
||||||
Collectors: filteredCollectors,
|
|
||||||
MISession: c.metricCollectors.MISession,
|
|
||||||
PerfCounterQuery: c.metricCollectors.PerfCounterQuery,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reg.MustRegister(version.NewCollector("windows_exporter"))
|
reg.MustRegister(version.NewCollector("windows_exporter"))
|
||||||
|
|
||||||
if err := reg.Register(metricCollectors.NewPrometheusCollector(scrapeTimeout, c.logger)); err != nil {
|
collectionHandler, err := c.metricCollectors.NewHandler(scrapeTimeout, c.logger, requestedCollectors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't create collector handler: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := reg.Register(collectionHandler); err != nil {
|
||||||
return nil, fmt.Errorf("couldn't register Prometheus collector: %w", err)
|
return nil, fmt.Errorf("couldn't register Prometheus collector: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var handler http.Handler
|
var regHandler http.Handler
|
||||||
if c.exporterMetricsRegistry != nil {
|
if c.exporterMetricsRegistry != nil {
|
||||||
handler = promhttp.HandlerFor(
|
regHandler = promhttp.HandlerFor(
|
||||||
prometheus.Gatherers{c.exporterMetricsRegistry, reg},
|
prometheus.Gatherers{c.exporterMetricsRegistry, reg},
|
||||||
promhttp.HandlerOpts{
|
promhttp.HandlerOpts{
|
||||||
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
|
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
|
||||||
ErrorHandling: promhttp.ContinueOnError,
|
ErrorHandling: promhttp.ContinueOnError,
|
||||||
MaxRequestsInFlight: c.options.MaxRequests,
|
MaxRequestsInFlight: 1,
|
||||||
Registry: c.exporterMetricsRegistry,
|
Registry: c.exporterMetricsRegistry,
|
||||||
|
EnableOpenMetrics: true,
|
||||||
|
ProcessStartTime: c.metricCollectors.GetStartTime(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// Note that we have to use h.exporterMetricsRegistry here to
|
// Note that we have to use h.exporterMetricsRegistry here to
|
||||||
// use the same promhttp metrics for all expositions.
|
// use the same promhttp metrics for all expositions.
|
||||||
handler = promhttp.InstrumentMetricHandler(
|
regHandler = promhttp.InstrumentMetricHandler(
|
||||||
c.exporterMetricsRegistry, handler,
|
c.exporterMetricsRegistry, regHandler,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
handler = promhttp.HandlerFor(
|
regHandler = promhttp.HandlerFor(
|
||||||
reg,
|
reg,
|
||||||
promhttp.HandlerOpts{
|
promhttp.HandlerOpts{
|
||||||
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
|
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
|
||||||
ErrorHandling: promhttp.ContinueOnError,
|
ErrorHandling: promhttp.ContinueOnError,
|
||||||
MaxRequestsInFlight: c.options.MaxRequests,
|
MaxRequestsInFlight: 1,
|
||||||
|
EnableOpenMetrics: true,
|
||||||
|
ProcessStartTime: c.metricCollectors.GetStartTime(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.withConcurrencyLimit(handler.ServeHTTP), nil
|
return regHandler, nil
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MetricsHTTPHandler) withConcurrencyLimit(next http.HandlerFunc) http.HandlerFunc {
|
|
||||||
if c.options.MaxRequests <= 0 {
|
|
||||||
return next
|
|
||||||
}
|
|
||||||
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
select {
|
|
||||||
case c.concurrencyCh <- struct{}{}:
|
|
||||||
defer func() { <-c.concurrencyCh }()
|
|
||||||
default:
|
|
||||||
w.WriteHeader(http.StatusServiceUnavailable)
|
|
||||||
_, _ = w.Write([]byte("Too many concurrent requests"))
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
next(w, r)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ func AddFlags(a *kingpin.Application, config *log.Config) {
|
|||||||
config.Config = new(promslog.Config)
|
config.Config = new(promslog.Config)
|
||||||
flag.AddFlags(a, config.Config)
|
flag.AddFlags(a, config.Config)
|
||||||
|
|
||||||
config.File = &log.AllowedFile{}
|
if config.File == nil {
|
||||||
a.Flag(FileFlagName, FileFlagHelp).Default("stderr").SetValue(config.File)
|
config.File = &log.AllowedFile{}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Flag(FileFlagName, FileFlagHelp).Default(config.File.String()).SetValue(config.File)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ type AllowedFile struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *AllowedFile) String() string {
|
func (f *AllowedFile) String() string {
|
||||||
|
if f == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
return f.s
|
return f.s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -193,6 +193,13 @@ func (c *Collector) Collect() (CounterValues, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectRoutine() {
|
func (c *Collector) collectRoutine() {
|
||||||
|
var (
|
||||||
|
itemCount uint32
|
||||||
|
bytesNeeded uint32
|
||||||
|
)
|
||||||
|
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
|
||||||
for range c.collectCh {
|
for range c.collectCh {
|
||||||
if ret := PdhCollectQueryData(c.handle); ret != ErrorSuccess {
|
if ret := PdhCollectQueryData(c.handle); ret != ErrorSuccess {
|
||||||
c.counterValuesCh <- nil
|
c.counterValuesCh <- nil
|
||||||
@@ -207,25 +214,24 @@ func (c *Collector) collectRoutine() {
|
|||||||
for _, counter := range c.counters {
|
for _, counter := range c.counters {
|
||||||
for _, instance := range counter.Instances {
|
for _, instance := range counter.Instances {
|
||||||
// Get the info with the current buffer size
|
// Get the info with the current buffer size
|
||||||
var itemCount uint32
|
bytesNeeded = uint32(cap(buf))
|
||||||
|
|
||||||
// Get the info with the current buffer size
|
for {
|
||||||
bufLen := uint32(0)
|
ret := PdhGetRawCounterArray(instance, &bytesNeeded, &itemCount, &buf[0])
|
||||||
|
|
||||||
ret := PdhGetRawCounterArray(instance, &bufLen, &itemCount, nil)
|
if ret == ErrorSuccess {
|
||||||
if ret != PdhMoreData {
|
break
|
||||||
return nil, fmt.Errorf("PdhGetRawCounterArray: %w", NewPdhError(ret))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, bufLen)
|
if err := NewPdhError(ret); ret != PdhMoreData && !isKnownCounterDataError(err) {
|
||||||
|
|
||||||
ret = PdhGetRawCounterArray(instance, &bufLen, &itemCount, &buf[0])
|
|
||||||
if ret != ErrorSuccess {
|
|
||||||
if err := NewPdhError(ret); !isKnownCounterDataError(err) {
|
|
||||||
return nil, fmt.Errorf("PdhGetRawCounterArray: %w", err)
|
return nil, fmt.Errorf("PdhGetRawCounterArray: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
if bytesNeeded <= uint32(cap(buf)) {
|
||||||
|
return nil, fmt.Errorf("PdhGetRawCounterArray reports buffer too small (%d), but buffer is large enough (%d): %w", uint32(cap(buf)), bytesNeeded, NewPdhError(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = make([]byte, bytesNeeded)
|
||||||
}
|
}
|
||||||
|
|
||||||
items := unsafe.Slice((*PdhRawCounterItem)(unsafe.Pointer(&buf[0])), itemCount)
|
items := unsafe.Slice((*PdhRawCounterItem)(unsafe.Pointer(&buf[0])), itemCount)
|
||||||
|
|||||||
@@ -61,4 +61,6 @@ func BenchmarkTestCollector(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
performanceData.Close()
|
performanceData.Close()
|
||||||
|
|
||||||
|
b.ReportAllocs()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//go:build windows
|
|
||||||
|
|
||||||
package collector
|
package collector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -27,26 +25,10 @@ import (
|
|||||||
|
|
||||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
types "github.com/prometheus-community/windows_exporter/internal/types"
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interface guard.
|
|
||||||
var _ prometheus.Collector = (*Prometheus)(nil)
|
|
||||||
|
|
||||||
// Prometheus implements prometheus.Collector for a set of Windows MetricCollectors.
|
|
||||||
type Prometheus struct {
|
|
||||||
maxScrapeDuration time.Duration
|
|
||||||
logger *slog.Logger
|
|
||||||
metricCollectors *MetricCollectors
|
|
||||||
|
|
||||||
// Base metrics returned by Prometheus
|
|
||||||
scrapeDurationDesc *prometheus.Desc
|
|
||||||
collectorScrapeDurationDesc *prometheus.Desc
|
|
||||||
collectorScrapeSuccessDesc *prometheus.Desc
|
|
||||||
collectorScrapeTimeoutDesc *prometheus.Desc
|
|
||||||
}
|
|
||||||
|
|
||||||
type collectorStatus struct {
|
type collectorStatus struct {
|
||||||
name string
|
name string
|
||||||
statusCode collectorStatusCode
|
statusCode collectorStatusCode
|
||||||
@@ -60,64 +42,26 @@ const (
|
|||||||
failed
|
failed
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPrometheusCollector returns a new Prometheus where the set of MetricCollectors must
|
func (c *Collection) collectAll(ch chan<- prometheus.Metric, logger *slog.Logger, maxScrapeDuration time.Duration) {
|
||||||
// return metrics within the given timeout.
|
|
||||||
func (c *MetricCollectors) NewPrometheusCollector(timeout time.Duration, logger *slog.Logger) *Prometheus {
|
|
||||||
return &Prometheus{
|
|
||||||
maxScrapeDuration: timeout,
|
|
||||||
metricCollectors: c,
|
|
||||||
logger: logger,
|
|
||||||
scrapeDurationDesc: prometheus.NewDesc(
|
|
||||||
prometheus.BuildFQName(types.Namespace, "exporter", "scrape_duration_seconds"),
|
|
||||||
"windows_exporter: Total scrape duration.",
|
|
||||||
nil,
|
|
||||||
nil,
|
|
||||||
),
|
|
||||||
collectorScrapeDurationDesc: prometheus.NewDesc(
|
|
||||||
prometheus.BuildFQName(types.Namespace, "exporter", "collector_duration_seconds"),
|
|
||||||
"windows_exporter: Duration of a collection.",
|
|
||||||
[]string{"collector"},
|
|
||||||
nil,
|
|
||||||
),
|
|
||||||
collectorScrapeSuccessDesc: prometheus.NewDesc(
|
|
||||||
prometheus.BuildFQName(types.Namespace, "exporter", "collector_success"),
|
|
||||||
"windows_exporter: Whether the collector was successful.",
|
|
||||||
[]string{"collector"},
|
|
||||||
nil,
|
|
||||||
),
|
|
||||||
collectorScrapeTimeoutDesc: prometheus.NewDesc(
|
|
||||||
prometheus.BuildFQName(types.Namespace, "exporter", "collector_timeout"),
|
|
||||||
"windows_exporter: Whether the collector timed out.",
|
|
||||||
[]string{"collector"},
|
|
||||||
nil,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Prometheus) Describe(_ chan<- *prometheus.Desc) {}
|
|
||||||
|
|
||||||
// Collect sends the collected metrics from each of the MetricCollectors to
|
|
||||||
// prometheus.
|
|
||||||
func (p *Prometheus) Collect(ch chan<- prometheus.Metric) {
|
|
||||||
collectorStartTime := time.Now()
|
collectorStartTime := time.Now()
|
||||||
|
|
||||||
// WaitGroup to wait for all collectors to finish
|
// WaitGroup to wait for all collectors to finish
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(p.metricCollectors.Collectors))
|
wg.Add(len(c.collectors))
|
||||||
|
|
||||||
// Using a channel to collect the status of each collector
|
// Using a channel to collect the status of each collector
|
||||||
// A channel is safe to use concurrently while a map is not
|
// A channel is safe to use concurrently while a map is not
|
||||||
collectorStatusCh := make(chan collectorStatus, len(p.metricCollectors.Collectors))
|
collectorStatusCh := make(chan collectorStatus, len(c.collectors))
|
||||||
|
|
||||||
// Execute all collectors concurrently
|
// Execute all collectors concurrently
|
||||||
// timeout handling is done in the execute function
|
// timeout handling is done in the execute function
|
||||||
for name, metricsCollector := range p.metricCollectors.Collectors {
|
for name, metricsCollector := range c.collectors {
|
||||||
go func(name string, metricsCollector Collector) {
|
go func(name string, metricsCollector Collector) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
collectorStatusCh <- collectorStatus{
|
collectorStatusCh <- collectorStatus{
|
||||||
name: name,
|
name: name,
|
||||||
statusCode: p.execute(name, metricsCollector, ch),
|
statusCode: c.collectCollector(ch, logger, name, metricsCollector, maxScrapeDuration),
|
||||||
}
|
}
|
||||||
}(name, metricsCollector)
|
}(name, metricsCollector)
|
||||||
}
|
}
|
||||||
@@ -139,14 +83,14 @@ func (p *Prometheus) Collect(ch chan<- prometheus.Metric) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
p.collectorScrapeSuccessDesc,
|
c.collectorScrapeSuccessDesc,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
successValue,
|
successValue,
|
||||||
status.name,
|
status.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
p.collectorScrapeTimeoutDesc,
|
c.collectorScrapeTimeoutDesc,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
timeoutValue,
|
timeoutValue,
|
||||||
status.name,
|
status.name,
|
||||||
@@ -154,13 +98,13 @@ func (p *Prometheus) Collect(ch chan<- prometheus.Metric) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
p.scrapeDurationDesc,
|
c.scrapeDurationDesc,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
time.Since(collectorStartTime).Seconds(),
|
time.Since(collectorStartTime).Seconds(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Prometheus) execute(name string, c Collector, ch chan<- prometheus.Metric) collectorStatusCode {
|
func (c *Collection) collectCollector(ch chan<- prometheus.Metric, logger *slog.Logger, name string, collector Collector, maxScrapeDuration time.Duration) collectorStatusCode {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
numMetrics int
|
numMetrics int
|
||||||
@@ -173,10 +117,10 @@ func (p *Prometheus) execute(name string, c Collector, ch chan<- prometheus.Metr
|
|||||||
bufCh := make(chan prometheus.Metric, 1000)
|
bufCh := make(chan prometheus.Metric, 1000)
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), p.maxScrapeDuration)
|
ctx, cancel := context.WithTimeout(context.Background(), maxScrapeDuration)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Execute the collector
|
// execute the collector
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@@ -188,7 +132,7 @@ func (p *Prometheus) execute(name string, c Collector, ch chan<- prometheus.Metr
|
|||||||
close(bufCh)
|
close(bufCh)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
errCh <- c.Collect(bufCh)
|
errCh <- collector.Collect(bufCh)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
@@ -232,7 +176,7 @@ func (p *Prometheus) execute(name string, c Collector, ch chan<- prometheus.Metr
|
|||||||
|
|
||||||
duration = time.Since(t)
|
duration = time.Since(t)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
p.collectorScrapeDurationDesc,
|
c.collectorScrapeDurationDesc,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
duration.Seconds(),
|
duration.Seconds(),
|
||||||
name,
|
name,
|
||||||
@@ -242,13 +186,13 @@ func (p *Prometheus) execute(name string, c Collector, ch chan<- prometheus.Metr
|
|||||||
|
|
||||||
duration = time.Since(t)
|
duration = time.Since(t)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
p.collectorScrapeDurationDesc,
|
c.collectorScrapeDurationDesc,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
duration.Seconds(),
|
duration.Seconds(),
|
||||||
name,
|
name,
|
||||||
)
|
)
|
||||||
|
|
||||||
p.logger.Warn(fmt.Sprintf("collector %s timeouted after %s, resulting in %d metrics", name, p.maxScrapeDuration, numMetrics))
|
logger.Warn(fmt.Sprintf("collector %s timeouted after %s, resulting in %d metrics", name, maxScrapeDuration, numMetrics))
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// Drain channel in case of premature return to not leak a goroutine.
|
// Drain channel in case of premature return to not leak a goroutine.
|
||||||
@@ -261,12 +205,12 @@ func (p *Prometheus) execute(name string, c Collector, ch chan<- prometheus.Metr
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loggerFn := p.logger.Warn
|
loggerFn := logger.Warn
|
||||||
if errors.Is(err, types.ErrNoData) ||
|
if errors.Is(err, types.ErrNoData) ||
|
||||||
errors.Is(err, perfdata.ErrNoData) ||
|
errors.Is(err, perfdata.ErrNoData) ||
|
||||||
errors.Is(err, perfdata.ErrPerformanceCounterNotInitialized) ||
|
errors.Is(err, perfdata.ErrPerformanceCounterNotInitialized) ||
|
||||||
errors.Is(err, mi.MI_RESULT_INVALID_NAMESPACE) {
|
errors.Is(err, mi.MI_RESULT_INVALID_NAMESPACE) {
|
||||||
loggerFn = p.logger.Debug
|
loggerFn = logger.Debug
|
||||||
}
|
}
|
||||||
|
|
||||||
loggerFn(fmt.Sprintf("collector %s failed after %s, resulting in %d metrics", name, duration, numMetrics),
|
loggerFn(fmt.Sprintf("collector %s failed after %s, resulting in %d metrics", name, duration, numMetrics),
|
||||||
@@ -276,7 +220,7 @@ func (p *Prometheus) execute(name string, c Collector, ch chan<- prometheus.Metr
|
|||||||
return failed
|
return failed
|
||||||
}
|
}
|
||||||
|
|
||||||
p.logger.Debug(fmt.Sprintf("collector %s succeeded after %s, resulting in %d metrics", name, duration, numMetrics))
|
logger.Debug(fmt.Sprintf("collector %s succeeded after %s, resulting in %d metrics", name, duration, numMetrics))
|
||||||
|
|
||||||
return success
|
return success
|
||||||
}
|
}
|
||||||
@@ -19,8 +19,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"maps"
|
||||||
"slices"
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
|
gotime "time"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/prometheus-community/windows_exporter/internal/collector/ad"
|
"github.com/prometheus-community/windows_exporter/internal/collector/ad"
|
||||||
@@ -72,10 +74,12 @@ import (
|
|||||||
"github.com/prometheus-community/windows_exporter/internal/collector/update"
|
"github.com/prometheus-community/windows_exporter/internal/collector/update"
|
||||||
"github.com/prometheus-community/windows_exporter/internal/collector/vmware"
|
"github.com/prometheus-community/windows_exporter/internal/collector/vmware"
|
||||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewWithFlags To be called by the exporter for collector initialization before running kingpin.Parse.
|
// NewWithFlags To be called by the exporter for collector initialization before running kingpin.Parse.
|
||||||
func NewWithFlags(app *kingpin.Application) *MetricCollectors {
|
func NewWithFlags(app *kingpin.Application) *Collection {
|
||||||
collectors := map[string]Collector{}
|
collectors := map[string]Collector{}
|
||||||
|
|
||||||
for name, builder := range BuildersWithFlags {
|
for name, builder := range BuildersWithFlags {
|
||||||
@@ -88,7 +92,7 @@ func NewWithFlags(app *kingpin.Application) *MetricCollectors {
|
|||||||
// NewWithConfig To be called by the external libraries for collector initialization without running [kingpin.Parse].
|
// NewWithConfig To be called by the external libraries for collector initialization without running [kingpin.Parse].
|
||||||
//
|
//
|
||||||
//goland:noinspection GoUnusedExportedFunction
|
//goland:noinspection GoUnusedExportedFunction
|
||||||
func NewWithConfig(config Config) *MetricCollectors {
|
func NewWithConfig(config Config) *Collection {
|
||||||
collectors := Map{}
|
collectors := Map{}
|
||||||
collectors[ad.Name] = ad.New(&config.AD)
|
collectors[ad.Name] = ad.New(&config.AD)
|
||||||
collectors[adcs.Name] = adcs.New(&config.ADCS)
|
collectors[adcs.Name] = adcs.New(&config.ADCS)
|
||||||
@@ -143,23 +147,48 @@ func NewWithConfig(config Config) *MetricCollectors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New To be called by the external libraries for collector initialization.
|
// New To be called by the external libraries for collector initialization.
|
||||||
func New(collectors Map) *MetricCollectors {
|
func New(collectors Map) *Collection {
|
||||||
return &MetricCollectors{
|
return &Collection{
|
||||||
Collectors: collectors,
|
collectors: collectors,
|
||||||
|
concurrencyCh: make(chan struct{}, 1),
|
||||||
|
scrapeDurationDesc: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, "exporter", "scrape_duration_seconds"),
|
||||||
|
"windows_exporter: Total scrape duration.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
collectorScrapeDurationDesc: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, "exporter", "collector_duration_seconds"),
|
||||||
|
"windows_exporter: Duration of a collection.",
|
||||||
|
[]string{"collector"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
collectorScrapeSuccessDesc: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, "exporter", "collector_success"),
|
||||||
|
"windows_exporter: Whether the collector was successful.",
|
||||||
|
[]string{"collector"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
collectorScrapeTimeoutDesc: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, "exporter", "collector_timeout"),
|
||||||
|
"windows_exporter: Whether the collector timed out.",
|
||||||
|
[]string{"collector"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable removes all collectors that not enabledCollectors.
|
// Enable removes all collectors that not enabledCollectors.
|
||||||
func (c *MetricCollectors) Enable(enabledCollectors []string) error {
|
func (c *Collection) Enable(enabledCollectors []string) error {
|
||||||
for _, name := range enabledCollectors {
|
for _, name := range enabledCollectors {
|
||||||
if _, ok := c.Collectors[name]; !ok {
|
if _, ok := c.collectors[name]; !ok {
|
||||||
return fmt.Errorf("unknown collector %s", name)
|
return fmt.Errorf("unknown collector %s", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for name := range c.Collectors {
|
for name := range c.collectors {
|
||||||
if !slices.Contains(enabledCollectors, name) {
|
if !slices.Contains(enabledCollectors, name) {
|
||||||
delete(c.Collectors, name)
|
delete(c.collectors, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,23 +196,25 @@ func (c *MetricCollectors) Enable(enabledCollectors []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build To be called by the exporter for collector initialization.
|
// Build To be called by the exporter for collector initialization.
|
||||||
func (c *MetricCollectors) Build(logger *slog.Logger) error {
|
func (c *Collection) Build(logger *slog.Logger) error {
|
||||||
|
c.startTime = gotime.Now()
|
||||||
|
|
||||||
err := c.initMI()
|
err := c.initMI()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error from initialize MI: %w", err)
|
return fmt.Errorf("error from initialize MI: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(c.Collectors))
|
wg.Add(len(c.collectors))
|
||||||
|
|
||||||
errCh := make(chan error, len(c.Collectors))
|
errCh := make(chan error, len(c.collectors))
|
||||||
errs := make([]error, 0, len(c.Collectors))
|
errs := make([]error, 0, len(c.collectors))
|
||||||
|
|
||||||
for _, collector := range c.Collectors {
|
for _, collector := range c.collectors {
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
if err = collector.Build(logger, c.MISession); err != nil {
|
if err = collector.Build(logger, c.miSession); err != nil {
|
||||||
errCh <- fmt.Errorf("error build collector %s: %w", collector.GetName(), err)
|
errCh <- fmt.Errorf("error build collector %s: %w", collector.GetName(), err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -201,21 +232,21 @@ func (c *MetricCollectors) Build(logger *slog.Logger) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close To be called by the exporter for collector cleanup.
|
// Close To be called by the exporter for collector cleanup.
|
||||||
func (c *MetricCollectors) Close() error {
|
func (c *Collection) Close() error {
|
||||||
errs := make([]error, 0, len(c.Collectors))
|
errs := make([]error, 0, len(c.collectors))
|
||||||
|
|
||||||
for _, collector := range c.Collectors {
|
for _, collector := range c.collectors {
|
||||||
if err := collector.Close(); err != nil {
|
if err := collector.Close(); err != nil {
|
||||||
errs = append(errs, fmt.Errorf("error from close collector %s: %w", collector.GetName(), err))
|
errs = append(errs, fmt.Errorf("error from close collector %s: %w", collector.GetName(), err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app, err := c.MISession.GetApplication()
|
app, err := c.miSession.GetApplication()
|
||||||
if err != nil && !errors.Is(err, mi.ErrNotInitialized) {
|
if err != nil && !errors.Is(err, mi.ErrNotInitialized) {
|
||||||
errs = append(errs, fmt.Errorf("error from get MI application: %w", err))
|
errs = append(errs, fmt.Errorf("error from get MI application: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.MISession.Close(); err != nil && !errors.Is(err, mi.ErrNotInitialized) {
|
if err := c.miSession.Close(); err != nil && !errors.Is(err, mi.ErrNotInitialized) {
|
||||||
errs = append(errs, fmt.Errorf("error from close MI session: %w", err))
|
errs = append(errs, fmt.Errorf("error from close MI session: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,8 +257,8 @@ func (c *MetricCollectors) Close() error {
|
|||||||
return errors.Join(errs...)
|
return errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close To be called by the exporter for collector cleanup.
|
// initMI To be called by the exporter for collector initialization.
|
||||||
func (c *MetricCollectors) initMI() error {
|
func (c *Collection) initMI() error {
|
||||||
app, err := mi.Application_Initialize()
|
app, err := mi.Application_Initialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error from initialize MI application: %w", err)
|
return fmt.Errorf("error from initialize MI application: %w", err)
|
||||||
@@ -242,10 +273,34 @@ func (c *MetricCollectors) initMI() error {
|
|||||||
return fmt.Errorf("error from set locale: %w", err)
|
return fmt.Errorf("error from set locale: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.MISession, err = app.NewSession(destinationOptions)
|
c.miSession, err = app.NewSession(destinationOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error from create NewSession: %w", err)
|
return fmt.Errorf("error from create NewSession: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithCollectors To be called by the exporter for collector initialization.
|
||||||
|
func (c *Collection) WithCollectors(collectors []string) (*Collection, error) {
|
||||||
|
metricCollectors := &Collection{
|
||||||
|
miSession: c.miSession,
|
||||||
|
startTime: c.startTime,
|
||||||
|
concurrencyCh: c.concurrencyCh,
|
||||||
|
scrapeDurationDesc: c.scrapeDurationDesc,
|
||||||
|
collectorScrapeDurationDesc: c.collectorScrapeDurationDesc,
|
||||||
|
collectorScrapeSuccessDesc: c.collectorScrapeSuccessDesc,
|
||||||
|
collectorScrapeTimeoutDesc: c.collectorScrapeTimeoutDesc,
|
||||||
|
collectors: maps.Clone(c.collectors),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := metricCollectors.Enable(collectors); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return metricCollectors, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collection) GetStartTime() gotime.Time {
|
||||||
|
return c.startTime
|
||||||
|
}
|
||||||
62
pkg/collector/handler.go
Normal file
62
pkg/collector/handler.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2024 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface guard.
|
||||||
|
var _ prometheus.Collector = (*Handler)(nil)
|
||||||
|
|
||||||
|
// Handler implements [prometheus.Collector] for a set of Windows Collection.
|
||||||
|
type Handler struct {
|
||||||
|
maxScrapeDuration time.Duration
|
||||||
|
logger *slog.Logger
|
||||||
|
collection *Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHandler returns a new Handler that implements a [prometheus.Collector] for the given metrics Collection.
|
||||||
|
func (c *Collection) NewHandler(maxScrapeDuration time.Duration, logger *slog.Logger, collectors []string) (*Handler, error) {
|
||||||
|
collection := c
|
||||||
|
|
||||||
|
if len(collectors) != 0 {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
collection, err = c.WithCollectors(collectors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create handler with collectors: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Handler{
|
||||||
|
maxScrapeDuration: maxScrapeDuration,
|
||||||
|
collection: collection,
|
||||||
|
logger: logger,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Handler) Describe(_ chan<- *prometheus.Desc) {}
|
||||||
|
|
||||||
|
// Collect sends the collected metrics from each of the Collection to
|
||||||
|
// prometheus.
|
||||||
|
func (p *Handler) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
p.collection.collectAll(ch, p.logger, p.maxScrapeDuration)
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||||
@@ -25,10 +26,16 @@ import (
|
|||||||
|
|
||||||
const DefaultCollectors = "cpu,cs,memory,logical_disk,physical_disk,net,os,service,system"
|
const DefaultCollectors = "cpu,cs,memory,logical_disk,physical_disk,net,os,service,system"
|
||||||
|
|
||||||
type MetricCollectors struct {
|
type Collection struct {
|
||||||
Collectors Map
|
collectors Map
|
||||||
MISession *mi.Session
|
miSession *mi.Session
|
||||||
PerfCounterQuery string
|
startTime time.Time
|
||||||
|
concurrencyCh chan struct{}
|
||||||
|
|
||||||
|
scrapeDurationDesc *prometheus.Desc
|
||||||
|
collectorScrapeDurationDesc *prometheus.Desc
|
||||||
|
collectorScrapeSuccessDesc *prometheus.Desc
|
||||||
|
collectorScrapeTimeoutDesc *prometheus.Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|||||||
Reference in New Issue
Block a user