Skip to content

Commit d95c6ab

Browse files
authored
Optionally enhance "sources" information with NtpData response (#106)
This commit extends the "sources" information with additional peer/source information from the NtpData response. Namely it adds: - Offset - Peer Delay - Peer Dispersion - Peer Response Time - Peer Jitter Asymmetry The additional data collection is hidden behind a new flag `--collector.sources-with-ntpdata` which defaults to `false` Signed-off-by: Rudolph Bott <[email protected]>
1 parent 34189ef commit d95c6ab

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ Flags:
6060
--chrony.timeout=5s Timeout on requests to the Chrony srever.
6161
--[no-]collector.tracking Collect tracking metrics
6262
--[no-]collector.sources Collect sources metrics
63+
--[no-]collector.sources.with-ntpdata
64+
Extend sources with ntpdata metrics (requires socket connection)
6365
--[no-]collector.serverstats
6466
Collect serverstats metrics
6567
--[no-]collector.chmod-socket

collector/collector.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type Exporter struct {
5555
timeout time.Duration
5656

5757
collectSources bool
58+
collectNtpdata bool
5859
collectTracking bool
5960
collectServerstats bool
6061
chmodSocket bool
@@ -86,6 +87,8 @@ type ChronyCollectorConfig struct {
8687

8788
// CollectSources will configure the exporter to collect `chronyc sources`.
8889
CollectSources bool
90+
// CollectNtpData will configure the exporter to extend sources info with `chronyc ntpdata`
91+
CollectNtpdata bool
8992
// CollectTracking will configure the exporter to collect `chronyc tracking`.
9093
CollectTracking bool
9194
// CollectServerstats will configure the exporter to collect `chronyc serverstats`.
@@ -98,6 +101,7 @@ func NewExporter(conf ChronyCollectorConfig, logger *slog.Logger) Exporter {
98101
timeout: conf.Timeout,
99102

100103
collectSources: conf.CollectSources,
104+
collectNtpdata: conf.CollectNtpdata,
101105
collectTracking: conf.CollectTracking,
102106
collectServerstats: conf.CollectServerstats,
103107
chmodSocket: conf.ChmodSocket,
@@ -161,7 +165,7 @@ func (e Exporter) Collect(ch chan<- prometheus.Metric) {
161165
client := chrony.Client{Sequence: 1, Connection: conn}
162166

163167
if e.collectSources {
164-
err = e.getSourcesMetrics(logger, ch, client)
168+
err = e.getSourcesMetrics(logger, ch, client, e.collectNtpdata)
165169
if err != nil {
166170
logger.Debug("Couldn't get sources", "err", err)
167171
up = 0

collector/sources.go

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,59 @@ var (
108108
),
109109
prometheus.GaugeValue,
110110
}
111+
112+
sourcesPeerOffset = typedDesc{
113+
prometheus.NewDesc(
114+
prometheus.BuildFQName(namespace, sourcesSubsystem, "peer_offset_seconds"),
115+
"Chrony sources peer offset",
116+
[]string{"source_address", "source_name"},
117+
nil,
118+
),
119+
prometheus.GaugeValue,
120+
}
121+
122+
sourcesPeerDelay = typedDesc{
123+
prometheus.NewDesc(
124+
prometheus.BuildFQName(namespace, sourcesSubsystem, "peer_delay_seconds"),
125+
"Chrony sources peer delay",
126+
[]string{"source_address", "source_name"},
127+
nil,
128+
),
129+
prometheus.GaugeValue,
130+
}
131+
132+
sourcesPeerDispersion = typedDesc{
133+
prometheus.NewDesc(
134+
prometheus.BuildFQName(namespace, sourcesSubsystem, "peer_dispersion_seconds"),
135+
"Chrony sources peer dispersion",
136+
[]string{"source_address", "source_name"},
137+
nil,
138+
),
139+
prometheus.GaugeValue,
140+
}
141+
142+
sourcesPeerResponseTime = typedDesc{
143+
prometheus.NewDesc(
144+
prometheus.BuildFQName(namespace, sourcesSubsystem, "peer_response_time_seconds"),
145+
"Chrony sources peer response time",
146+
[]string{"source_address", "source_name"},
147+
nil,
148+
),
149+
prometheus.GaugeValue,
150+
}
151+
152+
sourcesPeerJitterAsymmetry = typedDesc{
153+
prometheus.NewDesc(
154+
prometheus.BuildFQName(namespace, sourcesSubsystem, "peer_jitter_asymmetry_seconds"),
155+
"Chrony sources peer jitter asymmetry",
156+
[]string{"source_address", "source_name"},
157+
nil,
158+
),
159+
prometheus.GaugeValue,
160+
}
111161
)
112162

113-
func (e Exporter) getSourcesMetrics(logger *slog.Logger, ch chan<- prometheus.Metric, client chrony.Client) error {
163+
func (e Exporter) getSourcesMetrics(logger *slog.Logger, ch chan<- prometheus.Metric, client chrony.Client, collectNtpdata bool) error {
114164
packet, err := client.Communicate(chrony.NewSourcesPacket())
115165
if err != nil {
116166
return err
@@ -157,6 +207,22 @@ func (e Exporter) getSourcesMetrics(logger *slog.Logger, ch chan<- prometheus.Me
157207
ch <- sourcesPollInterval.mustNewConstMetric(math.Pow(2, float64(r.Poll)), sourceAddress, sourceName)
158208
ch <- sourcesStateInfo.mustNewConstMetric(1.0, sourceAddress, sourceName, r.State.String(), r.Mode.String())
159209
ch <- sourcesStratum.mustNewConstMetric(float64(r.Stratum), sourceAddress, sourceName)
210+
211+
if collectNtpdata {
212+
ntpDataPacket, err := client.Communicate(chrony.NewNTPDataPacket(r.IPAddr))
213+
if err != nil {
214+
return fmt.Errorf("Failed to get ntpdata response for: %s", r.IPAddr)
215+
}
216+
ntpData, ok := ntpDataPacket.(*chrony.ReplyNTPData)
217+
if !ok {
218+
return fmt.Errorf("Got wrong 'ntpdata' response: %q", packet)
219+
}
220+
ch <- sourcesPeerOffset.mustNewConstMetric(ntpData.Offset, sourceAddress, sourceName)
221+
ch <- sourcesPeerDelay.mustNewConstMetric(ntpData.PeerDelay, sourceAddress, sourceName)
222+
ch <- sourcesPeerResponseTime.mustNewConstMetric(ntpData.ResponseTime, sourceAddress, sourceName)
223+
ch <- sourcesPeerDispersion.mustNewConstMetric(ntpData.PeerDispersion, sourceAddress, sourceName)
224+
ch <- sourcesPeerJitterAsymmetry.mustNewConstMetric(ntpData.JitterAsymmetry, sourceAddress, sourceName)
225+
}
160226
}
161227

162228
return nil

main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ func main() {
5757
"Collect sources metrics",
5858
).Default("false").BoolVar(&conf.CollectSources)
5959

60+
kingpin.Flag(
61+
"collector.sources.with-ntpdata",
62+
"Extend sources with ntpdata metrics (requires socket connection)",
63+
).Default("false").BoolVar(&conf.CollectNtpdata)
64+
6065
kingpin.Flag(
6166
"collector.serverstats",
6267
"Collect serverstats metrics",

0 commit comments

Comments
 (0)