Skip to content

Commit

Permalink
Merge pull request google#1488 from tcolgate/master
Browse files Browse the repository at this point in the history
Add udp and udp6 network statistics
  • Loading branch information
dashpole authored Apr 10, 2017
2 parents 850f5ed + 227bb3a commit 359ef5b
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 2 deletions.
9 changes: 7 additions & 2 deletions cadvisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/google/cadvisor/version"

"crypto/tls"

"github.com/golang/glog"
)

Expand Down Expand Up @@ -60,13 +61,17 @@ var collectorKey = flag.String("collector_key", "", "Key for the collector's cer
var (
// Metrics to be ignored.
// Tcp metrics are ignored by default.
ignoreMetrics metricSetValue = metricSetValue{container.MetricSet{container.NetworkTcpUsageMetrics: struct{}{}}}
ignoreMetrics metricSetValue = metricSetValue{container.MetricSet{
container.NetworkTcpUsageMetrics: struct{}{},
container.NetworkUdpUsageMetrics: struct{}{},
}}

// List of metrics that can be ignored.
ignoreWhitelist = container.MetricSet{
container.DiskUsageMetrics: struct{}{},
container.NetworkUsageMetrics: struct{}{},
container.NetworkTcpUsageMetrics: struct{}{},
container.NetworkUdpUsageMetrics: struct{}{},
}
)

Expand Down Expand Up @@ -98,7 +103,7 @@ func (ml *metricSetValue) Set(value string) error {
}

func init() {
flag.Var(&ignoreMetrics, "disable_metrics", "comma-separated list of `metrics` to be disabled. Options are 'disk', 'network', 'tcp'. Note: tcp is disabled by default due to high CPU usage.")
flag.Var(&ignoreMetrics, "disable_metrics", "comma-separated list of `metrics` to be disabled. Options are 'disk', 'network', 'tcp', 'udp'. Note: tcp and udp are disabled by default due to high CPU usage.")
}

func main() {
Expand Down
6 changes: 6 additions & 0 deletions cadvisor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ func TestTcpMetricsAreDisabledByDefault(t *testing.T) {
assert.True(t, ignoreMetrics.Has(container.NetworkTcpUsageMetrics))
}

func TestUdpMetricsAreDisabledByDefault(t *testing.T) {
assert.True(t, ignoreMetrics.Has(container.NetworkUdpUsageMetrics))
flag.Parse()
assert.True(t, ignoreMetrics.Has(container.NetworkUdpUsageMetrics))
}

func TestIgnoreMetrics(t *testing.T) {
tests := []struct {
value string
Expand Down
1 change: 1 addition & 0 deletions container/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (
DiskUsageMetrics MetricKind = "disk"
NetworkUsageMetrics MetricKind = "network"
NetworkTcpUsageMetrics MetricKind = "tcp"
NetworkUdpUsageMetrics MetricKind = "udp"
AppMetrics MetricKind = "app"
)

Expand Down
84 changes: 84 additions & 0 deletions container/libcontainer/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package libcontainer
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
"path"
Expand Down Expand Up @@ -118,6 +119,21 @@ func GetStats(cgroupManager cgroups.Manager, rootFs string, pid int, ignoreMetri
stats.Network.Tcp6 = t6
}
}
if !ignoreMetrics.Has(container.NetworkUdpUsageMetrics) {
u, err := udpStatsFromProc(rootFs, pid, "net/udp")
if err != nil {
glog.V(2).Infof("Unable to get udp stats from pid %d: %v", pid, err)
} else {
stats.Network.Udp = u
}

u6, err := udpStatsFromProc(rootFs, pid, "net/udp6")
if err != nil {
glog.V(2).Infof("Unable to get udp6 stats from pid %d: %v", pid, err)
} else {
stats.Network.Udp6 = u6
}
}

// For backwards compatibility.
if len(stats.Network.Interfaces) > 0 {
Expand Down Expand Up @@ -291,6 +307,74 @@ func scanTcpStats(tcpStatsFile string) (info.TcpStat, error) {
return stats, nil
}

func udpStatsFromProc(rootFs string, pid int, file string) (info.UdpStat, error) {
var err error
var udpStats info.UdpStat

udpStatsFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file)

r, err := os.Open(udpStatsFile)
if err != nil {
return udpStats, fmt.Errorf("failure opening %s: %v", udpStatsFile, err)
}

udpStats, err = scanUdpStats(r)
if err != nil {
return udpStats, fmt.Errorf("couldn't read udp stats: %v", err)
}

return udpStats, nil
}

func scanUdpStats(r io.Reader) (info.UdpStat, error) {
var stats info.UdpStat

scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanLines)

// Discard header line
if b := scanner.Scan(); !b {
return stats, scanner.Err()
}

listening := uint64(0)
dropped := uint64(0)
rxQueued := uint64(0)
txQueued := uint64(0)

for scanner.Scan() {
line := scanner.Text()
// Format: sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops

listening++

fs := strings.Fields(line)
if len(fs) != 13 {
continue
}

rx, tx := uint64(0), uint64(0)
fmt.Sscanf(fs[4], "%X:%X", &rx, &tx)
rxQueued += rx
txQueued += tx

d, err := strconv.Atoi(string(fs[12]))
if err != nil {
continue
}
dropped += uint64(d)
}

stats = info.UdpStat{
Listen: listening,
Dropped: dropped,
RxQueued: rxQueued,
TxQueued: txQueued,
}

return stats, nil
}

func GetProcesses(cgroupManager cgroups.Manager) ([]int, error) {
pids, err := cgroupManager.GetPids()
if err != nil {
Expand Down
25 changes: 25 additions & 0 deletions container/libcontainer/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package libcontainer

import (
"os"
"testing"

info "github.com/google/cadvisor/info/v1"
Expand Down Expand Up @@ -61,3 +62,27 @@ func TestScanInterfaceStats(t *testing.T) {
}
}
}

func TestScanUDPStats(t *testing.T) {
udpStatsFile := "testdata/procnetudp"
r, err := os.Open(udpStatsFile)
if err != nil {
t.Errorf("failure opening %s: %v", udpStatsFile, err)
}

stats, err := scanUdpStats(r)
if err != nil {
t.Error(err)
}

var udpstats = info.UdpStat{
Listen: 2,
Dropped: 4,
RxQueued: 10,
TxQueued: 11,
}

if stats != udpstats {
t.Errorf("Expected %#v, got %#v", udpstats, stats)
}
}
3 changes: 3 additions & 0 deletions container/libcontainer/testdata/procnetudp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops
1: 00000000:07D3 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 16583 2 ffff8800b4549400 0
21: 00000000:A841 00000000:0000 07 0000000A:0000000B 00:00000000 00000000 1000 0 114299623 2 ffff880338477800 4
18 changes: 18 additions & 0 deletions info/v1/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,10 @@ type NetworkStats struct {
Tcp TcpStat `json:"tcp"`
// TCP6 connection stats (Established, Listen...)
Tcp6 TcpStat `json:"tcp6"`
// UDP connection stats
Udp UdpStat `json:"udp"`
// UDP6 connection stats
Udp6 UdpStat `json:"udp6"`
}

type TcpStat struct {
Expand Down Expand Up @@ -413,6 +417,20 @@ type TcpStat struct {
Closing uint64
}

type UdpStat struct {
// Count of UDP sockets in state "Listen"
Listen uint64

// Count of UDP packets dropped by the IP stack
Dropped uint64

// Count of packets Queued for Receieve
RxQueued uint64

// Count of packets Queued for Transmit
TxQueued uint64
}

type FsStats struct {
// The block device name associated with the filesystem.
Device string `json:"device,omitempty"`
Expand Down
4 changes: 4 additions & 0 deletions info/v2/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ type NetworkStats struct {
Tcp TcpStat `json:"tcp"`
// TCP6 connection stats (Established, Listen...)
Tcp6 TcpStat `json:"tcp6"`
// UDP connection stats
Udp v1.UdpStat `json:"udp"`
// UDP6 connection stats
Udp6 v1.UdpStat `json:"udp6"`
}

// Instantaneous CPU stats
Expand Down

0 comments on commit 359ef5b

Please sign in to comment.