forked from prometheus/procfs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add /proc/net/udp parsing especially for the tx_queue and rx_queue le…
…ngths. @pgier this belongs to the requested of @discordianfish in prometheus/node_exporter#1503. Signed-off-by: Peter Bueschel <[email protected]>
- Loading branch information
Showing
3 changed files
with
239 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2018 The Prometheus Authors | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package procfs | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"os" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type ( | ||
// NetUDPLine is a line parsed from /proc/net/udp | ||
// For the proc file format details, see https://linux.die.net/man/5/proc | ||
NetUDPLine struct { | ||
TxQueue uint64 | ||
RxQueue uint64 | ||
} | ||
|
||
NetUDP struct { | ||
TxQueueLength uint64 | ||
RxQueueLength uint64 | ||
UsedSockets uint64 | ||
} | ||
) | ||
|
||
// NetUDP returns kernel/networking statistics for udp datagrams read from /proc/net/udp. | ||
func (fs FS) NetUDP() (*NetUDP, error) { | ||
return newNetUDP(fs.proc.Path("net/udp")) | ||
} | ||
|
||
// newNetUDP creates a new NetUDP from the contents of the given file. | ||
func newNetUDP(file string) (*NetUDP, error) { | ||
f, err := os.Open(file) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
|
||
netUDP := &NetUDP{} | ||
s := bufio.NewScanner(f) | ||
s.Scan() // skip first line with headers | ||
for s.Scan() { | ||
fields := strings.Fields(s.Text()) | ||
line, err := parseNetUDPLine(fields) | ||
if err != nil { | ||
return nil, err | ||
} | ||
netUDP.TxQueueLength += line.TxQueue | ||
netUDP.RxQueueLength += line.RxQueue | ||
netUDP.UsedSockets++ | ||
} | ||
if err := s.Err(); err != nil { | ||
return nil, err | ||
} | ||
return netUDP, nil | ||
} | ||
|
||
func parseNetUDPLine(fields []string) (*NetUDPLine, error) { | ||
line := &NetUDPLine{} | ||
if len(fields) < 5 { | ||
return nil, fmt.Errorf( | ||
"cannot parse net udp socket line as it has less then 5 columns: %s", | ||
strings.Join(fields, " "), | ||
) | ||
} | ||
q := strings.Split(fields[4], ":") | ||
if len(q) < 2 { | ||
return nil, fmt.Errorf( | ||
"cannot parse tx/rx queues in udp socket line as it has a missing colon: %s", | ||
fields[4], | ||
) | ||
} | ||
var err error // parse error | ||
if line.TxQueue, err = strconv.ParseUint(q[0], 16, 64); err != nil { | ||
return nil, fmt.Errorf("cannot parse tx_queue value in udp socket line: %s", err) | ||
} | ||
if line.RxQueue, err = strconv.ParseUint(q[1], 16, 64); err != nil { | ||
return nil, fmt.Errorf("cannot parse rx_queue value in udp socket line: %s", err) | ||
} | ||
return line, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// Copyright 2018 The Prometheus Authors | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package procfs | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func Test_parseNetUDPLine(t *testing.T) { | ||
type args struct { | ||
fields []string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want *NetUDPLine | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "reading valid lines, no issue should happened", | ||
args: args{ | ||
fields: []string{"1:", "00000000:0000", "00000000:0000", "07", "00000017:0000002A"}, | ||
}, | ||
want: &NetUDPLine{TxQueue: 23, RxQueue: 42}, | ||
}, | ||
{ | ||
name: "error case - invalid line - number of fields/columns < 5", | ||
args: args{ | ||
fields: []string{"1:", "00000000:0000", "00000000:0000", "07"}, | ||
}, | ||
want: nil, | ||
wantErr: true, | ||
}, | ||
{ | ||
name: "error case - cannot parse line - missing colon", | ||
args: args{ | ||
fields: []string{"1:", "00000000:0000", "00000000:0000", "07", "0000000000000001"}, | ||
}, | ||
want: nil, | ||
wantErr: true, | ||
}, | ||
{ | ||
name: "error case - parse tx_queue - not an valid hex", | ||
args: args{ | ||
fields: []string{"1:", "00000000:0000", "00000000:0000", "07", "DEADCODE:00000001"}, | ||
}, | ||
want: nil, | ||
wantErr: true, | ||
}, | ||
{ | ||
name: "error case - parse rx_queue - not an valid hex", | ||
args: args{ | ||
fields: []string{"1:", "00000000:0000", "00000000:0000", "07", "00000000:FEEDCODE"}, | ||
}, | ||
want: nil, | ||
wantErr: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := parseNetUDPLine(tt.args.fields) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("parseNetUDPLine() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if tt.want == nil && got != nil { | ||
t.Errorf("parseNetUDPLine() = %v, want %v", got, tt.want) | ||
} | ||
if got != nil { | ||
if (got.RxQueue != tt.want.RxQueue) || (got.TxQueue != tt.want.TxQueue) { | ||
t.Errorf("parseNetUDPLine() = %#v, want %#v", got, tt.want) | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func Test_newNetUDP(t *testing.T) { | ||
type args struct { | ||
file string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want *NetUDP | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "file found, no error should come up", | ||
args: args{file: "fixtures/proc/net/udp"}, | ||
want: &NetUDP{TxQueueLength: 2, RxQueueLength: 2, UsedSockets: 3}, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "error case - file not found", | ||
args: args{file: "somewhere over the rainbow"}, | ||
want: nil, | ||
wantErr: true, | ||
}, | ||
{ | ||
name: "error case - parse error", | ||
args: args{file: "fixtures/proc/net/udp_broken"}, | ||
want: nil, | ||
wantErr: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := newNetUDP(tt.args.file) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("newNetUDP() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("newNetUDP() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |