Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e51a24b

Browse files
committed
Add response logging function
Response.Log writes a human-readable representation of the NTP response to the provided output writer. Meant for debugging purposes.
1 parent 644d2f7 commit e51a24b

4 files changed

Lines changed: 183 additions & 190 deletions

File tree

ntp.go

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import (
1414
"bytes"
1515
"crypto/rand"
1616
"encoding/binary"
17+
"encoding/hex"
1718
"errors"
1819
"fmt"
20+
"io"
1921
"math"
2022
"net"
2123
"strconv"
@@ -57,6 +59,7 @@ const (
5759

5860
// Time constants
5961
nanoPerSec = 1_000_000_000
62+
timeFormat = "Mon Jan _2 2006 15:04:05.00000000 (MST)"
6063

6164
// Fixed-point constants (Q*.16, Q*.28, Q*.32)
6265
mask16 = (1 << 16) - 1 // 0x0000ffff
@@ -458,6 +461,45 @@ func (r *Response) IsKissOfDeath() bool {
458461
return r.Version < 5 && r.Stratum == 0
459462
}
460463

464+
// Log outputs a human-readable representation of the NTP response to the
465+
// provided io.Writer. Meant for debugging purposes.
466+
func (r *Response) Log(w io.Writer) {
467+
now := time.Now().Local()
468+
fmt.Fprintf(w, " Version: %d\n", r.Version)
469+
fmt.Fprintf(w, "ClockOffset: %s\n", r.ClockOffset)
470+
fmt.Fprintf(w, " RTT: %s\n", r.RTT)
471+
fmt.Fprintf(w, " SystemTime: %s\n", fmtTime(now))
472+
fmt.Fprintf(w, " ~TrueTime: %s\n", fmtTime(now.Add(r.ClockOffset)))
473+
fmt.Fprintf(w, " ClientXmit: %s\n", fmtTime(r.Timestamps.ClientXmit))
474+
fmt.Fprintf(w, " ServerRecv: %s\n", fmtTime(r.Timestamps.ServerRecv))
475+
fmt.Fprintf(w, " ServerXmit: %s\n", fmtTime(r.Timestamps.ServerXmit))
476+
fmt.Fprintf(w, " ClientRecv: %s\n", fmtTime(r.Timestamps.ClientRecv))
477+
fmt.Fprintf(w, " Stratum: %d\n", r.Stratum)
478+
fmt.Fprintf(w, " Leap: %s\n", fmtLeap(r.Leap))
479+
fmt.Fprintf(w, " Flags: %s\n", fmtFlags(r.Flags))
480+
fmt.Fprintf(w, " Era: %d\n", r.Era)
481+
fmt.Fprintf(w, " Timescale: %s\n", fmtTimescale(r.Timescale))
482+
fmt.Fprintf(w, " Poll: %s\n", r.Poll)
483+
fmt.Fprintf(w, " Precision: %s\n", r.Precision)
484+
fmt.Fprintf(w, " RootDelay: %s\n", r.RootDelay)
485+
fmt.Fprintf(w, " RootDisp: %s\n", r.RootDispersion)
486+
fmt.Fprintf(w, " RootDist: %s\n", r.RootDistance)
487+
fmt.Fprintf(w, " MinError: %s\n", r.MinError)
488+
fmt.Fprintf(w, " RefTime: %s\n", fmtTime(r.ReferenceTime))
489+
if r.Version == 5 {
490+
fmt.Fprintf(w, " RefIDBytes: %s\n", fmtRefIDFilter(r.ReferenceIDFilterValues))
491+
fmt.Fprintf(w, " Correction: %s\n", fmtCorrection(r.Correction))
492+
fmt.Fprintf(w, " Offsets: %s\n", fmtTimescaleOffsets(r.TimescaleOffsets))
493+
fmt.Fprintf(w, " MonoOffset: %s\n", r.MonotonicOffset)
494+
fmt.Fprintf(w, " MonoEpoch: %s\n", fmtEpoch(r.MonotonicEpochID))
495+
fmt.Fprintf(w, " Supported: %v\n", r.SupportedVersions)
496+
fmt.Fprintf(w, " SrvCookie: %s", fmtCookie(r.ServerCookie))
497+
} else {
498+
fmt.Fprintf(w, " RefID: %s (0x%08x)\n", r.ReferenceString(), r.ReferenceID)
499+
fmt.Fprintf(w, " KissCode: %s", fmtKissCode(r.KissCode))
500+
}
501+
}
502+
461503
// ReferenceString returns the response's ReferenceID value formatted as a
462504
// string. If the response's stratum is zero, then the "kiss o' death" string
463505
// is returned. If stratum is one, then the server is a reference clock and
@@ -886,3 +928,126 @@ func toInterval(t int8) time.Duration {
886928
return time.Second
887929
}
888930
}
931+
932+
func fmtCookie(c uint64) string {
933+
if c == 0 {
934+
return "<zero>"
935+
}
936+
return fmt.Sprintf("0x%016x", c)
937+
}
938+
939+
func fmtCorrection(c Correction) string {
940+
if c.OriginDelay < 0 || c.ReturnDelay < 0 {
941+
return "<invalid>"
942+
}
943+
if c.OriginPathID == 0 && c.ReturnPathID == 0 {
944+
return "<none>"
945+
}
946+
return fmt.Sprintf("%s (0x%04x) / %s (0x%04x)",
947+
c.OriginDelay, c.OriginPathID,
948+
c.ReturnDelay, c.ReturnPathID)
949+
}
950+
951+
func fmtEpoch(epoch uint32) string {
952+
if epoch == 0 {
953+
return "<zero>"
954+
}
955+
return fmt.Sprintf("0x%08x", epoch)
956+
}
957+
958+
func fmtKissCode(s string) string {
959+
if s == "" {
960+
return "<empty>"
961+
}
962+
return s
963+
}
964+
965+
func fmtLeap(li LeapIndicator) string {
966+
switch li {
967+
case LeapNoWarning:
968+
return "No Warning"
969+
case LeapAddSecond:
970+
return "Add Second"
971+
case LeapDelSecond:
972+
return "Delete Second"
973+
default:
974+
return "Unknown"
975+
}
976+
}
977+
978+
func fmtRefIDFilter(filter []byte) string {
979+
if filter == nil {
980+
return "<nil>"
981+
}
982+
l := min(len(filter), 24)
983+
return "0x" + hex.EncodeToString(filter[:l]) + "..."
984+
}
985+
986+
func fmtFlags(flags ResponseFlags) string {
987+
ftab := map[ResponseFlags]string{
988+
FlagSynchronized: "Synchronized",
989+
FlagInterleaved: "Interleaved",
990+
}
991+
992+
copy := flags
993+
var s strings.Builder
994+
s.WriteString("[")
995+
for flags != 0 {
996+
f := flags & -flags
997+
if s.Len() > 1 {
998+
s.WriteString(" ")
999+
}
1000+
if ss, ok := ftab[f]; ok {
1001+
s.WriteString(ss)
1002+
} else {
1003+
s.WriteString("Unknown")
1004+
}
1005+
flags &= ^f
1006+
}
1007+
fmt.Fprintf(&s, "] (0x%08x)", uint32(copy))
1008+
return s.String()
1009+
}
1010+
1011+
func fmtTime(value time.Time) string {
1012+
if value.IsZero() {
1013+
return "<zero>"
1014+
}
1015+
return value.Format(timeFormat)
1016+
}
1017+
1018+
func fmtTimescale(ts Timescale) string {
1019+
switch ts {
1020+
case TimescaleUTC:
1021+
return "UTC"
1022+
case TimescaleTAI:
1023+
return "TAI"
1024+
case TimescaleUT1:
1025+
return "UT1"
1026+
case TimescaleUTCSmeared:
1027+
return "UTC(smeared)"
1028+
default:
1029+
return "Unknown"
1030+
}
1031+
}
1032+
1033+
func fmtTimescaleOffset(o TimescaleOffset) string {
1034+
return fmt.Sprintf("%s=%v", fmtTimescale(o.Timescale), o.Offset)
1035+
}
1036+
1037+
func fmtTimescaleOffsets(offsets []TimescaleOffset) string {
1038+
if offsets == nil {
1039+
return "<none>"
1040+
}
1041+
1042+
var s strings.Builder
1043+
s.WriteString("[")
1044+
for i, o := range offsets {
1045+
if i > 0 {
1046+
s.WriteString(", ")
1047+
}
1048+
s.WriteString(fmtTimescaleOffset(o))
1049+
}
1050+
s.WriteString("]")
1051+
1052+
return s.String()
1053+
}

ntp4_test.go

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
package ntp
66

77
import (
8+
"bytes"
89
"errors"
10+
"fmt"
911
"net"
1012
"sync/atomic"
1113
"testing"
@@ -14,33 +16,6 @@ import (
1416
"github.com/stretchr/testify/assert"
1517
)
1618

17-
func logResponseV4(t *testing.T, r *Response) {
18-
now := time.Now().Local()
19-
t.Logf("[%s] Version: %d", host, r.Version)
20-
t.Logf("[%s] ClockOffset: %s", host, r.ClockOffset)
21-
t.Logf("[%s] RTT: %s", host, r.RTT)
22-
t.Logf("[%s] SystemTime: %s", host, fmtTime(now))
23-
t.Logf("[%s] ~TrueTime: %s", host, fmtTime(now.Add(r.ClockOffset)))
24-
t.Logf("[%s] ClientXmit: %s", host, fmtTime(r.Timestamps.ClientXmit))
25-
t.Logf("[%s] ServerRecv: %s", host, fmtTime(r.Timestamps.ServerRecv))
26-
t.Logf("[%s] ServerXmit: %s", host, fmtTime(r.Timestamps.ServerXmit))
27-
t.Logf("[%s] ClientRecv: %s", host, fmtTime(r.Timestamps.ClientRecv))
28-
t.Logf("[%s] Stratum: %d", host, r.Stratum)
29-
t.Logf("[%s] Leap: %s", host, fmtLeapIndicator(r.Leap))
30-
t.Logf("[%s] Flags: %s", host, fmtResponseFlags(r.Flags))
31-
t.Logf("[%s] Era: %d", host, r.Era)
32-
t.Logf("[%s] Timescale: %s", host, fmtTimescale(r.Timescale))
33-
t.Logf("[%s] RefID: %s (0x%08x)", host, r.ReferenceString(), r.ReferenceID)
34-
t.Logf("[%s] RefTime: %s", host, fmtTime(r.ReferenceTime))
35-
t.Logf("[%s] Poll: %s", host, r.Poll)
36-
t.Logf("[%s] Precision: %s", host, r.Precision)
37-
t.Logf("[%s] RootDelay: %s", host, r.RootDelay)
38-
t.Logf("[%s] RootDisp: %s", host, r.RootDispersion)
39-
t.Logf("[%s] RootDist: %s", host, r.RootDistance)
40-
t.Logf("[%s] MinError: %s", host, r.MinError)
41-
t.Logf("[%s] KissCode: %s", host, fmtKissCode(r.KissCode))
42-
}
43-
4419
func TestOnlineBadServerPort(t *testing.T) {
4520
// Not NTP port.
4621
r, err := QueryWithOptions(host+":9", QueryOptions{Timeout: 1 * time.Second})
@@ -54,7 +29,11 @@ func TestOnlineV3Query(t *testing.T) {
5429
return
5530
}
5631
assertValid(t, r)
57-
logResponseV4(t, r)
32+
33+
var buf bytes.Buffer
34+
fmt.Fprintf(&buf, "\n Address: %s\n", host)
35+
r.Log(&buf)
36+
t.Log(buf.String())
5837
}
5938

6039
func TestOnlineV4Query(t *testing.T) {
@@ -63,7 +42,11 @@ func TestOnlineV4Query(t *testing.T) {
6342
return
6443
}
6544
assertValid(t, r)
66-
logResponseV4(t, r)
45+
46+
var buf bytes.Buffer
47+
fmt.Fprintf(&buf, "\n Address: %s\n", host)
48+
r.Log(&buf)
49+
t.Log(buf.String())
6750
}
6851

6952
func TestOnlineV4QueryTimeout(t *testing.T) {

ntp5_test.go

Lines changed: 5 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -7,105 +7,15 @@ package ntp
77
import (
88
"bytes"
99
"encoding/binary"
10-
"encoding/hex"
1110
"fmt"
1211
"net"
13-
"strings"
1412
"testing"
1513
"time"
1614

1715
"github.com/stretchr/testify/assert"
1816
"github.com/stretchr/testify/require"
1917
)
2018

21-
func logResponseV5(t *testing.T, r *Response) {
22-
now := time.Now().Local()
23-
t.Logf("[%s] Version: %d", host, r.Version)
24-
t.Logf("[%s] ClockOffset: %s", host, r.ClockOffset)
25-
t.Logf("[%s] RTT: %s", host, r.RTT)
26-
t.Logf("[%s] Correction: %s", host, fmtCorrection(r.Correction))
27-
t.Logf("[%s] SystemTime: %s", host, fmtTime(now))
28-
t.Logf("[%s] ~TrueTime: %s", host, fmtTime(now.Add(r.ClockOffset)))
29-
t.Logf("[%s] ClientXmit: %s", host, fmtTime(r.Timestamps.ClientXmit))
30-
t.Logf("[%s] ServerRecv: %s", host, fmtTime(r.Timestamps.ServerRecv))
31-
t.Logf("[%s] ServerXmit: %s", host, fmtTime(r.Timestamps.ServerXmit))
32-
t.Logf("[%s] ClientRecv: %s", host, fmtTime(r.Timestamps.ClientRecv))
33-
t.Logf("[%s] Stratum: %d", host, r.Stratum)
34-
t.Logf("[%s] Leap: %s", host, fmtLeapIndicator(r.Leap))
35-
t.Logf("[%s] Flags: %s", host, fmtResponseFlags(r.Flags))
36-
t.Logf("[%s] Era: %d", host, r.Era)
37-
t.Logf("[%s] Timescale: %s", host, fmtTimescale(r.Timescale))
38-
t.Logf("[%s] Offsets: %s", host, fmtTimescaleOffsets(r.TimescaleOffsets))
39-
t.Logf("[%s] RefIDBytes: %s", host, fmtRefIDFilter(r.ReferenceIDFilterValues))
40-
t.Logf("[%s] RefTime: %s", host, fmtTime(r.ReferenceTime))
41-
t.Logf("[%s] MonoOffset: %s", host, r.MonotonicOffset)
42-
t.Logf("[%s] MonoEpoch: %s", host, fmtEpoch(r.MonotonicEpochID))
43-
t.Logf("[%s] Supported: %v", host, r.SupportedVersions)
44-
t.Logf("[%s] Poll: %s", host, r.Poll)
45-
t.Logf("[%s] Precision: %s", host, r.Precision)
46-
t.Logf("[%s] RootDelay: %s", host, r.RootDelay)
47-
t.Logf("[%s] RootDisp: %s", host, r.RootDispersion)
48-
t.Logf("[%s] RootDist: %s", host, r.RootDistance)
49-
t.Logf("[%s] MinError: %s", host, r.MinError)
50-
t.Logf("[%s] SrvCookie: %s", host, fmtCookie(r.ServerCookie))
51-
}
52-
53-
func fmtRefIDFilter(filter []byte) string {
54-
if filter == nil {
55-
return "<nil>"
56-
}
57-
l := min(len(filter), 24)
58-
return "0x" + hex.EncodeToString(filter[:l]) + "..."
59-
}
60-
61-
func fmtEpoch(epoch uint32) string {
62-
if epoch == 0 {
63-
return "<zero>"
64-
}
65-
return fmt.Sprintf("0x%08x", epoch)
66-
}
67-
68-
func fmtTimescaleOffset(o TimescaleOffset) string {
69-
return fmt.Sprintf("%s=%v", fmtTimescale(o.Timescale), o.Offset)
70-
}
71-
72-
func fmtTimescaleOffsets(offsets []TimescaleOffset) string {
73-
if offsets == nil {
74-
return "<none>"
75-
}
76-
77-
var s strings.Builder
78-
s.WriteString("[")
79-
for i, o := range offsets {
80-
if i > 0 {
81-
s.WriteString(", ")
82-
}
83-
s.WriteString(fmtTimescaleOffset(o))
84-
}
85-
s.WriteString("]")
86-
87-
return s.String()
88-
}
89-
90-
func fmtCorrection(c Correction) string {
91-
if c.OriginDelay < 0 || c.ReturnDelay < 0 {
92-
return "<invalid>"
93-
}
94-
if c.OriginPathID == 0 && c.ReturnPathID == 0 {
95-
return "<none>"
96-
}
97-
return fmt.Sprintf("%s (0x%04x) / %s (0x%04x)",
98-
c.OriginDelay, c.OriginPathID,
99-
c.ReturnDelay, c.ReturnPathID)
100-
}
101-
102-
func fmtCookie(c uint64) string {
103-
if c == 0 {
104-
return "<zero>"
105-
}
106-
return fmt.Sprintf("0x%016x", c)
107-
}
108-
10919
func TestOnlineV5Query(t *testing.T) {
11020
if host == "localhost" {
11121
t.Skip("Timeout test not available with localhost NTP server.")
@@ -133,7 +43,11 @@ func TestOnlineV5Query(t *testing.T) {
13343
return
13444
}
13545
assertValid(t, r)
136-
logResponseV5(t, r)
46+
47+
var buf bytes.Buffer
48+
fmt.Fprintf(&buf, "\n Address: %s\n", host)
49+
r.Log(&buf)
50+
t.Log(buf.String())
13751
}
13852

13953
func TestOfflineV5Time32Duration(t *testing.T) {

0 commit comments

Comments
 (0)