mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-03-09 20:16:35 +00:00
exchange: Use new collector interface (#1685)
This commit is contained in:
@@ -15,6 +15,7 @@ linters:
|
|||||||
- gocognit
|
- gocognit
|
||||||
- goconst
|
- goconst
|
||||||
- gocyclo
|
- gocyclo
|
||||||
|
- godot
|
||||||
- gomnd
|
- gomnd
|
||||||
- paralleltest
|
- paralleltest
|
||||||
- lll
|
- lll
|
||||||
|
|||||||
@@ -3,42 +3,68 @@
|
|||||||
package exchange
|
package exchange
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
"github.com/prometheus-community/windows_exporter/internal/types"
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/utils"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Name = "exchange"
|
const Name = "exchange"
|
||||||
|
|
||||||
|
const (
|
||||||
|
adAccessProcesses = "ADAccessProcesses"
|
||||||
|
transportQueues = "TransportQueues"
|
||||||
|
httpProxy = "HttpProxy"
|
||||||
|
activeSync = "ActiveSync"
|
||||||
|
availabilityService = "AvailabilityService"
|
||||||
|
outlookWebAccess = "OutlookWebAccess"
|
||||||
|
autoDiscover = "Autodiscover"
|
||||||
|
workloadManagement = "WorkloadManagement"
|
||||||
|
rpcClientAccess = "RpcClientAccess"
|
||||||
|
mapiHttpEmsmdb = "MapiHttpEmsmdb"
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
CollectorsEnabled []string `yaml:"collectors_enabled"`
|
CollectorsEnabled []string `yaml:"collectors_enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var ConfigDefaults = Config{
|
var ConfigDefaults = Config{
|
||||||
CollectorsEnabled: []string{
|
CollectorsEnabled: []string{
|
||||||
"ADAccessProcesses",
|
adAccessProcesses,
|
||||||
"TransportQueues",
|
transportQueues,
|
||||||
"HttpProxy",
|
httpProxy,
|
||||||
"ActiveSync",
|
activeSync,
|
||||||
"AvailabilityService",
|
availabilityService,
|
||||||
"OutlookWebAccess",
|
outlookWebAccess,
|
||||||
"Autodiscover",
|
autoDiscover,
|
||||||
"WorkloadManagement",
|
workloadManagement,
|
||||||
"RpcClientAccess",
|
rpcClientAccess,
|
||||||
"MapiHttpEmsmdb",
|
mapiHttpEmsmdb,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type Collector struct {
|
type Collector struct {
|
||||||
config Config
|
config Config
|
||||||
|
|
||||||
|
perfDataCollectorADAccessProcesses perfdata.Collector
|
||||||
|
perfDataCollectorTransportQueues perfdata.Collector
|
||||||
|
perfDataCollectorHttpProxy perfdata.Collector
|
||||||
|
perfDataCollectorActiveSync perfdata.Collector
|
||||||
|
perfDataCollectorAvailabilityService perfdata.Collector
|
||||||
|
perfDataCollectorOWA perfdata.Collector
|
||||||
|
perfDataCollectorAutoDiscover perfdata.Collector
|
||||||
|
perfDataCollectorWorkloadManagementWorkloads perfdata.Collector
|
||||||
|
perfDataCollectorRpcClientAccess perfdata.Collector
|
||||||
|
perfDataCollectorMapiHttpEmsmdb perfdata.Collector
|
||||||
|
|
||||||
activeMailboxDeliveryQueueLength *prometheus.Desc
|
activeMailboxDeliveryQueueLength *prometheus.Desc
|
||||||
activeSyncRequestsPerSec *prometheus.Desc
|
activeSyncRequestsPerSec *prometheus.Desc
|
||||||
activeTasks *prometheus.Desc
|
activeTasks *prometheus.Desc
|
||||||
@@ -118,16 +144,16 @@ func NewWithFlags(app *kingpin.Application) *Collector {
|
|||||||
app.PreAction(func(*kingpin.ParseContext) error {
|
app.PreAction(func(*kingpin.ParseContext) error {
|
||||||
if listAllCollectors {
|
if listAllCollectors {
|
||||||
collectorDesc := map[string]string{
|
collectorDesc := map[string]string{
|
||||||
"ADAccessProcesses": "[19108] MSExchange ADAccess Processes",
|
adAccessProcesses: "[19108] MSExchange ADAccess Processes",
|
||||||
"TransportQueues": "[20524] MSExchangeTransport Queues",
|
transportQueues: "[20524] MSExchangeTransport Queues",
|
||||||
"HttpProxy": "[36934] MSExchange HttpProxy",
|
httpProxy: "[36934] MSExchange HttpProxy",
|
||||||
"ActiveSync": "[25138] MSExchange ActiveSync",
|
activeSync: "[25138] MSExchange ActiveSync",
|
||||||
"AvailabilityService": "[24914] MSExchange Availability Service",
|
availabilityService: "[24914] MSExchange Availability Service",
|
||||||
"OutlookWebAccess": "[24618] MSExchange OWA",
|
outlookWebAccess: "[24618] MSExchange OWA",
|
||||||
"Autodiscover": "[29240] MSExchange Autodiscover",
|
autoDiscover: "[29240] MSExchange Autodiscover",
|
||||||
"WorkloadManagement": "[19430] MSExchange WorkloadManagement Workloads",
|
workloadManagement: "[19430] MSExchange WorkloadManagement Workloads",
|
||||||
"RpcClientAccess": "[29336] MSExchange RpcClientAccess",
|
rpcClientAccess: "[29336] MSExchange RpcClientAccess",
|
||||||
"MapiHttpEmsmdb": "[26463] MSExchange MapiHttp Emsmdb",
|
mapiHttpEmsmdb: "[26463] MSExchange MapiHttp Emsmdb",
|
||||||
}
|
}
|
||||||
|
|
||||||
sb := strings.Builder{}
|
sb := strings.Builder{}
|
||||||
@@ -159,6 +185,10 @@ func (c *Collector) GetName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
|
if utils.PDHEnabled() {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
return []string{
|
return []string{
|
||||||
"MSExchange ADAccess Processes",
|
"MSExchange ADAccess Processes",
|
||||||
"MSExchangeTransport Queues",
|
"MSExchangeTransport Queues",
|
||||||
@@ -178,10 +208,31 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
|
if utils.PDHEnabled() {
|
||||||
|
collectorFuncs := map[string]func() error{
|
||||||
|
adAccessProcesses: c.buildADAccessProcesses,
|
||||||
|
transportQueues: c.buildTransportQueues,
|
||||||
|
httpProxy: c.buildHTTPProxy,
|
||||||
|
activeSync: c.buildActiveSync,
|
||||||
|
availabilityService: c.buildAvailabilityService,
|
||||||
|
outlookWebAccess: c.buildOWA,
|
||||||
|
autoDiscover: c.buildAutoDiscover,
|
||||||
|
workloadManagement: c.buildWorkloadManagementWorkloads,
|
||||||
|
rpcClientAccess: c.buildRPC,
|
||||||
|
mapiHttpEmsmdb: c.buildMapiHttpEmsmdb,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, collectorName := range c.config.CollectorsEnabled {
|
||||||
|
if err := collectorFuncs[collectorName](); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// desc creates a new prometheus description
|
// desc creates a new prometheus description
|
||||||
desc := func(metricName string, description string, labels ...string) *prometheus.Desc {
|
desc := func(metricName string, description string, labels ...string) *prometheus.Desc {
|
||||||
return prometheus.NewDesc(
|
return prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, "exchange", metricName),
|
prometheus.BuildFQName(types.Namespace, Name, metricName),
|
||||||
description,
|
description,
|
||||||
labels,
|
labels,
|
||||||
nil,
|
nil,
|
||||||
@@ -232,18 +283,22 @@ func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect collects exchange metrics and sends them to prometheus.
|
// Collect collects exchange metrics and sends them to prometheus.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
if utils.PDHEnabled() {
|
||||||
|
return c.collectPDH(ch)
|
||||||
|
}
|
||||||
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
logger = logger.With(slog.String("collector", Name))
|
||||||
collectorFuncs := map[string]func(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error{
|
collectorFuncs := map[string]func(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error{
|
||||||
"ADAccessProcesses": c.collectADAccessProcesses,
|
adAccessProcesses: c.collectADAccessProcesses,
|
||||||
"TransportQueues": c.collectTransportQueues,
|
transportQueues: c.collectTransportQueues,
|
||||||
"HttpProxy": c.collectHTTPProxy,
|
httpProxy: c.collectHTTPProxy,
|
||||||
"ActiveSync": c.collectActiveSync,
|
activeSync: c.collectActiveSync,
|
||||||
"AvailabilityService": c.collectAvailabilityService,
|
availabilityService: c.collectAvailabilityService,
|
||||||
"OutlookWebAccess": c.collectOWA,
|
outlookWebAccess: c.collectOWA,
|
||||||
"Autodiscover": c.collectAutoDiscover,
|
autoDiscover: c.collectAutoDiscover,
|
||||||
"WorkloadManagement": c.collectWorkloadManagementWorkloads,
|
workloadManagement: c.collectWorkloadManagementWorkloads,
|
||||||
"RpcClientAccess": c.collectRPC,
|
rpcClientAccess: c.collectRPC,
|
||||||
"MapiHttpEmsmdb": c.collectMapiHttpEmsmdb,
|
mapiHttpEmsmdb: c.collectMapiHttpEmsmdb,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, collectorName := range c.config.CollectorsEnabled {
|
for _, collectorName := range c.config.CollectorsEnabled {
|
||||||
@@ -259,476 +314,28 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch ch
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perflib: [19108] MSExchange ADAccess Processes.
|
// Collect collects exchange metrics and sends them to prometheus.
|
||||||
type perflibADAccessProcesses struct {
|
func (c *Collector) collectPDH(ch chan<- prometheus.Metric) error {
|
||||||
Name string
|
collectorFuncs := map[string]func(ch chan<- prometheus.Metric) error{
|
||||||
|
adAccessProcesses: c.collectPDHADAccessProcesses,
|
||||||
LDAPReadTime float64 `perflib:"LDAP Read Time"`
|
transportQueues: c.collectPDHTransportQueues,
|
||||||
LDAPSearchTime float64 `perflib:"LDAP Search Time"`
|
httpProxy: c.collectPDHHTTPProxy,
|
||||||
LDAPWriteTime float64 `perflib:"LDAP Write Time"`
|
activeSync: c.collectPDHActiveSync,
|
||||||
LDAPTimeoutErrorsPerSec float64 `perflib:"LDAP Timeout Errors/sec"`
|
availabilityService: c.collectPDHAvailabilityService,
|
||||||
LongRunningLDAPOperationsPerMin float64 `perflib:"Long Running LDAP Operations/min"`
|
outlookWebAccess: c.collectPDHOWA,
|
||||||
}
|
autoDiscover: c.collectPDHAutoDiscover,
|
||||||
|
workloadManagement: c.collectPDHWorkloadManagementWorkloads,
|
||||||
func (c *Collector) collectADAccessProcesses(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
rpcClientAccess: c.collectPDHRPC,
|
||||||
logger = logger.With(slog.String("collector", Name))
|
mapiHttpEmsmdb: c.collectPDHMapiHttpEmsmdb,
|
||||||
|
|
||||||
var data []perflibADAccessProcesses
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange ADAccess Processes"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
labelUseCount := make(map[string]int)
|
errs := make([]error, len(c.config.CollectorsEnabled))
|
||||||
|
|
||||||
for _, proc := range data {
|
for i, collectorName := range c.config.CollectorsEnabled {
|
||||||
labelName := c.toLabelName(proc.Name)
|
errs[i] = collectorFuncs[collectorName](ch)
|
||||||
if strings.HasSuffix(labelName, "_total") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we're not including the PID suffix from the instance names in the label names, we get an occasional duplicate.
|
|
||||||
// This seems to affect about 4 instances only of this object.
|
|
||||||
labelUseCount[labelName]++
|
|
||||||
if labelUseCount[labelName] > 1 {
|
|
||||||
labelName = fmt.Sprintf("%s_%d", labelName, labelUseCount[labelName])
|
|
||||||
}
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.ldapReadTime,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
c.msToSec(proc.LDAPReadTime),
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.ldapSearchTime,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
c.msToSec(proc.LDAPSearchTime),
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.ldapWriteTime,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
c.msToSec(proc.LDAPWriteTime),
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.ldapTimeoutErrorsPerSec,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
proc.LDAPTimeoutErrorsPerSec,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.longRunningLDAPOperationsPerMin,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
proc.LongRunningLDAPOperationsPerMin*60,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return errors.Join(errs...)
|
||||||
}
|
|
||||||
|
|
||||||
// Perflib: [24914] MSExchange Availability Service.
|
|
||||||
type perflibAvailabilityService struct {
|
|
||||||
RequestsSec float64 `perflib:"Availability Requests (sec)"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectAvailabilityService(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
|
||||||
|
|
||||||
var data []perflibAvailabilityService
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange Availability Service"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, availservice := range data {
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.availabilityRequestsSec,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
availservice.RequestsSec,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perflib: [36934] MSExchange HttpProxy.
|
|
||||||
type perflibHTTPProxy struct {
|
|
||||||
Name string
|
|
||||||
|
|
||||||
MailboxServerLocatorAverageLatency float64 `perflib:"MailboxServerLocator Average Latency (Moving Average)"`
|
|
||||||
AverageAuthenticationLatency float64 `perflib:"Average Authentication Latency"`
|
|
||||||
AverageCASProcessingLatency float64 `perflib:"Average ClientAccess Server Processing Latency"`
|
|
||||||
MailboxServerProxyFailureRate float64 `perflib:"Mailbox Server Proxy Failure Rate"`
|
|
||||||
OutstandingProxyRequests float64 `perflib:"Outstanding Proxy Requests"`
|
|
||||||
ProxyRequestsPerSec float64 `perflib:"Proxy Requests/Sec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectHTTPProxy(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
|
||||||
|
|
||||||
var data []perflibHTTPProxy
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange HttpProxy"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, instance := range data {
|
|
||||||
labelName := c.toLabelName(instance.Name)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.mailboxServerLocatorAverageLatency,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
c.msToSec(instance.MailboxServerLocatorAverageLatency),
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.averageAuthenticationLatency,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
instance.AverageAuthenticationLatency,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.averageCASProcessingLatency,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
c.msToSec(instance.AverageCASProcessingLatency),
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.mailboxServerProxyFailureRate,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
instance.MailboxServerProxyFailureRate,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.outstandingProxyRequests,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
instance.OutstandingProxyRequests,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.proxyRequestsPerSec,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
instance.ProxyRequestsPerSec,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perflib: [24618] MSExchange OWA.
|
|
||||||
type perflibOWA struct {
|
|
||||||
CurrentUniqueUsers float64 `perflib:"Current Unique Users"`
|
|
||||||
RequestsPerSec float64 `perflib:"Requests/sec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectOWA(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
|
||||||
|
|
||||||
var data []perflibOWA
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange OWA"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, owa := range data {
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.currentUniqueUsers,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
owa.CurrentUniqueUsers,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.owaRequestsPerSec,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
owa.RequestsPerSec,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perflib: [25138] MSExchange ActiveSync.
|
|
||||||
type perflibActiveSync struct {
|
|
||||||
RequestsPerSec float64 `perflib:"Requests/sec"`
|
|
||||||
PingCommandsPending float64 `perflib:"Ping Commands Pending"`
|
|
||||||
SyncCommandsPerSec float64 `perflib:"Sync Commands/sec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectActiveSync(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
|
||||||
|
|
||||||
var data []perflibActiveSync
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange ActiveSync"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, instance := range data {
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.activeSyncRequestsPerSec,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
instance.RequestsPerSec,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.pingCommandsPending,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
instance.PingCommandsPending,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.syncCommandsPerSec,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
instance.SyncCommandsPerSec,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perflib: [29366] MSExchange RpcClientAccess.
|
|
||||||
type perflibRPCClientAccess struct {
|
|
||||||
RPCAveragedLatency float64 `perflib:"RPC Averaged Latency"`
|
|
||||||
RPCRequests float64 `perflib:"RPC Requests"`
|
|
||||||
ActiveUserCount float64 `perflib:"Active User Count"`
|
|
||||||
ConnectionCount float64 `perflib:"Connection Count"`
|
|
||||||
RPCOperationsPerSec float64 `perflib:"RPC Operations/sec"`
|
|
||||||
UserCount float64 `perflib:"User Count"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectRPC(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
|
||||||
|
|
||||||
var data []perflibRPCClientAccess
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange RpcClientAccess"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rpc := range data {
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.rpcAveragedLatency,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
c.msToSec(rpc.RPCAveragedLatency),
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.rpcRequests,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
rpc.RPCRequests,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.activeUserCount,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
rpc.ActiveUserCount,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.connectionCount,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
rpc.ConnectionCount,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.rpcOperationsPerSec,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
rpc.RPCOperationsPerSec,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.userCount,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
rpc.UserCount,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perflib: [20524] MSExchangeTransport Queues.
|
|
||||||
type perflibTransportQueues struct {
|
|
||||||
Name string
|
|
||||||
|
|
||||||
ExternalActiveRemoteDeliveryQueueLength float64 `perflib:"External Active Remote Delivery Queue Length"`
|
|
||||||
InternalActiveRemoteDeliveryQueueLength float64 `perflib:"Internal Active Remote Delivery Queue Length"`
|
|
||||||
ActiveMailboxDeliveryQueueLength float64 `perflib:"Active Mailbox Delivery Queue Length"`
|
|
||||||
RetryMailboxDeliveryQueueLength float64 `perflib:"Retry Mailbox Delivery Queue Length"`
|
|
||||||
UnreachableQueueLength float64 `perflib:"Unreachable Queue Length"`
|
|
||||||
ExternalLargestDeliveryQueueLength float64 `perflib:"External Largest Delivery Queue Length"`
|
|
||||||
InternalLargestDeliveryQueueLength float64 `perflib:"Internal Largest Delivery Queue Length"`
|
|
||||||
PoisonQueueLength float64 `perflib:"Poison Queue Length"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectTransportQueues(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
|
||||||
|
|
||||||
var data []perflibTransportQueues
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchangeTransport Queues"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, queue := range data {
|
|
||||||
labelName := c.toLabelName(queue.Name)
|
|
||||||
if strings.HasSuffix(labelName, "_total") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.externalActiveRemoteDeliveryQueueLength,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
queue.ExternalActiveRemoteDeliveryQueueLength,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.internalActiveRemoteDeliveryQueueLength,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
queue.InternalActiveRemoteDeliveryQueueLength,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.activeMailboxDeliveryQueueLength,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
queue.ActiveMailboxDeliveryQueueLength,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.retryMailboxDeliveryQueueLength,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
queue.RetryMailboxDeliveryQueueLength,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.unreachableQueueLength,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
queue.UnreachableQueueLength,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.externalLargestDeliveryQueueLength,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
queue.ExternalLargestDeliveryQueueLength,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.internalLargestDeliveryQueueLength,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
queue.InternalLargestDeliveryQueueLength,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.poisonQueueLength,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
queue.PoisonQueueLength,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perflib: [19430] MSExchange WorkloadManagement Workloads.
|
|
||||||
type perflibWorkloadManagementWorkloads struct {
|
|
||||||
Name string
|
|
||||||
|
|
||||||
ActiveTasks float64 `perflib:"ActiveTasks"`
|
|
||||||
CompletedTasks float64 `perflib:"CompletedTasks"`
|
|
||||||
QueuedTasks float64 `perflib:"QueuedTasks"`
|
|
||||||
YieldedTasks float64 `perflib:"YieldedTasks"`
|
|
||||||
IsActive float64 `perflib:"Active"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectWorkloadManagementWorkloads(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
|
||||||
|
|
||||||
var data []perflibWorkloadManagementWorkloads
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange WorkloadManagement Workloads"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, instance := range data {
|
|
||||||
labelName := c.toLabelName(instance.Name)
|
|
||||||
if strings.HasSuffix(labelName, "_total") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.activeTasks,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
instance.ActiveTasks,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.completedTasks,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
instance.CompletedTasks,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.queuedTasks,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
instance.QueuedTasks,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.yieldedTasks,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
instance.YieldedTasks,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.isActive,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
instance.IsActive,
|
|
||||||
labelName,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// [29240] MSExchangeAutodiscover.
|
|
||||||
type perflibAutodiscover struct {
|
|
||||||
RequestsPerSec float64 `perflib:"Requests/sec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectAutoDiscover(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
|
||||||
|
|
||||||
var data []perflibAutodiscover
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchangeAutodiscover"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, autodisc := range data {
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.autoDiscoverRequestsPerSec,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
autodisc.RequestsPerSec,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// perflib [26463] MSExchange MapiHttp Emsmdb.
|
|
||||||
type perflibMapiHttpEmsmdb struct {
|
|
||||||
ActiveUserCount float64 `perflib:"Active User Count"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectMapiHttpEmsmdb(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = logger.With(slog.String("collector", Name))
|
|
||||||
|
|
||||||
var data []perflibMapiHttpEmsmdb
|
|
||||||
|
|
||||||
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange MapiHttp Emsmdb"], &data, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, mapihttp := range data {
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.activeUserCountMapiHttpEmsMDB,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
mapihttp.ActiveUserCount,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// toLabelName converts strings to lowercase and replaces all whitespaces and dots with underscores.
|
// toLabelName converts strings to lowercase and replaces all whitespaces and dots with underscores.
|
||||||
|
|||||||
101
internal/collector/exchange/exchange_active_sync.go
Normal file
101
internal/collector/exchange/exchange_active_sync.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
requestsPerSec = "Requests/sec"
|
||||||
|
pingCommandsPending = "Ping Commands Pending"
|
||||||
|
syncCommandsPerSec = "Sync Commands/sec"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Perflib: [25138] MSExchange ActiveSync.
|
||||||
|
type perflibActiveSync struct {
|
||||||
|
RequestsPerSec float64 `perflib:"Requests/sec"`
|
||||||
|
PingCommandsPending float64 `perflib:"Ping Commands Pending"`
|
||||||
|
SyncCommandsPerSec float64 `perflib:"Sync Commands/sec"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildActiveSync() error {
|
||||||
|
counters := []string{
|
||||||
|
requestsPerSec,
|
||||||
|
pingCommandsPending,
|
||||||
|
syncCommandsPerSec,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorActiveSync, err = perfdata.NewCollector(perfdata.V1, "MSExchange ActiveSync", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchange ActiveSync collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectActiveSync(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibActiveSync
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange ActiveSync"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, instance := range data {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeSyncRequestsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
instance.RequestsPerSec,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.pingCommandsPending,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
instance.PingCommandsPending,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.syncCommandsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
instance.SyncCommandsPerSec,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHActiveSync(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorActiveSync.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchange ActiveSync metrics: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchange ActiveSync returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, data := range perfData {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeSyncRequestsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[requestsPerSec].FirstValue,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.pingCommandsPending,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[pingCommandsPending].FirstValue,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.syncCommandsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[syncCommandsPerSec].FirstValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
164
internal/collector/exchange/exchange_ad_access_processes.go
Normal file
164
internal/collector/exchange/exchange_ad_access_processes.go
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ldapReadTime = "LDAP Read Time"
|
||||||
|
ldapSearchTime = "LDAP Search Time"
|
||||||
|
ldapWriteTime = "LDAP Write Time"
|
||||||
|
ldapTimeoutErrorsPerSec = "LDAP Timeout Errors/sec"
|
||||||
|
longRunningLDAPOperationsPerMin = "Long Running LDAP Operations/min"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Perflib: [19108] MSExchange ADAccess Processes.
|
||||||
|
type perflibADAccessProcesses struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
LDAPReadTime float64 `perflib:"LDAP Read Time"`
|
||||||
|
LDAPSearchTime float64 `perflib:"LDAP Search Time"`
|
||||||
|
LDAPWriteTime float64 `perflib:"LDAP Write Time"`
|
||||||
|
LDAPTimeoutErrorsPerSec float64 `perflib:"LDAP Timeout Errors/sec"`
|
||||||
|
LongRunningLDAPOperationsPerMin float64 `perflib:"Long Running LDAP Operations/min"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildADAccessProcesses() error {
|
||||||
|
counters := []string{
|
||||||
|
ldapReadTime,
|
||||||
|
ldapSearchTime,
|
||||||
|
ldapWriteTime,
|
||||||
|
ldapTimeoutErrorsPerSec,
|
||||||
|
longRunningLDAPOperationsPerMin,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorADAccessProcesses, err = perfdata.NewCollector(perfdata.V1, "MSExchange ADAccess Processes", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchange ADAccess Processes collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectADAccessProcesses(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibADAccessProcesses
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange ADAccess Processes"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
labelUseCount := make(map[string]int)
|
||||||
|
|
||||||
|
for _, proc := range data {
|
||||||
|
labelName := c.toLabelName(proc.Name)
|
||||||
|
if strings.HasSuffix(labelName, "_total") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we're not including the PID suffix from the instance names in the label names, we get an occasional duplicate.
|
||||||
|
// This seems to affect about 4 instances only of this object.
|
||||||
|
labelUseCount[labelName]++
|
||||||
|
if labelUseCount[labelName] > 1 {
|
||||||
|
labelName = fmt.Sprintf("%s_%d", labelName, labelUseCount[labelName])
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ldapReadTime,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
c.msToSec(proc.LDAPReadTime),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ldapSearchTime,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
c.msToSec(proc.LDAPSearchTime),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ldapWriteTime,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
c.msToSec(proc.LDAPWriteTime),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ldapTimeoutErrorsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
proc.LDAPTimeoutErrorsPerSec,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.longRunningLDAPOperationsPerMin,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
proc.LongRunningLDAPOperationsPerMin*60,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHADAccessProcesses(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorADAccessProcesses.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchange ADAccess Processes metrics: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchange ADAccess Processes returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
labelUseCount := make(map[string]int)
|
||||||
|
|
||||||
|
for name, data := range perfData {
|
||||||
|
labelName := c.toLabelName(name)
|
||||||
|
|
||||||
|
// Since we're not including the PID suffix from the instance names in the label names, we get an occasional duplicate.
|
||||||
|
// This seems to affect about 4 instances only of this object.
|
||||||
|
labelUseCount[labelName]++
|
||||||
|
if labelUseCount[labelName] > 1 {
|
||||||
|
labelName = fmt.Sprintf("%s_%d", labelName, labelUseCount[labelName])
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ldapReadTime,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
c.msToSec(data[ldapReadTime].FirstValue),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ldapSearchTime,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
c.msToSec(data[ldapSearchTime].FirstValue),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ldapWriteTime,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
c.msToSec(data[ldapWriteTime].FirstValue),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.ldapTimeoutErrorsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[ldapTimeoutErrorsPerSec].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.longRunningLDAPOperationsPerMin,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[longRunningLDAPOperationsPerMin].FirstValue*60,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
71
internal/collector/exchange/exchange_autodiscover.go
Normal file
71
internal/collector/exchange/exchange_autodiscover.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// [29240] MSExchangeAutodiscover.
|
||||||
|
type perflibAutodiscover struct {
|
||||||
|
RequestsPerSec float64 `perflib:"Requests/sec"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildAutoDiscover() error {
|
||||||
|
counters := []string{
|
||||||
|
requestsPerSec,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorAutoDiscover, err = perfdata.NewCollector(perfdata.V1, "MSExchange Autodiscover", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchange Autodiscover collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectAutoDiscover(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibAutodiscover
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchangeAutodiscover"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, autodisc := range data {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.autoDiscoverRequestsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
autodisc.RequestsPerSec,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHAutoDiscover(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorAutoDiscover.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchange Autodiscover metrics: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchange Autodiscover returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, data := range perfData {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.autoDiscoverRequestsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[requestsPerSec].FirstValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
69
internal/collector/exchange/exchange_availability_service.go
Normal file
69
internal/collector/exchange/exchange_availability_service.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Perflib: [24914] MSExchange Availability Service.
|
||||||
|
type perflibAvailabilityService struct {
|
||||||
|
RequestsSec float64 `perflib:"Availability Requests (sec)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildAvailabilityService() error {
|
||||||
|
counters := []string{}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorAvailabilityService, err = perfdata.NewCollector(perfdata.V1, "MSExchange Availability Service", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchange Availability Service collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectAvailabilityService(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibAvailabilityService
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange Availability Service"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, availservice := range data {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.availabilityRequestsSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
availservice.RequestsSec,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHAvailabilityService(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorAvailabilityService.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchange Availability Service metrics: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchange Availability Service returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, data := range perfData {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.availabilityRequestsSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[requestsPerSec].FirstValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
156
internal/collector/exchange/exchange_http_proxy.go
Normal file
156
internal/collector/exchange/exchange_http_proxy.go
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
mailboxServerLocatorAverageLatency = "MailboxServerLocator Average Latency (Moving Average)"
|
||||||
|
averageAuthenticationLatency = "Average Authentication Latency"
|
||||||
|
averageCASProcessingLatency = "Average ClientAccess Server Processing Latency"
|
||||||
|
mailboxServerProxyFailureRate = "Mailbox Server Proxy Failure Rate"
|
||||||
|
outstandingProxyRequests = "Outstanding Proxy Requests"
|
||||||
|
proxyRequestsPerSec = "Proxy Requests/Sec"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Perflib: [36934] MSExchange HttpProxy.
|
||||||
|
type perflibHTTPProxy struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
MailboxServerLocatorAverageLatency float64 `perflib:"MailboxServerLocator Average Latency (Moving Average)"`
|
||||||
|
AverageAuthenticationLatency float64 `perflib:"Average Authentication Latency"`
|
||||||
|
AverageCASProcessingLatency float64 `perflib:"Average ClientAccess Server Processing Latency"`
|
||||||
|
MailboxServerProxyFailureRate float64 `perflib:"Mailbox Server Proxy Failure Rate"`
|
||||||
|
OutstandingProxyRequests float64 `perflib:"Outstanding Proxy Requests"`
|
||||||
|
ProxyRequestsPerSec float64 `perflib:"Proxy Requests/Sec"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildHTTPProxy() error {
|
||||||
|
counters := []string{
|
||||||
|
mailboxServerLocatorAverageLatency,
|
||||||
|
averageAuthenticationLatency,
|
||||||
|
averageCASProcessingLatency,
|
||||||
|
mailboxServerProxyFailureRate,
|
||||||
|
outstandingProxyRequests,
|
||||||
|
proxyRequestsPerSec,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorHttpProxy, err = perfdata.NewCollector(perfdata.V1, "MSExchange HttpProxy", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchange HttpProxy collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectHTTPProxy(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibHTTPProxy
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange HttpProxy"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, instance := range data {
|
||||||
|
labelName := c.toLabelName(instance.Name)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.mailboxServerLocatorAverageLatency,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
c.msToSec(instance.MailboxServerLocatorAverageLatency),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.averageAuthenticationLatency,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
instance.AverageAuthenticationLatency,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.averageCASProcessingLatency,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
c.msToSec(instance.AverageCASProcessingLatency),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.mailboxServerProxyFailureRate,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
instance.MailboxServerProxyFailureRate,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.outstandingProxyRequests,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
instance.OutstandingProxyRequests,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.proxyRequestsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
instance.ProxyRequestsPerSec,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHHTTPProxy(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorHttpProxy.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchange HttpProxy Service metrics: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchange HttpProxy Service returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, data := range perfData {
|
||||||
|
labelName := c.toLabelName(name)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.mailboxServerLocatorAverageLatency,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
c.msToSec(data[mailboxServerLocatorAverageLatency].FirstValue),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.averageAuthenticationLatency,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[averageAuthenticationLatency].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.averageCASProcessingLatency,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
c.msToSec(data[averageCASProcessingLatency].FirstValue),
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.mailboxServerProxyFailureRate,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[mailboxServerProxyFailureRate].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.outstandingProxyRequests,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[outstandingProxyRequests].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.proxyRequestsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[proxyRequestsPerSec].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
75
internal/collector/exchange/exchange_mapi_http_emsmdb.go
Normal file
75
internal/collector/exchange/exchange_mapi_http_emsmdb.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
activeUserCount = "Active User Count"
|
||||||
|
)
|
||||||
|
|
||||||
|
// perflib [26463] MSExchange MapiHttp Emsmdb.
|
||||||
|
type perflibMapiHttpEmsmdb struct {
|
||||||
|
ActiveUserCount float64 `perflib:"Active User Count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildMapiHttpEmsmdb() error {
|
||||||
|
counters := []string{
|
||||||
|
activeUserCount,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorMapiHttpEmsmdb, err = perfdata.NewCollector(perfdata.V1, "MSExchange MapiHttp Emsmdb", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchange MapiHttp Emsmdb: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectMapiHttpEmsmdb(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibMapiHttpEmsmdb
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange MapiHttp Emsmdb"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mapihttp := range data {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeUserCountMapiHttpEmsMDB,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
mapihttp.ActiveUserCount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHMapiHttpEmsmdb(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorMapiHttpEmsmdb.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchange MapiHttp Emsmdb metrics: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchange MapiHttp Emsmdb returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, data := range perfData {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeUserCountMapiHttpEmsMDB,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[activeUserCount].FirstValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
88
internal/collector/exchange/exchange_outlook_web_access.go
Normal file
88
internal/collector/exchange/exchange_outlook_web_access.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
currentUniqueUsers = "Current Unique Users"
|
||||||
|
// requestsPerSec = "Requests/sec"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Perflib: [24618] MSExchange OWA.
|
||||||
|
type perflibOWA struct {
|
||||||
|
CurrentUniqueUsers float64 `perflib:"Current Unique Users"`
|
||||||
|
RequestsPerSec float64 `perflib:"Requests/sec"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildOWA() error {
|
||||||
|
counters := []string{
|
||||||
|
currentUniqueUsers,
|
||||||
|
requestsPerSec,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorOWA, err = perfdata.NewCollector(perfdata.V1, "MSExchange OWA", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchange OWA collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectOWA(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibOWA
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange OWA"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, owa := range data {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.currentUniqueUsers,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
owa.CurrentUniqueUsers,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.owaRequestsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
owa.RequestsPerSec,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHOWA(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorOWA.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchange OWA metrics: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchange OWA returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, data := range perfData {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.currentUniqueUsers,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[currentUniqueUsers].FirstValue,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.owaRequestsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[requestsPerSec].FirstValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
140
internal/collector/exchange/exchange_rpc_client_access.go
Normal file
140
internal/collector/exchange/exchange_rpc_client_access.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
rpcAveragedLatency = "RPC Averaged Latency"
|
||||||
|
rpcRequests = "RPC Requests"
|
||||||
|
// activeUserCount = "Active User Count"
|
||||||
|
connectionCount = "Connection Count"
|
||||||
|
rpcOperationsPerSec = "RPC Operations/sec"
|
||||||
|
userCount = "User Count"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Perflib: [29366] MSExchange RpcClientAccess.
|
||||||
|
type perflibRPCClientAccess struct {
|
||||||
|
RPCAveragedLatency float64 `perflib:"RPC Averaged Latency"`
|
||||||
|
RPCRequests float64 `perflib:"RPC Requests"`
|
||||||
|
ActiveUserCount float64 `perflib:"Active User Count"`
|
||||||
|
ConnectionCount float64 `perflib:"Connection Count"`
|
||||||
|
RPCOperationsPerSec float64 `perflib:"RPC Operations/sec"`
|
||||||
|
UserCount float64 `perflib:"User Count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildRPC() error {
|
||||||
|
counters := []string{
|
||||||
|
rpcAveragedLatency,
|
||||||
|
rpcRequests,
|
||||||
|
activeUserCount,
|
||||||
|
connectionCount,
|
||||||
|
rpcOperationsPerSec,
|
||||||
|
userCount,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorRpcClientAccess, err = perfdata.NewCollector(perfdata.V1, "MSExchange RpcClientAccess", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchange RpcClientAccess collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectRPC(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibRPCClientAccess
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange RpcClientAccess"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rpc := range data {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.rpcAveragedLatency,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
c.msToSec(rpc.RPCAveragedLatency),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.rpcRequests,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
rpc.RPCRequests,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeUserCount,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
rpc.ActiveUserCount,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.connectionCount,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
rpc.ConnectionCount,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.rpcOperationsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
rpc.RPCOperationsPerSec,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.userCount,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
rpc.UserCount,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHRPC(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorRpcClientAccess.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchange RpcClientAccess: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchange RpcClientAccess returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, data := range perfData {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.rpcAveragedLatency,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
c.msToSec(data[rpcAveragedLatency].FirstValue),
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.rpcRequests,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[rpcRequests].FirstValue,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeUserCount,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[activeUserCount].FirstValue,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.connectionCount,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[connectionCount].FirstValue,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.rpcOperationsPerSec,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[rpcOperationsPerSec].FirstValue,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.userCount,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[userCount].FirstValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
191
internal/collector/exchange/exchange_transport_queues.go
Normal file
191
internal/collector/exchange/exchange_transport_queues.go
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
externalActiveRemoteDeliveryQueueLength = "External Active Remote Delivery Queue Length"
|
||||||
|
internalActiveRemoteDeliveryQueueLength = "Internal Active Remote Delivery Queue Length"
|
||||||
|
activeMailboxDeliveryQueueLength = "Active Mailbox Delivery Queue Length"
|
||||||
|
retryMailboxDeliveryQueueLength = "Retry Mailbox Delivery Queue Length"
|
||||||
|
unreachableQueueLength = "Unreachable Queue Length"
|
||||||
|
externalLargestDeliveryQueueLength = "External Largest Delivery Queue Length"
|
||||||
|
internalLargestDeliveryQueueLength = "Internal Largest Delivery Queue Length"
|
||||||
|
poisonQueueLength = "Poison Queue Length"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Perflib: [20524] MSExchangeTransport Queues.
|
||||||
|
type perflibTransportQueues struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
ExternalActiveRemoteDeliveryQueueLength float64 `perflib:"External Active Remote Delivery Queue Length"`
|
||||||
|
InternalActiveRemoteDeliveryQueueLength float64 `perflib:"Internal Active Remote Delivery Queue Length"`
|
||||||
|
ActiveMailboxDeliveryQueueLength float64 `perflib:"Active Mailbox Delivery Queue Length"`
|
||||||
|
RetryMailboxDeliveryQueueLength float64 `perflib:"Retry Mailbox Delivery Queue Length"`
|
||||||
|
UnreachableQueueLength float64 `perflib:"Unreachable Queue Length"`
|
||||||
|
ExternalLargestDeliveryQueueLength float64 `perflib:"External Largest Delivery Queue Length"`
|
||||||
|
InternalLargestDeliveryQueueLength float64 `perflib:"Internal Largest Delivery Queue Length"`
|
||||||
|
PoisonQueueLength float64 `perflib:"Poison Queue Length"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildTransportQueues() error {
|
||||||
|
counters := []string{
|
||||||
|
externalActiveRemoteDeliveryQueueLength,
|
||||||
|
internalActiveRemoteDeliveryQueueLength,
|
||||||
|
activeMailboxDeliveryQueueLength,
|
||||||
|
retryMailboxDeliveryQueueLength,
|
||||||
|
unreachableQueueLength,
|
||||||
|
externalLargestDeliveryQueueLength,
|
||||||
|
internalLargestDeliveryQueueLength,
|
||||||
|
poisonQueueLength,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorTransportQueues, err = perfdata.NewCollector(perfdata.V1, "MSExchangeTransport Queues", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchangeTransport Queues collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectTransportQueues(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibTransportQueues
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchangeTransport Queues"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, queue := range data {
|
||||||
|
labelName := c.toLabelName(queue.Name)
|
||||||
|
if strings.HasSuffix(labelName, "_total") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.externalActiveRemoteDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
queue.ExternalActiveRemoteDeliveryQueueLength,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.internalActiveRemoteDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
queue.InternalActiveRemoteDeliveryQueueLength,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeMailboxDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
queue.ActiveMailboxDeliveryQueueLength,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.retryMailboxDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
queue.RetryMailboxDeliveryQueueLength,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.unreachableQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
queue.UnreachableQueueLength,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.externalLargestDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
queue.ExternalLargestDeliveryQueueLength,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.internalLargestDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
queue.InternalLargestDeliveryQueueLength,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.poisonQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
queue.PoisonQueueLength,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHTransportQueues(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorTransportQueues.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchangeTransport Queues: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchangeTransport Queues returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, data := range perfData {
|
||||||
|
labelName := c.toLabelName(name)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.externalActiveRemoteDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[externalActiveRemoteDeliveryQueueLength].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.internalActiveRemoteDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[internalActiveRemoteDeliveryQueueLength].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeMailboxDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[activeMailboxDeliveryQueueLength].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.retryMailboxDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[retryMailboxDeliveryQueueLength].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.unreachableQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[unreachableQueueLength].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.externalLargestDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[externalLargestDeliveryQueueLength].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.internalLargestDeliveryQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[internalLargestDeliveryQueueLength].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.poisonQueueLength,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[poisonQueueLength].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
146
internal/collector/exchange/exchange_workload_management.go
Normal file
146
internal/collector/exchange/exchange_workload_management.go
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||||
|
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||||
|
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
activeTasks = "ActiveTasks"
|
||||||
|
completedTasks = "CompletedTasks"
|
||||||
|
queuedTasks = "QueuedTasks"
|
||||||
|
yieldedTasks = "YieldedTasks"
|
||||||
|
isActive = "Active"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Perflib: [19430] MSExchange WorkloadManagement Workloads.
|
||||||
|
type perflibWorkloadManagementWorkloads struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
ActiveTasks float64 `perflib:"ActiveTasks"`
|
||||||
|
CompletedTasks float64 `perflib:"CompletedTasks"`
|
||||||
|
QueuedTasks float64 `perflib:"QueuedTasks"`
|
||||||
|
YieldedTasks float64 `perflib:"YieldedTasks"`
|
||||||
|
IsActive float64 `perflib:"Active"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) buildWorkloadManagementWorkloads() error {
|
||||||
|
counters := []string{
|
||||||
|
activeTasks,
|
||||||
|
completedTasks,
|
||||||
|
queuedTasks,
|
||||||
|
yieldedTasks,
|
||||||
|
isActive,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollectorWorkloadManagementWorkloads, err = perfdata.NewCollector(perfdata.V1, "MSExchange WorkloadManagement Workloads", perfdata.AllInstances, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create MSExchange WorkloadManagement Workloads collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectWorkloadManagementWorkloads(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
|
var data []perflibWorkloadManagementWorkloads
|
||||||
|
|
||||||
|
if err := v1.UnmarshalObject(ctx.PerfObjects["MSExchange WorkloadManagement Workloads"], &data, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, instance := range data {
|
||||||
|
labelName := c.toLabelName(instance.Name)
|
||||||
|
if strings.HasSuffix(labelName, "_total") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeTasks,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
instance.ActiveTasks,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.completedTasks,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
instance.CompletedTasks,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.queuedTasks,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
instance.QueuedTasks,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.yieldedTasks,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
instance.YieldedTasks,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.isActive,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
instance.IsActive,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPDHWorkloadManagementWorkloads(ch chan<- prometheus.Metric) error {
|
||||||
|
perfData, err := c.perfDataCollectorWorkloadManagementWorkloads.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect MSExchange WorkloadManagement Workloads: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perfData) == 0 {
|
||||||
|
return errors.New("perflib query for MSExchange WorkloadManagement Workloads returned empty result set")
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, data := range perfData {
|
||||||
|
labelName := c.toLabelName(name)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.activeTasks,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[activeTasks].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.completedTasks,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[completedTasks].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.queuedTasks,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[queuedTasks].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.yieldedTasks,
|
||||||
|
prometheus.CounterValue,
|
||||||
|
data[yieldedTasks].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.isActive,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
data[isActive].FirstValue,
|
||||||
|
labelName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user