Repository: prometheus/snmp_exporter
Pull request #908 (2023-07-05 04:38:49)

Improved Lookup process for label information to utilize TypeMapping
We've made improvements to the Metric Lookup process. 
Previously, the byte representation of labels was output as-is under certain circumstances. With this update, it now references the processing of TypeMapping for output.

generator.yml
```
modules:
  default:
    walk:
    - lldpRemPortIdSubtype
    - lldpLocPortIdSubtype
    - lldpRemPortId
    - lldpLocPortId
    - lldpRemSysName
    lookups:
    - source_indexes:
      - lldpRemTimeMark
      - lldpRemLocalPortNum
      - lldpRemIndex
      lookup: "lldpRemPortId"
    - source_indexes: ['lldpRemLocalPortNum']
      lookup: "lldpLocPortId"
    overrides:
      lldpRemPortIdSubtype:
        ignore: true
      lldpLocPortIdSubtype:
        ignore: true
```

before
```
lldpLocPortId{lldpLocPortId="Management1",lldpLocPortNum="245"} 1
# HELP lldpRemPortId The string value used to identify the port component associated with the remote system. - 1.0.8802.1.1.2.1.4.1.1.7
# TYPE lldpRemPortId gauge
lldpRemPortId{lldpLocPortId="0x4D616E6167656D656E743100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",lldpRemIndex="2",lldpRemLocalPortNum="245",lldpRemPortId="0x4769312F31340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",lldpRemTimeMark="0"} 1
# HELP lldpRemSysName The string value used to identify the system name of the remote system. - 1.0.8802.1.1.2.1.4.1.1.9
# TYPE lldpRemSysName gauge
lldpRemSysName{lldpLocPortId="0x4D616E6167656D656E743100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",lldpRemIndex="14",lldpRemLocalPortNum="245",lldpRemPortId="0x4769312F31340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",lldpRemSysName="hostname",lldpRemTimeMark="0"} 1
```

after
```
lldpLocPortId{lldpLocPortId="Management1",lldpLocPortNum="245"} 1
# HELP lldpRemPortId The string value used to identify the port component associated with the remote system. - 1.0.8802.1.1.2.1.4.1.1.7
# TYPE lldpRemPortId gauge
lldpRemPortId{lldpLocPortId="Management1",lldpRemIndex="2",lldpRemLocalPortNum="245",lldpRemPortId="Gi1/14",lldpRemTimeMark="0"} 1
# HELP lldpRemSysName The string value used to identify the system name of the remote system. - 1.0.8802.1.1.2.1.4.1.1.9
# TYPE lldpRemSysName gauge
lldpRemSysName{lldpLocPortId="Management1",lldpRemIndex="2",lldpRemLocalPortNum="245",lldpRemPortId="Gi1/14",lldpRemSysName="hostname",lldpRemTimeMark="0"} 1
```

servak: Sorry for the delay after the review, I added a test and rebased it again.

Patch:
diff --git a/collector/collector.go b/collector/collector.go
index f31e146..1879bf3 100644
--- a/collector/collector.go
+++ b/collector/collector.go
@@ -566,10 +566,7 @@ func pduToSamples(indexOids []int, pdu *gosnmp.SnmpPDU, metric *config.Metric, o
 
 		if typeMapping, ok := combinedTypeMapping[metricType]; ok {
 			// Lookup associated sub type in previous object.
-			oids := strings.Split(metric.Oid, ".")
-			i, _ := strconv.Atoi(oids[len(oids)-1])
-			oids[len(oids)-1] = strconv.Itoa(i - 1)
-			prevOid := fmt.Sprintf("%s.%s", strings.Join(oids, "."), listToOid(indexOids))
+			prevOid := fmt.Sprintf("%s.%s", getPrevOid(metric.Oid), listToOid(indexOids))
 			if prevPdu, ok := oidToPdu[prevOid]; ok {
 				val := int(getPduValue(&prevPdu))
 				if t, ok := typeMapping[val]; ok {
@@ -872,6 +869,13 @@ func indexOidsAsString(indexOids []int, typ string, fixedSize int, implied bool,
 	}
 }
 
+func getPrevOid(oid string) string {
+	oids := strings.Split(oid, ".")
+	i, _ := strconv.Atoi(oids[len(oids)-1])
+	oids[len(oids)-1] = strconv.Itoa(i - 1)
+	return strings.Join(oids, ".")
+}
+
 func indexesToLabels(indexOids []int, metric *config.Metric, oidToPdu map[string]gosnmp.SnmpPDU, metrics internalMetrics) map[string]string {
 	labels := map[string]string{}
 	labelOids := map[string][]int{}
@@ -898,7 +902,21 @@ func indexesToLabels(indexOids []int, metric *config.Metric, oidToPdu map[string
 			oid = fmt.Sprintf("%s.%s", oid, listToOid(labelOids[label]))
 		}
 		if pdu, ok := oidToPdu[oid]; ok {
-			labels[lookup.Labelname] = pduValueAsString(&pdu, lookup.Type, metrics)
+			t := lookup.Type
+			if typeMapping, ok := combinedTypeMapping[lookup.Type]; ok {
+				// Lookup associated sub type in previous object.
+				prevOid := getPrevOid(lookup.Oid)
+				for _, label := range lookup.Labels {
+					prevOid = fmt.Sprintf("%s.%s", prevOid, listToOid(labelOids[label]))
+				}
+				if prevPdu, ok := oidToPdu[prevOid]; ok {
+					val := int(getPduValue(&prevPdu))
+					if ty, ok := typeMapping[val]; ok {
+						t = ty
+					}
+				}
+			}
+			labels[lookup.Labelname] = pduValueAsString(&pdu, t, metrics)
 			labelOids[lookup.Labelname] = []int{int(gosnmp.ToBigInt(pdu.Value).Int64())}
 		} else {
 			labels[lookup.Labelname] = ""


Test patch:
diff --git a/collector/collector_test.go b/collector/collector_test.go
index 7a5fae2..51382bd 100644
--- a/collector/collector_test.go
+++ b/collector/collector_test.go
@@ -1006,6 +1006,25 @@ func TestIndexesToLabels(t *testing.T) {
 			},
 			result: map[string]string{"a": "1", "chainable_id": "42", "targetlabel": "targetvalue"},
 		},
+		{
+			oid: []int{1, 8, 1},
+			metric: config.Metric{
+				Indexes: []*config.Index{
+					{Labelname: "lldpRemTimeMark", Type: "gauge"},
+					{Labelname: "lldpRemLocalPortNum", Type: "gauge"},
+					{Labelname: "lldpRemIndex", Type: "gauge"},
+				},
+				Lookups: []*config.Lookup{
+					{Labels: []string{"lldpRemLocalPortNum"}, Labelname: "lldpLocPortId", Oid: "1.1.3", Type: "LldpPortId"},
+				},
+			},
+			oidToPdu: map[string]gosnmp.SnmpPDU{
+				"1.1.9.1.8.1": gosnmp.SnmpPDU{Value: "hostname"},
+				"1.1.2.8":     gosnmp.SnmpPDU{Value: 3},
+				"1.1.3.8":     gosnmp.SnmpPDU{Value: []byte{4, 5, 6, 7, 8, 9}},
+			},
+			result: map[string]string{"lldpRemTimeMark": "1", "lldpRemLocalPortNum": "8", "lldpRemIndex": "1", "lldpLocPortId": "04:05:06:07:08:09"},
+		},
 	}
 	for _, c := range cases {
 		got := indexesToLabels(c.oid, &c.metric, c.oidToPdu, internalMetrics{})