mirror of
https://github.com/shirou/gopsutil.git
synced 2025-05-10 19:29:14 +08:00
Merge pull request #109 from influxdb/nc-net-snmp
Add system wide network protocol stats
This commit is contained in:
commit
4e774eabc2
@ -119,6 +119,11 @@ Several methods have been added which are not present in psutil, but will provid
|
||||
|
||||
- various status
|
||||
|
||||
- net_protocols (linux only)
|
||||
|
||||
- system wide stats on network protocols (i.e IP, TCP, UDP, etc.)
|
||||
- sourced from /proc/net/snmp
|
||||
|
||||
Some codes are ported from Ohai. many thanks.
|
||||
|
||||
|
||||
@ -145,6 +150,7 @@ users x x x x
|
||||
pids x x x x
|
||||
pid_exists x x x x
|
||||
net_connections x x
|
||||
net_protocols x
|
||||
net_if_addrs
|
||||
net_if_stats
|
||||
================= ====== ======= ====== =======
|
||||
|
11
net/net.go
11
net/net.go
@ -45,6 +45,12 @@ type NetConnectionStat struct {
|
||||
Pid int32 `json:"pid"`
|
||||
}
|
||||
|
||||
// System wide stats about different network protocols
|
||||
type NetProtoCountersStat struct {
|
||||
Protocol string `json:"protocol"`
|
||||
Stats map[string]int64 `json:"stats"`
|
||||
}
|
||||
|
||||
// NetInterfaceAddr is designed for represent interface addresses
|
||||
type NetInterfaceAddr struct {
|
||||
Addr string `json:"addr"`
|
||||
@ -75,6 +81,11 @@ func (n NetConnectionStat) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func (n NetProtoCountersStat) String() string {
|
||||
s, _ := json.Marshal(n)
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func (a Addr) String() string {
|
||||
s, _ := json.Marshal(a)
|
||||
return string(s)
|
||||
|
@ -3,6 +3,7 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -90,3 +91,11 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// NetProtoCounters returns network statistics for the entire system
|
||||
// If protocols is empty then all protocols are returned, otherwise
|
||||
// just the protocols in the list are returned.
|
||||
// Not Implemented for Darwin
|
||||
func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
|
||||
return nil, errors.New("NetProtoCounters not implemented for darwin")
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -81,3 +82,11 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// NetProtoCounters returns network statistics for the entire system
|
||||
// If protocols is empty then all protocols are returned, otherwise
|
||||
// just the protocols in the list are returned.
|
||||
// Not Implemented for FreeBSD
|
||||
func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
|
||||
return nil, errors.New("NetProtoCounters not implemented for freebsd")
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@ -89,3 +90,73 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
var netProtocols = []string{
|
||||
"ip",
|
||||
"icmp",
|
||||
"icmpmsg",
|
||||
"tcp",
|
||||
"udp",
|
||||
"udplite",
|
||||
}
|
||||
|
||||
// NetProtoCounters returns network statistics for the entire system
|
||||
// If protocols is empty then all protocols are returned, otherwise
|
||||
// just the protocols in the list are returned.
|
||||
// Available protocols:
|
||||
// ip,icmp,icmpmsg,tcp,udp,udplite
|
||||
func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
|
||||
if len(protocols) == 0 {
|
||||
protocols = netProtocols
|
||||
}
|
||||
|
||||
stats := make([]NetProtoCountersStat, 0, len(protocols))
|
||||
protos := make(map[string]bool, len(protocols))
|
||||
for _, p := range protocols {
|
||||
protos[p] = true
|
||||
}
|
||||
|
||||
filename := "/proc/net/snmp"
|
||||
lines, err := common.ReadLines(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
linecount := len(lines)
|
||||
for i := 0; i < linecount; i++ {
|
||||
line := lines[i]
|
||||
r := strings.IndexRune(line, ':')
|
||||
if r == -1 {
|
||||
return nil, errors.New(filename + " is not fomatted correctly, expected ':'.")
|
||||
}
|
||||
proto := strings.ToLower(line[:r])
|
||||
if !protos[proto] {
|
||||
// skip protocol and data line
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// Read header line
|
||||
statNames := strings.Split(line[r+2:], " ")
|
||||
|
||||
// Read data line
|
||||
i++
|
||||
statValues := strings.Split(lines[i][r+2:], " ")
|
||||
if len(statNames) != len(statValues) {
|
||||
return nil, errors.New(filename + " is not fomatted correctly, expected same number of columns.")
|
||||
}
|
||||
stat := NetProtoCountersStat{
|
||||
Protocol: proto,
|
||||
Stats: make(map[string]int64, len(statNames)),
|
||||
}
|
||||
for j := range statNames {
|
||||
value, err := strconv.ParseInt(statValues[j], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stat.Stats[statNames[j]] = value
|
||||
}
|
||||
stats = append(stats, stat)
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
@ -26,6 +26,22 @@ func TestNetIOCountersStatString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetProtoCountersStatString(t *testing.T) {
|
||||
v := NetProtoCountersStat{
|
||||
Protocol: "tcp",
|
||||
Stats: map[string]int64{
|
||||
"MaxConn": -1,
|
||||
"ActiveOpens": 4000,
|
||||
"PassiveOpens": 3000,
|
||||
},
|
||||
}
|
||||
e := `{"protocol":"tcp","stats":{"ActiveOpens":4000,"MaxConn":-1,"PassiveOpens":3000}}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("NetProtoCountersStat string is invalid: %v", v)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNetConnectionStatString(t *testing.T) {
|
||||
v := NetConnectionStat{
|
||||
Fd: 10,
|
||||
@ -122,6 +138,45 @@ func TestNetInterfaces(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetProtoCountersStatsAll(t *testing.T) {
|
||||
v, err := NetProtoCounters(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get NetProtoCounters: %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Fatalf("Could not get NetProtoCounters: %v", err)
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.Protocol == "" {
|
||||
t.Errorf("Invalid NetProtoCountersStat: %v", vv)
|
||||
}
|
||||
if len(vv.Stats) == 0 {
|
||||
t.Errorf("Invalid NetProtoCountersStat: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetProtoCountersStats(t *testing.T) {
|
||||
v, err := NetProtoCounters([]string{"tcp", "ip"})
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get NetProtoCounters: %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Fatalf("Could not get NetProtoCounters: %v", err)
|
||||
}
|
||||
if len(v) != 2 {
|
||||
t.Fatalf("Go incorrect number of NetProtoCounters: %v", err)
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.Protocol != "tcp" && vv.Protocol != "ip" {
|
||||
t.Errorf("Invalid NetProtoCountersStat: %v", vv)
|
||||
}
|
||||
if len(vv.Stats) == 0 {
|
||||
t.Errorf("Invalid NetProtoCountersStat: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetConnections(t *testing.T) {
|
||||
if ci := os.Getenv("CI"); ci != "" { // skip if test on drone.io
|
||||
return
|
||||
|
@ -3,6 +3,7 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
@ -96,3 +97,11 @@ func getAdapterList() (*syscall.IpAdapterInfo, error) {
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// NetProtoCounters returns network statistics for the entire system
|
||||
// If protocols is empty then all protocols are returned, otherwise
|
||||
// just the protocols in the list are returned.
|
||||
// Not Implemented for Windows
|
||||
func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
|
||||
return nil, errors.New("NetProtoCounters not implemented for windows")
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user