Skip to content

Commit

Permalink
Merge pull request #1315 from phibos/ntp_timestamp
Browse files Browse the repository at this point in the history
Add NTPTimeStamp type
  • Loading branch information
bastischubert authored Dec 24, 2024
2 parents 8a12041 + 25feabb commit 0f4ef2f
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 0 deletions.
21 changes: 21 additions & 0 deletions collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,20 @@ func parseDateAndTimeWithPattern(metric *config.Metric, pdu *gosnmp.SnmpPDU, met
return float64(t.Unix()), nil
}

func parseNtpTimestamp(pdu *gosnmp.SnmpPDU) (float64, error) {
var data []byte = pdu.Value.([]byte)

// Prometheus uses the Unix time epoch (seconds since 1970).
// NTP seconds are counted since 1900 and must be corrected
// by removing 70 yrs of seconds (1970-1900) or 2208988800
// seconds.
secs := int64(binary.BigEndian.Uint32(data[:4])) - 2208988800
nanos := (int64(binary.BigEndian.Uint32(data[4:])) * 1e9) >> 32

t := time.Unix(secs, nanos)
return float64(t.Unix()), nil
}

func pduToSamples(indexOids []int, pdu *gosnmp.SnmpPDU, metric *config.Metric, oidToPdu map[string]gosnmp.SnmpPDU, logger *slog.Logger, metrics Metrics) []prometheus.Metric {
var err error
// The part of the OID that is the indexes.
Expand Down Expand Up @@ -598,6 +612,13 @@ func pduToSamples(indexOids []int, pdu *gosnmp.SnmpPDU, metric *config.Metric, o
logger.Debug("Error parsing ParseDateAndTime", "err", err)
return []prometheus.Metric{}
}
case "NTPTimeStamp":
t = prometheus.GaugeValue
value, err = parseNtpTimestamp(pdu)
if err != nil {
logger.Debug("Error parsing NTPTimeStamp", "err", err)
return []prometheus.Metric{}
}
case "EnumAsInfo":
return enumAsInfo(metric, int(value), labelnames, labelvalues)
case "EnumAsStateSet":
Expand Down
23 changes: 23 additions & 0 deletions collector/collector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,29 @@ func TestGetPduLargeValue(t *testing.T) {
}
}

func TestNtpTimestamp(t *testing.T) {
cases := []struct {
pdu *gosnmp.SnmpPDU
result float64
err error
}{
{
pdu: &gosnmp.SnmpPDU{Value: []byte{235, 6, 119, 246, 48, 209, 11, 59}},
result: 1.734080886e+09,
err: nil,
},
}
for _, c := range cases {
got, err := parseNtpTimestamp(c.pdu)
if !reflect.DeepEqual(err, c.err) {
t.Errorf("parseNtpTimestamp(%v) error: got %v, want %v", c.pdu, err, c.err)
}
if !reflect.DeepEqual(got, c.result) {
t.Errorf("parseNtpTimestamp(%v) result: got %v, want %v", c.pdu, got, c.result)
}
}
}

func TestOidToList(t *testing.T) {
cases := []struct {
oid string
Expand Down
1 change: 1 addition & 0 deletions generator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ modules:
# OctetString: A bit string, rendered as 0xff34.
# DateAndTime: An RFC 2579 DateAndTime byte sequence. If the device has no time zone data, UTC is used.
# ParseDateAndTime: Parse a DisplayString and return the timestamp. See datetime_pattern config option
# NTPTimeStamp: Parse the NTP timestamp (RFC-1305, March 1992, Section 3.1) and return Unix timestamp as float.
# DisplayString: An ASCII or UTF-8 string.
# PhysAddress48: A 48 bit MAC address, rendered as 00:01:02:03:04:ff.
# Float: A 32 bit floating-point value with type gauge.
Expand Down
5 changes: 5 additions & 0 deletions generator/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ func prepareTree(nodes *Node, logger *slog.Logger) map[string]*Node {
if n.TextualConvention == "ParseDateAndTime" {
n.Type = "ParseDateAndTime"
}
if n.TextualConvention == "NTPTimeStamp" {
n.Type = "NTPTimeStamp"
}
// Convert RFC 4001 InetAddress types textual convention to type.
if n.TextualConvention == "InetAddressIPv4" || n.TextualConvention == "InetAddressIPv6" || n.TextualConvention == "InetAddress" {
n.Type = n.TextualConvention
Expand Down Expand Up @@ -170,6 +173,8 @@ func metricType(t string) (string, bool) {
return t, true
case "ParseDateAndTime":
return t, true
case "NTPTimeStamp":
return t, true
case "EnumAsInfo", "EnumAsStateSet":
return t, true
default:
Expand Down
12 changes: 12 additions & 0 deletions generator/tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ func TestTreePrepare(t *testing.T) {
in: &Node{Oid: "1", Type: "OctectString", TextualConvention: "InetAddress"},
out: &Node{Oid: "1", Type: "InetAddress", TextualConvention: "InetAddress"},
},
// NTPTimeStamp
{
in: &Node{Oid: "1", Type: "OctectString", TextualConvention: "NTPTimeStamp"},
out: &Node{Oid: "1", Type: "NTPTimeStamp", TextualConvention: "NTPTimeStamp"},
},
}
for i, c := range cases {
// Indexes always end up initialized.
Expand Down Expand Up @@ -346,6 +351,7 @@ func TestGenerateConfigModule(t *testing.T) {
{Oid: "1.203", Access: "ACCESS_READONLY", Label: "InetAddressIPv4", Type: "OCTETSTR", TextualConvention: "InetAddressIPv4"},
{Oid: "1.204", Access: "ACCESS_READONLY", Label: "InetAddressIPv6", Type: "OCTETSTR", TextualConvention: "InetAddressIPv6"},
{Oid: "1.205", Access: "ACCESS_READONLY", Label: "ParseDateAndTime", Type: "DisplayString", TextualConvention: "ParseDateAndTime"},
{Oid: "1.206", Access: "ACCESS_READONLY", Label: "NTPTimeStamp", Type: "NTPTimeStamp", TextualConvention: "NTPTimeStamp"},
}},
cfg: &ModuleConfig{
Walk: []string{"root", "1.3"},
Expand Down Expand Up @@ -473,6 +479,12 @@ func TestGenerateConfigModule(t *testing.T) {
Type: "ParseDateAndTime",
Help: " - 1.205",
},
{
Name: "NTPTimeStamp",
Oid: "1.206",
Type: "NTPTimeStamp",
Help: " - 1.206",
},
},
},
},
Expand Down

0 comments on commit 0f4ef2f

Please sign in to comment.