Repository: prometheus/procfs
Pull request #590 (2023-11-18 17:48:39)

Synchronize common files from prometheus/prometheus
Propagating changes from prometheus/prometheus default branch.


Patch:
diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index babd8a0..ffa6b30 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -22,7 +22,7 @@ jobs:
       - name: install Go
         uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
         with:
-          go-version: 1.20.x
+          go-version: 1.21.x
       - name: Install snmp_exporter/generator dependencies
         run: sudo apt-get update && sudo apt-get -y install libsnmp-dev
         if: github.repository == 'prometheus/snmp_exporter'
diff --git a/crypto.go b/crypto.go
index 9a73e26..13ee66f 100644
--- a/crypto.go
+++ b/crypto.go
@@ -84,7 +84,7 @@ func parseCrypto(r io.Reader) ([]Crypto, error) {
 
 		kv := strings.Split(text, ":")
 		if len(kv) != 2 {
-			return nil, fmt.Errorf("%w: Cannot parae line: %q", ErrFileParse, text)
+			return nil, fmt.Errorf("%w: Cannot parse line: %q", ErrFileParse, text)
 		}
 
 		k := strings.TrimSpace(kv[0])
diff --git a/net_ip_socket.go b/net_ip_socket.go
index 4da81ea..ba7d9ca 100644
--- a/net_ip_socket.go
+++ b/net_ip_socket.go
@@ -50,10 +50,13 @@ type (
 		// UsedSockets shows the total number of parsed lines representing the
 		// number of used sockets.
 		UsedSockets uint64
+		// Drops shows the total number of dropped packets of all UPD sockets.
+		Drops *uint64
 	}
 
 	// netIPSocketLine represents the fields parsed from a single line
 	// in /proc/net/{t,u}dp{,6}. Fields which are not used by IPSocket are skipped.
+	// Drops is non-nil for udp{,6}, but nil for tcp{,6}.
 	// For the proc file format details, see https://linux.die.net/man/5/proc.
 	netIPSocketLine struct {
 		Sl        uint64
@@ -66,6 +69,7 @@ type (
 		RxQueue   uint64
 		UID       uint64
 		Inode     uint64
+		Drops     *uint64
 	}
 )
 
@@ -77,13 +81,14 @@ func newNetIPSocket(file string) (NetIPSocket, error) {
 	defer f.Close()
 
 	var netIPSocket NetIPSocket
+	isUDP := strings.Contains(file, "udp")
 
 	lr := io.LimitReader(f, readLimit)
 	s := bufio.NewScanner(lr)
 	s.Scan() // skip first line with headers
 	for s.Scan() {
 		fields := strings.Fields(s.Text())
-		line, err := parseNetIPSocketLine(fields)
+		line, err := parseNetIPSocketLine(fields, isUDP)
 		if err != nil {
 			return nil, err
 		}
@@ -104,19 +109,25 @@ func newNetIPSocketSummary(file string) (*NetIPSocketSummary, error) {
 	defer f.Close()
 
 	var netIPSocketSummary NetIPSocketSummary
+	var udpPacketDrops uint64
+	isUDP := strings.Contains(file, "udp")
 
 	lr := io.LimitReader(f, readLimit)
 	s := bufio.NewScanner(lr)
 	s.Scan() // skip first line with headers
 	for s.Scan() {
 		fields := strings.Fields(s.Text())
-		line, err := parseNetIPSocketLine(fields)
+		line, err := parseNetIPSocketLine(fields, isUDP)
 		if err != nil {
 			return nil, err
 		}
 		netIPSocketSummary.TxQueueLength += line.TxQueue
 		netIPSocketSummary.RxQueueLength += line.RxQueue
 		netIPSocketSummary.UsedSockets++
+		if isUDP {
+			udpPacketDrops += *line.Drops
+			netIPSocketSummary.Drops = &udpPacketDrops
+		}
 	}
 	if err := s.Err(); err != nil {
 		return nil, err
@@ -149,7 +160,7 @@ func parseIP(hexIP string) (net.IP, error) {
 }
 
 // parseNetIPSocketLine parses a single line, represented by a list of fields.
-func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
+func parseNetIPSocketLine(fields []string, isUDP bool) (*netIPSocketLine, error) {
 	line := &netIPSocketLine{}
 	if len(fields) < 10 {
 		return nil, fmt.Errorf(
@@ -224,5 +235,14 @@ func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
 		return nil, fmt.Errorf("%s: Cannot parse inode value in %q: %w", ErrFileParse, line.Inode, err)
 	}
 
+	// drops
+	if isUDP {
+		drops, err := strconv.ParseUint(fields[12], 0, 64)
+		if err != nil {
+			return nil, fmt.Errorf("%s: Cannot parse drops value in %q: %w", ErrFileParse, drops, err)
+		}
+		line.Drops = &drops
+	}
+
 	return line, nil
 }


Test patch:
diff --git a/net_ip_socket_test.go b/net_ip_socket_test.go
index 9bbad87..3c057fb 100644
--- a/net_ip_socket_test.go
+++ b/net_ip_socket_test.go
@@ -25,6 +25,7 @@ func Test_parseNetIPSocketLine(t *testing.T) {
 		name    string
 		want    *netIPSocketLine
 		wantErr bool
+		isUDP   bool
 	}{
 		{
 			name:   "reading valid lines, no issue should happened",
@@ -96,10 +97,17 @@ func Test_parseNetIPSocketLine(t *testing.T) {
 			want:    nil,
 			wantErr: true,
 		},
+		{
+			name:    "error case - parse Drops - not a valid uint",
+			fields:  []string{"1:", "00000000:0000", "00000000:0000", "07", "00000000:00000001", "0:0", "0", "10", "0", "39309", "2", "000000009bd60d72", "-5"},
+			want:    nil,
+			wantErr: true,
+			isUDP:   true,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got, err := parseNetIPSocketLine(tt.fields)
+			got, err := parseNetIPSocketLine(tt.fields, tt.isUDP)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("parseNetIPSocketLine() error = %v, wantErr %v", err, tt.wantErr)
 				return
diff --git a/net_udp_test.go b/net_udp_test.go
index 9abb64d..6576161 100644
--- a/net_udp_test.go
+++ b/net_udp_test.go
@@ -41,6 +41,7 @@ func Test_newNetUDP(t *testing.T) {
 					RxQueue:   1,
 					UID:       0,
 					Inode:     2740,
+					Drops:     intToU64(100),
 				},
 				&netIPSocketLine{
 					Sl:        1,
@@ -53,6 +54,7 @@ func Test_newNetUDP(t *testing.T) {
 					RxQueue:   0,
 					UID:       0,
 					Inode:     2740,
+					Drops:     intToU64(100),
 				},
 				&netIPSocketLine{
 					Sl:        2,
@@ -65,6 +67,7 @@ func Test_newNetUDP(t *testing.T) {
 					RxQueue:   1,
 					UID:       0,
 					Inode:     2740,
+					Drops:     intToU64(100),
 				},
 			},
 			wantErr: false,
@@ -84,6 +87,7 @@ func Test_newNetUDP(t *testing.T) {
 					RxQueue:   0,
 					UID:       981,
 					Inode:     21040,
+					Drops:     intToU64(0),
 				},
 				&netIPSocketLine{
 					Sl:        6073,
@@ -96,6 +100,7 @@ func Test_newNetUDP(t *testing.T) {
 					RxQueue:   0,
 					UID:       1000,
 					Inode:     11337031,
+					Drops:     intToU64(0),
 				},
 			},
 			wantErr: false,
@@ -137,13 +142,13 @@ func Test_newNetUDPSummary(t *testing.T) {
 		{
 			name:    "udp file found, no error should come up",
 			file:    "testdata/fixtures/proc/net/udp",
-			want:    &NetUDPSummary{TxQueueLength: 2, RxQueueLength: 2, UsedSockets: 3},
+			want:    &NetUDPSummary{TxQueueLength: 2, RxQueueLength: 2, UsedSockets: 3, Drops: intToU64(300)},
 			wantErr: false,
 		},
 		{
 			name:    "udp6 file found, no error should come up",
 			file:    "testdata/fixtures/proc/net/udp6",
-			want:    &NetUDPSummary{TxQueueLength: 0, RxQueueLength: 0, UsedSockets: 2},
+			want:    &NetUDPSummary{TxQueueLength: 0, RxQueueLength: 0, UsedSockets: 2, Drops: intToU64(0)},
 			wantErr: false,
 		},
 		{
@@ -172,3 +177,9 @@ func Test_newNetUDPSummary(t *testing.T) {
 		})
 	}
 }
+
+// intToU64 convert int to uint64 and return it pointer.
+func intToU64(i int) *uint64 {
+	cast := uint64(i)
+	return &cast
+}