mirror of
https://github.com/prometheus/node_exporter.git
synced 2024-11-10 07:34:09 -08:00
Merge pull request #250 from sky-uk/ntp-rtt
Use the offset calculation that includes round trip time in the ntp collector
This commit is contained in:
commit
d4799999fc
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -26,3 +26,8 @@ dependencies-stamp
|
|||
/.deps
|
||||
/.release
|
||||
/.tarballs
|
||||
|
||||
# Intellij
|
||||
|
||||
/.idea
|
||||
*.iml
|
||||
|
|
|
@ -18,7 +18,6 @@ package collector
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/ntp"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
@ -58,13 +57,13 @@ func NewNtpCollector() (Collector, error) {
|
|||
}
|
||||
|
||||
func (c *ntpCollector) Update(ch chan<- prometheus.Metric) (err error) {
|
||||
t, err := ntp.TimeV(*ntpServer, byte(*ntpProtocolVersion))
|
||||
resp, err := ntp.Query(*ntpServer, *ntpProtocolVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't get NTP drift: %s", err)
|
||||
}
|
||||
drift := t.Sub(time.Now())
|
||||
log.Debugf("Set ntp_drift_seconds: %f", drift.Seconds())
|
||||
c.drift.Set(drift.Seconds())
|
||||
driftSeconds := resp.ClockOffset.Seconds()
|
||||
log.Debugf("Set ntp_drift_seconds: %f", driftSeconds)
|
||||
c.drift.Set(driftSeconds)
|
||||
c.drift.Collect(ch)
|
||||
return err
|
||||
}
|
||||
|
|
4
vendor/github.com/beevik/ntp/CONTRIBUTORS
generated
vendored
Normal file
4
vendor/github.com/beevik/ntp/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
Brett Vickers (beevik)
|
||||
Mikhail Salosin (AlphaB)
|
||||
Anton Tolchanov (knyar)
|
||||
Christopher Batey (chbatey)
|
3
vendor/github.com/beevik/ntp/README.md
generated
vendored
3
vendor/github.com/beevik/ntp/README.md
generated
vendored
|
@ -1,3 +1,6 @@
|
|||
[![Build Status](https://travis-ci.org/beevik/ntp.svg?branch=master)](https://travis-ci.org/beevik/ntp)
|
||||
[![GoDoc](https://godoc.org/github.com/beevik/ntp?status.svg)](https://godoc.org/github.com/beevik/ntp)
|
||||
|
||||
ntp
|
||||
===
|
||||
|
||||
|
|
159
vendor/github.com/beevik/ntp/ntp.go
generated
vendored
159
vendor/github.com/beevik/ntp/ntp.go
generated
vendored
|
@ -2,10 +2,11 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ntp provides a simple mechanism for querying the current time
|
||||
// from a remote NTP server. This package only supports NTP client mode
|
||||
// behavior and version 4 of the NTP protocol. See RFC 5905.
|
||||
// Approach inspired by go-nuts post by Michael Hofmann:
|
||||
// Package ntp provides a simple mechanism for querying the current time from
|
||||
// a remote NTP server. This package only supports NTP client mode behavior
|
||||
// and version 4 of the NTP protocol. See RFC 5905. Approach inspired by go-
|
||||
// nuts post by Michael Hofmann:
|
||||
//
|
||||
// https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/FlcdMU5fkLQ
|
||||
package ntp
|
||||
|
||||
|
@ -28,16 +29,43 @@ const (
|
|||
reservedPrivate
|
||||
)
|
||||
|
||||
const (
|
||||
maxStratum = 16
|
||||
nanoPerSec = 1000000000
|
||||
)
|
||||
|
||||
var (
|
||||
timeout = 5 * time.Second
|
||||
ntpEpoch = time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
)
|
||||
|
||||
type ntpTime struct {
|
||||
Seconds uint32
|
||||
Fraction uint32
|
||||
}
|
||||
|
||||
func (t ntpTime) UTC() time.Time {
|
||||
nsec := uint64(t.Seconds)*1e9 + (uint64(t.Fraction) * 1e9 >> 32)
|
||||
return time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nsec))
|
||||
func (t ntpTime) Time() time.Time {
|
||||
return ntpEpoch.Add(t.sinceEpoch())
|
||||
}
|
||||
|
||||
// sinceEpoch converts the ntpTime record t into a duration since the NTP
|
||||
// epoch time (Jan 1, 1900).
|
||||
func (t ntpTime) sinceEpoch() time.Duration {
|
||||
sec := time.Duration(t.Seconds) * time.Second
|
||||
frac := time.Duration(uint64(t.Fraction) * nanoPerSec >> 32)
|
||||
return sec + frac
|
||||
}
|
||||
|
||||
// toNtpTime converts the time value t into an ntpTime representation.
|
||||
func toNtpTime(t time.Time) ntpTime {
|
||||
nsec := uint64(t.Sub(ntpEpoch))
|
||||
return ntpTime{
|
||||
Seconds: uint32(nsec / nanoPerSec),
|
||||
Fraction: uint32((nsec % nanoPerSec) << 32 / nanoPerSec),
|
||||
}
|
||||
}
|
||||
|
||||
// msg is an internal representation of an NTP packet.
|
||||
type msg struct {
|
||||
LiVnMode byte // Leap Indicator (2) + Version (3) + Mode (3)
|
||||
Stratum byte
|
||||
|
@ -45,69 +73,134 @@ type msg struct {
|
|||
Precision byte
|
||||
RootDelay uint32
|
||||
RootDispersion uint32
|
||||
ReferenceId uint32
|
||||
ReferenceID uint32
|
||||
ReferenceTime ntpTime
|
||||
OriginTime ntpTime
|
||||
ReceiveTime ntpTime
|
||||
TransmitTime ntpTime
|
||||
}
|
||||
|
||||
// SetVersion sets the NTP protocol version on the message.
|
||||
func (m *msg) SetVersion(v byte) {
|
||||
m.LiVnMode = (m.LiVnMode & 0xc7) | v<<3
|
||||
// setVersion sets the NTP protocol version on the message.
|
||||
func (m *msg) setVersion(v int) {
|
||||
m.LiVnMode = (m.LiVnMode & 0xc7) | uint8(v)<<3
|
||||
}
|
||||
|
||||
// SetMode sets the NTP protocol mode on the message.
|
||||
func (m *msg) SetMode(md mode) {
|
||||
// setMode sets the NTP protocol mode on the message.
|
||||
func (m *msg) setMode(md mode) {
|
||||
m.LiVnMode = (m.LiVnMode & 0xf8) | byte(md)
|
||||
}
|
||||
|
||||
// Time returns the "receive time" from the remote NTP server
|
||||
// specifed as host. NTP client mode is used.
|
||||
func getTime(host string, version byte) (time.Time, error) {
|
||||
// A Response contains time data, some of which is returned by the NTP server
|
||||
// and some of which is calculated by the client.
|
||||
type Response struct {
|
||||
Time time.Time // receive time reported by the server
|
||||
RTT time.Duration // round-trip time between client and server
|
||||
ClockOffset time.Duration // local clock offset relative to server
|
||||
Stratum uint8 // stratum level of NTP server's clock
|
||||
}
|
||||
|
||||
// Query returns information from the remote NTP server specifed as host. NTP
|
||||
// client mode is used.
|
||||
func Query(host string, version int) (*Response, error) {
|
||||
m, err := getTime(host, version)
|
||||
now := toNtpTime(time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &Response{
|
||||
Time: m.ReceiveTime.Time(),
|
||||
RTT: rtt(m.OriginTime, m.ReceiveTime, m.TransmitTime, now),
|
||||
ClockOffset: offset(m.OriginTime, m.ReceiveTime, m.TransmitTime, now),
|
||||
Stratum: m.Stratum,
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc5905#section-7.3
|
||||
if r.Stratum == 0 {
|
||||
r.Stratum = maxStratum
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Time returns the "receive time" from the remote NTP server specifed as
|
||||
// host. NTP client mode is used.
|
||||
func getTime(host string, version int) (*msg, error) {
|
||||
if version < 2 || version > 4 {
|
||||
panic("ntp: invalid version number")
|
||||
}
|
||||
|
||||
raddr, err := net.ResolveUDPAddr("udp", host+":123")
|
||||
if err != nil {
|
||||
return time.Now(), err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
con, err := net.DialUDP("udp", nil, raddr)
|
||||
if err != nil {
|
||||
return time.Now(), err
|
||||
return nil, err
|
||||
}
|
||||
defer con.Close()
|
||||
con.SetDeadline(time.Now().Add(5 * time.Second))
|
||||
con.SetDeadline(time.Now().Add(timeout))
|
||||
|
||||
m := new(msg)
|
||||
m.SetMode(client)
|
||||
m.SetVersion(version)
|
||||
m.setMode(client)
|
||||
m.setVersion(version)
|
||||
m.TransmitTime = toNtpTime(time.Now())
|
||||
|
||||
err = binary.Write(con, binary.BigEndian, m)
|
||||
if err != nil {
|
||||
return time.Now(), err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = binary.Read(con, binary.BigEndian, m)
|
||||
if err != nil {
|
||||
return time.Now(), err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := m.ReceiveTime.UTC().Local()
|
||||
return t, nil
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// TimeV returns the "receive time" from the remote NTP server
|
||||
// specifed as host. Use the NTP client mode with the requested
|
||||
// version number (2, 3, or 4).
|
||||
func TimeV(host string, version byte) (time.Time, error) {
|
||||
return getTime(host, version)
|
||||
// TimeV returns the "receive time" from the remote NTP server specifed as
|
||||
// host. Use the NTP client mode with the requested version number (2, 3, or
|
||||
// 4).
|
||||
func TimeV(host string, version int) (time.Time, error) {
|
||||
m, err := getTime(host, version)
|
||||
if err != nil {
|
||||
return time.Now(), err
|
||||
}
|
||||
return m.ReceiveTime.Time().Local(), nil
|
||||
}
|
||||
|
||||
// Time returns the "receive time" from the remote NTP server
|
||||
// specifed as host. NTP client mode version 4 is used.
|
||||
// Time returns the "receive time" from the remote NTP server specifed as
|
||||
// host. NTP client mode version 4 is used.
|
||||
func Time(host string) (time.Time, error) {
|
||||
return getTime(host, 4)
|
||||
return TimeV(host, 4)
|
||||
}
|
||||
|
||||
func rtt(t1, t2, t3, t4 ntpTime) time.Duration {
|
||||
// round trip delay time (https://tools.ietf.org/html/rfc5905#section-8)
|
||||
// T1 = client send time
|
||||
// T2 = server receive time
|
||||
// T3 = server reply time
|
||||
// T4 = client receive time
|
||||
//
|
||||
// RTT d:
|
||||
// d = (T4-T1) - (T3-T2)
|
||||
a := t4.Time().Sub(t1.Time())
|
||||
b := t3.Time().Sub(t2.Time())
|
||||
return a - b
|
||||
}
|
||||
|
||||
func offset(t1, t2, t3, t4 ntpTime) time.Duration {
|
||||
// local offset equation (https://tools.ietf.org/html/rfc5905#section-8)
|
||||
// T1 = client send time
|
||||
// T2 = server receive time
|
||||
// T3 = server reply time
|
||||
// T4 = client receive time
|
||||
//
|
||||
// Local clock offset t:
|
||||
// t = ((T2-T1) + (T3-T4)) / 2
|
||||
a := t2.Time().Sub(t1.Time())
|
||||
b := t3.Time().Sub(t4.Time())
|
||||
return (a + b) / time.Duration(2)
|
||||
}
|
||||
|
|
5
vendor/vendor.json
vendored
5
vendor/vendor.json
vendored
|
@ -8,9 +8,10 @@
|
|||
"revisionTime": "2016-01-18T19:00:32-05:00"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "JhaYHdVIj52Fpdcb7DuDjr/gk0Q=",
|
||||
"path": "github.com/beevik/ntp",
|
||||
"revision": "283ed9d548825a1dae0994311560e8dbf8efac68",
|
||||
"revisionTime": "2015-11-09T15:30:19-08:00"
|
||||
"revision": "f0545e6f2c3cb0d0a2ed115b88c539d8e5247ef3",
|
||||
"revisionTime": "2016-05-31T23:09:58Z"
|
||||
},
|
||||
{
|
||||
"path": "github.com/beorn7/perks/quantile",
|
||||
|
|
Loading…
Reference in a new issue