From 07e7ed274590b691ab92ad20085e09e40fb9f11f Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Thu, 12 Feb 2026 09:47:42 -0600 Subject: [PATCH] replace fmt.Sprintf with strconv in hot paths Use strconv.FormatInt/FormatUint instead of fmt.Sprintf for integer conversions in snmpValueToString. Use encoding/hex + strings.Builder instead of fmt.Sprintf loop in formatHex. Use strconv.FormatUint for WebSocket ref counter. Reduces allocations per OID significantly. --- agent.go | 4 ++-- snmp.go | 31 ++++++++++++++++--------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/agent.go b/agent.go index 1acc223..a23d82e 100644 --- a/agent.go +++ b/agent.go @@ -8,6 +8,7 @@ import ( "log/slog" "os" "runtime" + "strconv" "strings" "sync" "sync/atomic" @@ -89,8 +90,7 @@ func runSession(ctx context.Context, baseURL, token string) error { refCounter.Store(1) nextRef := func() string { - r := refCounter.Add(1) - return fmt.Sprintf("%d", r) + return strconv.FormatUint(refCounter.Add(1), 10) } sendMsg := func(event string, payload json.RawMessage) { diff --git a/snmp.go b/snmp.go index a8b5b88..dc323ab 100644 --- a/snmp.go +++ b/snmp.go @@ -1,8 +1,11 @@ package main import ( + "encoding/hex" "fmt" "log/slog" + "strconv" + "strings" "time" "unicode/utf8" @@ -254,13 +257,12 @@ func mapPrivProtocol(p string) gosnmp.SnmpV3PrivProtocol { func snmpValueToString(pdu gosnmp.SnmpPDU) string { switch pdu.Type { case gosnmp.Integer: - return fmt.Sprintf("%d", gosnmp.ToBigInt(pdu.Value).Int64()) + return strconv.FormatInt(gosnmp.ToBigInt(pdu.Value).Int64(), 10) case gosnmp.OctetString: b := pdu.Value.([]byte) if !utf8.Valid(b) { return formatHex(b) } - // Check for non-printable control chars for _, c := range b { if c < 0x20 && c != '\n' && c != '\r' && c != '\t' { return formatHex(b) @@ -270,13 +272,13 @@ func snmpValueToString(pdu gosnmp.SnmpPDU) string { case gosnmp.ObjectIdentifier: return pdu.Value.(string) case gosnmp.Counter32: - return fmt.Sprintf("%d", pdu.Value.(uint)) + return strconv.FormatUint(uint64(pdu.Value.(uint)), 10) case gosnmp.Counter64: - return fmt.Sprintf("%d", pdu.Value.(uint64)) + return strconv.FormatUint(pdu.Value.(uint64), 10) case gosnmp.Gauge32: - return fmt.Sprintf("%d", pdu.Value.(uint)) + return strconv.FormatUint(uint64(pdu.Value.(uint)), 10) case gosnmp.TimeTicks: - return fmt.Sprintf("%d", pdu.Value.(uint32)) + return strconv.FormatUint(uint64(pdu.Value.(uint32)), 10) case gosnmp.IPAddress: return pdu.Value.(string) case gosnmp.Null, gosnmp.NoSuchObject, gosnmp.NoSuchInstance, gosnmp.EndOfMibView: @@ -292,16 +294,15 @@ func formatHex(b []byte) string { if len(b) == 0 { return "" } - parts := make([]string, len(b)) - for i, v := range b { - parts[i] = fmt.Sprintf("%02x", v) - } - result := "" - for i, p := range parts { + h := hex.EncodeToString(b) + var buf strings.Builder + buf.Grow(len(h) + len(b) - 1) + for i := 0; i < len(h); i += 2 { if i > 0 { - result += ":" + buf.WriteByte(':') } - result += p + buf.WriteByte(h[i]) + buf.WriteByte(h[i+1]) } - return result + return buf.String() }