2023-11-04 19:51:35 +00:00
//go:build windows
package time
import (
"errors"
"github.com/alecthomas/kingpin/v2"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/prometheus-community/windows_exporter/pkg/perflib"
"github.com/prometheus-community/windows_exporter/pkg/types"
"github.com/prometheus-community/windows_exporter/pkg/winversion"
"github.com/prometheus/client_golang/prometheus"
)
const Name = "time"
type Config struct { }
var ConfigDefaults = Config { }
// collector is a Prometheus collector for Perflib counter metrics
type collector struct {
logger log . Logger
ClockFrequencyAdjustmentPPBTotal * prometheus . Desc
ComputedTimeOffset * prometheus . Desc
NTPClientTimeSourceCount * prometheus . Desc
NTPRoundtripDelay * prometheus . Desc
NTPServerIncomingRequestsTotal * prometheus . Desc
NTPServerOutgoingResponsesTotal * prometheus . Desc
}
func New ( logger log . Logger , _ * Config ) types . Collector {
c := & collector { }
c . SetLogger ( logger )
return c
}
func NewWithFlags ( _ * kingpin . Application ) types . Collector {
return & collector { }
}
func ( c * collector ) GetName ( ) string {
return Name
}
func ( c * collector ) SetLogger ( logger log . Logger ) {
c . logger = log . With ( logger , "collector" , Name )
}
func ( c * collector ) GetPerfCounter ( ) ( [ ] string , error ) {
return [ ] string { "Windows Time Service" } , nil
}
func ( c * collector ) Build ( ) error {
if winversion . WindowsVersionFloat <= 6.1 {
return errors . New ( "Windows version older than Server 2016 detected. The time collector will not run and should be disabled via CLI flags or configuration file" )
}
c . ClockFrequencyAdjustmentPPBTotal = prometheus . NewDesc (
prometheus . BuildFQName ( types . Namespace , Name , "clock_frequency_adjustment_ppb_total" ) ,
"Total adjustment made to the local system clock frequency by W32Time in Parts Per Billion (PPB) units." ,
nil ,
nil ,
)
c . ComputedTimeOffset = prometheus . NewDesc (
prometheus . BuildFQName ( types . Namespace , Name , "computed_time_offset_seconds" ) ,
"Absolute time offset between the system clock and the chosen time source, in seconds" ,
nil ,
nil ,
)
c . NTPClientTimeSourceCount = prometheus . NewDesc (
prometheus . BuildFQName ( types . Namespace , Name , "ntp_client_time_sources" ) ,
"Active number of NTP Time sources being used by the client" ,
nil ,
nil ,
)
c . NTPRoundtripDelay = prometheus . NewDesc (
prometheus . BuildFQName ( types . Namespace , Name , "ntp_round_trip_delay_seconds" ) ,
"Roundtrip delay experienced by the NTP client in receiving a response from the server for the most recent request, in seconds" ,
nil ,
nil ,
)
c . NTPServerOutgoingResponsesTotal = prometheus . NewDesc (
prometheus . BuildFQName ( types . Namespace , Name , "ntp_server_outgoing_responses_total" ) ,
"Total number of requests responded to by NTP server" ,
nil ,
nil ,
)
c . NTPServerIncomingRequestsTotal = prometheus . NewDesc (
prometheus . BuildFQName ( types . Namespace , Name , "ntp_server_incoming_requests_total" ) ,
"Total number of requests received by NTP server" ,
nil ,
nil ,
)
return nil
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func ( c * collector ) Collect ( ctx * types . ScrapeContext , ch chan <- prometheus . Metric ) error {
2024-05-11 10:05:45 +00:00
if err := c . collect ( ctx , ch ) ; err != nil {
_ = level . Error ( c . logger ) . Log ( "msg" , "failed collecting time metrics" , "err" , err )
2023-11-04 19:51:35 +00:00
return err
}
return nil
}
// Perflib "Windows Time Service"
type windowsTime struct {
ClockFrequencyAdjustmentPPBTotal float64 ` perflib:"Clock Frequency Adjustment (ppb)" `
ComputedTimeOffset float64 ` perflib:"Computed Time Offset" `
NTPClientTimeSourceCount float64 ` perflib:"NTP Client Time Source Count" `
NTPRoundtripDelay float64 ` perflib:"NTP Roundtrip Delay" `
NTPServerIncomingRequestsTotal float64 ` perflib:"NTP Server Incoming Requests" `
NTPServerOutgoingResponsesTotal float64 ` perflib:"NTP Server Outgoing Responses" `
}
2024-05-11 10:05:45 +00:00
func ( c * collector ) collect ( ctx * types . ScrapeContext , ch chan <- prometheus . Metric ) error {
2023-11-04 19:51:35 +00:00
var dst [ ] windowsTime // Single-instance class, array is required but will have single entry.
if err := perflib . UnmarshalObject ( ctx . PerfObjects [ "Windows Time Service" ] , & dst , c . logger ) ; err != nil {
2024-05-11 10:05:45 +00:00
return err
2023-11-04 19:51:35 +00:00
}
ch <- prometheus . MustNewConstMetric (
c . ClockFrequencyAdjustmentPPBTotal ,
prometheus . CounterValue ,
dst [ 0 ] . ClockFrequencyAdjustmentPPBTotal ,
)
ch <- prometheus . MustNewConstMetric (
c . ComputedTimeOffset ,
prometheus . GaugeValue ,
dst [ 0 ] . ComputedTimeOffset / 1000000 , // microseconds -> seconds
)
ch <- prometheus . MustNewConstMetric (
c . NTPClientTimeSourceCount ,
prometheus . GaugeValue ,
dst [ 0 ] . NTPClientTimeSourceCount ,
)
ch <- prometheus . MustNewConstMetric (
c . NTPRoundtripDelay ,
prometheus . GaugeValue ,
dst [ 0 ] . NTPRoundtripDelay / 1000000 , // microseconds -> seconds
)
ch <- prometheus . MustNewConstMetric (
c . NTPServerIncomingRequestsTotal ,
prometheus . CounterValue ,
dst [ 0 ] . NTPServerIncomingRequestsTotal ,
)
ch <- prometheus . MustNewConstMetric (
c . NTPServerOutgoingResponsesTotal ,
prometheus . CounterValue ,
dst [ 0 ] . NTPServerOutgoingResponsesTotal ,
)
2024-05-11 10:05:45 +00:00
return nil
2023-11-04 19:51:35 +00:00
}