adcs: Implement PDH collector (#1648)

This commit is contained in:
Jan-Otto Kröpke
2024-09-28 13:23:08 +02:00
committed by GitHub
parent 622813343f
commit 798bf32dec
5 changed files with 235 additions and 81 deletions

View File

@@ -4,10 +4,11 @@ package adcs
import (
"errors"
"fmt"
"log/slog"
"strings"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/pkg/perfdata"
"github.com/prometheus-community/windows_exporter/pkg/perflib"
"github.com/prometheus-community/windows_exporter/pkg/types"
"github.com/prometheus-community/windows_exporter/pkg/utils"
@@ -24,6 +25,8 @@ var ConfigDefaults = Config{}
type Collector struct {
config Config
perfDataCollector *perfdata.Collector
challengeResponseProcessingTime *prometheus.Desc
challengeResponsesPerSecond *prometheus.Desc
failedRequestsPerSecond *prometheus.Desc
@@ -60,6 +63,10 @@ func (c *Collector) GetName() string {
}
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() {
return []string{}, nil
}
return []string{"Certification Authority"}, nil
}
@@ -68,6 +75,31 @@ func (c *Collector) Close(_ *slog.Logger) error {
}
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
if utils.PDHEnabled() {
counters := []string{
RequestsPerSecond,
RequestProcessingTime,
RetrievalsPerSecond,
RetrievalProcessingTime,
FailedRequestsPerSecond,
IssuedRequestsPerSecond,
PendingRequestsPerSecond,
RequestCryptographicSigningTime,
RequestPolicyModuleProcessingTime,
ChallengeResponsesPerSecond,
ChallengeResponseProcessingTime,
SignedCertificateTimestampListsPerSecond,
SignedCertificateTimestampListProcessingTime,
}
var err error
c.perfDataCollector, err = perfdata.NewCollector("Processor Information", []string{"*"}, counters)
if err != nil {
return fmt.Errorf("failed to create Processor Information collector: %w", err)
}
}
c.requestsPerSecond = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "requests_total"),
"Total certificate requests processed",
@@ -151,6 +183,10 @@ func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) 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))
if err := c.collectADCSCounters(ctx, logger, ch); err != nil {
logger.Error("failed collecting ADCS metrics",
@@ -163,23 +199,6 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch ch
return nil
}
type perflibADCS struct {
Name string
RequestsPerSecond float64 `perflib:"Requests/sec"`
RequestProcessingTime float64 `perflib:"Request processing time (ms)"`
RetrievalsPerSecond float64 `perflib:"Retrievals/sec"`
RetrievalProcessingTime float64 `perflib:"Retrieval processing time (ms)"`
FailedRequestsPerSecond float64 `perflib:"Failed Requests/sec"`
IssuedRequestsPerSecond float64 `perflib:"Issued Requests/sec"`
PendingRequestsPerSecond float64 `perflib:"Pending Requests/sec"`
RequestCryptographicSigningTime float64 `perflib:"Request cryptographic signing time (ms)"`
RequestPolicyModuleProcessingTime float64 `perflib:"Request policy module processing time (ms)"`
ChallengeResponsesPerSecond float64 `perflib:"Challenge Responses/sec"`
ChallengeResponseProcessingTime float64 `perflib:"Challenge Response processing time (ms)"`
SignedCertificateTimestampListsPerSecond float64 `perflib:"Signed Certificate Timestamp Lists/sec"`
SignedCertificateTimestampListProcessingTime float64 `perflib:"Signed Certificate Timestamp List processing time (ms)"`
}
func (c *Collector) collectADCSCounters(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
dst := make([]perflibADCS, 0)
@@ -197,10 +216,10 @@ func (c *Collector) collectADCSCounters(ctx *types.ScrapeContext, logger *slog.L
}
for _, d := range dst {
n := strings.ToLower(d.Name)
if n == "" {
if d.Name == "" {
continue
}
ch <- prometheus.MustNewConstMetric(
c.requestsPerSecond,
prometheus.CounterValue,
@@ -283,3 +302,97 @@ func (c *Collector) collectADCSCounters(ctx *types.ScrapeContext, logger *slog.L
return nil
}
func (c *Collector) collectPDH(ch chan<- prometheus.Metric) error {
data, err := c.perfDataCollector.Collect()
if err != nil {
return fmt.Errorf("failed to collect Certification Authority (ADCS) metrics: %w", err)
}
if len(data) == 0 {
return errors.New("perflib query for Certification Authority (ADCS) returned empty result set")
}
for name, adcsData := range data {
ch <- prometheus.MustNewConstMetric(
c.requestsPerSecond,
prometheus.CounterValue,
adcsData[RequestsPerSecond].FirstValue,
name,
)
ch <- prometheus.MustNewConstMetric(
c.requestProcessingTime,
prometheus.GaugeValue,
utils.MilliSecToSec(adcsData[RequestProcessingTime].FirstValue),
name,
)
ch <- prometheus.MustNewConstMetric(
c.retrievalsPerSecond,
prometheus.CounterValue,
adcsData[RetrievalsPerSecond].FirstValue,
name,
)
ch <- prometheus.MustNewConstMetric(
c.retrievalProcessingTime,
prometheus.GaugeValue,
utils.MilliSecToSec(adcsData[RetrievalProcessingTime].FirstValue),
name,
)
ch <- prometheus.MustNewConstMetric(
c.failedRequestsPerSecond,
prometheus.CounterValue,
adcsData[FailedRequestsPerSecond].FirstValue,
name,
)
ch <- prometheus.MustNewConstMetric(
c.issuedRequestsPerSecond,
prometheus.CounterValue,
adcsData[IssuedRequestsPerSecond].FirstValue,
name,
)
ch <- prometheus.MustNewConstMetric(
c.pendingRequestsPerSecond,
prometheus.CounterValue,
adcsData[PendingRequestsPerSecond].FirstValue,
name,
)
ch <- prometheus.MustNewConstMetric(
c.requestCryptographicSigningTime,
prometheus.GaugeValue,
utils.MilliSecToSec(adcsData[RequestCryptographicSigningTime].FirstValue),
name,
)
ch <- prometheus.MustNewConstMetric(
c.requestPolicyModuleProcessingTime,
prometheus.GaugeValue,
utils.MilliSecToSec(adcsData[RequestPolicyModuleProcessingTime].FirstValue),
name,
)
ch <- prometheus.MustNewConstMetric(
c.challengeResponsesPerSecond,
prometheus.CounterValue,
adcsData[ChallengeResponsesPerSecond].FirstValue,
name,
)
ch <- prometheus.MustNewConstMetric(
c.challengeResponseProcessingTime,
prometheus.GaugeValue,
utils.MilliSecToSec(adcsData[ChallengeResponseProcessingTime].FirstValue),
name,
)
ch <- prometheus.MustNewConstMetric(
c.signedCertificateTimestampListsPerSecond,
prometheus.CounterValue,
adcsData[SignedCertificateTimestampListsPerSecond].FirstValue,
name,
)
ch <- prometheus.MustNewConstMetric(
c.signedCertificateTimestampListProcessingTime,
prometheus.GaugeValue,
utils.MilliSecToSec(adcsData[SignedCertificateTimestampListProcessingTime].FirstValue),
name,
)
}
return nil
}

View File

@@ -0,0 +1,34 @@
package adcs
const (
RequestsPerSecond = "Requests/sec"
RequestProcessingTime = "Request processing time (ms)"
RetrievalsPerSecond = "Retrievals/sec"
RetrievalProcessingTime = "Retrieval processing time (ms)"
FailedRequestsPerSecond = "Failed Requests/sec"
IssuedRequestsPerSecond = "Issued Requests/sec"
PendingRequestsPerSecond = "Pending Requests/sec"
RequestCryptographicSigningTime = "Request cryptographic signing time (ms)"
RequestPolicyModuleProcessingTime = "Request policy module processing time (ms)"
ChallengeResponsesPerSecond = "Challenge Responses/sec"
ChallengeResponseProcessingTime = "Challenge Response processing time (ms)"
SignedCertificateTimestampListsPerSecond = "Signed Certificate Timestamp Lists/sec"
SignedCertificateTimestampListProcessingTime = "Signed Certificate Timestamp List processing time (ms)"
)
type perflibADCS struct {
Name string
RequestsPerSecond float64 `perflib:"Requests/sec"`
RequestProcessingTime float64 `perflib:"Request processing time (ms)"`
RetrievalsPerSecond float64 `perflib:"Retrievals/sec"`
RetrievalProcessingTime float64 `perflib:"Retrieval processing time (ms)"`
FailedRequestsPerSecond float64 `perflib:"Failed Requests/sec"`
IssuedRequestsPerSecond float64 `perflib:"Issued Requests/sec"`
PendingRequestsPerSecond float64 `perflib:"Pending Requests/sec"`
RequestCryptographicSigningTime float64 `perflib:"Request cryptographic signing time (ms)"`
RequestPolicyModuleProcessingTime float64 `perflib:"Request policy module processing time (ms)"`
ChallengeResponsesPerSecond float64 `perflib:"Challenge Responses/sec"`
ChallengeResponseProcessingTime float64 `perflib:"Challenge Response processing time (ms)"`
SignedCertificateTimestampListsPerSecond float64 `perflib:"Signed Certificate Timestamp Lists/sec"`
SignedCertificateTimestampListProcessingTime float64 `perflib:"Signed Certificate Timestamp List processing time (ms)"`
}

View File

@@ -26,3 +26,32 @@ const (
ProcessorUtilityRate = "% Processor Utility"
UserTimeSeconds = "% User Time"
)
type perflibProcessorInformation struct {
Name string
C1TimeSeconds float64 `perflib:"% C1 Time"`
C2TimeSeconds float64 `perflib:"% C2 Time"`
C3TimeSeconds float64 `perflib:"% C3 Time"`
C1TransitionsTotal float64 `perflib:"C1 Transitions/sec"`
C2TransitionsTotal float64 `perflib:"C2 Transitions/sec"`
C3TransitionsTotal float64 `perflib:"C3 Transitions/sec"`
ClockInterruptsTotal float64 `perflib:"Clock Interrupts/sec"`
DPCsQueuedTotal float64 `perflib:"DPCs Queued/sec"`
DPCTimeSeconds float64 `perflib:"% DPC Time"`
IdleBreakEventsTotal float64 `perflib:"Idle Break Events/sec"`
IdleTimeSeconds float64 `perflib:"% Idle Time"`
InterruptsTotal float64 `perflib:"Interrupts/sec"`
InterruptTimeSeconds float64 `perflib:"% Interrupt Time"`
ParkingStatus float64 `perflib:"Parking Status"`
PerformanceLimitPercent float64 `perflib:"% Performance Limit"`
PriorityTimeSeconds float64 `perflib:"% Priority Time"`
PrivilegedTimeSeconds float64 `perflib:"% Privileged Time"`
PrivilegedUtilitySeconds float64 `perflib:"% Privileged Utility"`
ProcessorFrequencyMHz float64 `perflib:"Processor Frequency"`
ProcessorPerformance float64 `perflib:"% Processor Performance"`
ProcessorMPerf float64 `perflib:"% Processor Performance,secondvalue"`
ProcessorTimeSeconds float64 `perflib:"% Processor Time"`
ProcessorUtilityRate float64 `perflib:"% Processor Utility"`
ProcessorRTC float64 `perflib:"% Processor Utility,secondvalue"`
UserTimeSeconds float64 `perflib:"% User Time"`
}

View File

@@ -142,7 +142,6 @@ func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
[]string{"core"},
nil,
)
c.cStateSecondsTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "cstate_seconds_total"),
"Time spent in low-power idle state",
@@ -226,42 +225,13 @@ func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
}
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name))
if utils.PDHEnabled() {
return c.collectPDH(ch)
}
return c.collectFull(ctx, logger, ch)
}
logger = logger.With(slog.String("collector", Name))
type perflibProcessorInformation struct {
Name string
C1TimeSeconds float64 `perflib:"% C1 Time"`
C2TimeSeconds float64 `perflib:"% C2 Time"`
C3TimeSeconds float64 `perflib:"% C3 Time"`
C1TransitionsTotal float64 `perflib:"C1 Transitions/sec"`
C2TransitionsTotal float64 `perflib:"C2 Transitions/sec"`
C3TransitionsTotal float64 `perflib:"C3 Transitions/sec"`
ClockInterruptsTotal float64 `perflib:"Clock Interrupts/sec"`
DPCsQueuedTotal float64 `perflib:"DPCs Queued/sec"`
DPCTimeSeconds float64 `perflib:"% DPC Time"`
IdleBreakEventsTotal float64 `perflib:"Idle Break Events/sec"`
IdleTimeSeconds float64 `perflib:"% Idle Time"`
InterruptsTotal float64 `perflib:"Interrupts/sec"`
InterruptTimeSeconds float64 `perflib:"% Interrupt Time"`
ParkingStatus float64 `perflib:"Parking Status"`
PerformanceLimitPercent float64 `perflib:"% Performance Limit"`
PriorityTimeSeconds float64 `perflib:"% Priority Time"`
PrivilegedTimeSeconds float64 `perflib:"% Privileged Time"`
PrivilegedUtilitySeconds float64 `perflib:"% Privileged Utility"`
ProcessorFrequencyMHz float64 `perflib:"Processor Frequency"`
ProcessorPerformance float64 `perflib:"% Processor Performance"`
ProcessorMPerf float64 `perflib:"% Processor Performance,secondvalue"`
ProcessorTimeSeconds float64 `perflib:"% Processor Time"`
ProcessorUtilityRate float64 `perflib:"% Processor Utility"`
ProcessorRTC float64 `perflib:"% Processor Utility,secondvalue"`
UserTimeSeconds float64 `perflib:"% User Time"`
return c.collectFull(ctx, logger, ch)
}
func (c *Collector) collectFull(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {