From a62dbf48b0fe5e2e28e3cc9dc80a70d2ec5ebc25 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 25 Apr 2016 16:15:48 -0700 Subject: [PATCH] Improve stats output This adds specific types and improves the json format for the marshaled structure so that it is inline with the output that the spec produce, camelCase not snake_case. This should be the last change needed for people to really depend on the output of this command and ensure that it does not change with any internal changes instead of just marshaling the libcontainer structure. Signed-off-by: Michael Crosby --- events.go | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 147 insertions(+), 3 deletions(-) diff --git a/events.go b/events.go index cc12eaef6..05c7cb712 100644 --- a/events.go +++ b/events.go @@ -11,6 +11,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" "github.com/opencontainers/runc/libcontainer" + "github.com/opencontainers/runc/libcontainer/cgroups" ) // event struct for encoding the event data to json. @@ -20,9 +21,82 @@ type event struct { Data interface{} `json:"data,omitempty"` } +// stats is the runc specific stats structure for stability when encoding and decoding stats. +type stats struct { + Cpu cpu `json:"cpu"` + Memory memory `json:"memory"` + Pids pids `json:"pids"` + Blkio blkio `json:"blkio"` + Hugetlb map[string]hugetlb `json:"hugetlb"` +} + +type hugetlb struct { + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type blkioEntry struct { + Major uint64 `json:"major,omitempty"` + Minor uint64 `json:"minor,omitempty"` + Op string `json:"op,omitempty"` + Value uint64 `json:"value,omitempty"` +} + +type blkio struct { + IoServiceBytesRecursive []blkioEntry `json:"ioServiceBytesRecursive,omitempty"` + IoServicedRecursive []blkioEntry `json:"ioServicedRecursive,omitempty"` + IoQueuedRecursive []blkioEntry `json:"ioQueueRecursive,omitempty"` + IoServiceTimeRecursive []blkioEntry `json:"ioServiceTimeRecursive,omitempty"` + IoWaitTimeRecursive []blkioEntry `json:"ioWaitTimeRecursive,omitempty"` + IoMergedRecursive []blkioEntry `json:"ioMergedRecursive,omitempty"` + IoTimeRecursive []blkioEntry `json:"ioTimeRecursive,omitempty"` + SectorsRecursive []blkioEntry `json:"sectorsRecursive,omitempty"` +} + +type pids struct { + Current uint64 `json:"current,omitempty"` + Limit uint64 `json:"limit,omitempty"` +} + +type throttling struct { + Periods uint64 `json:"periods,omitempty"` + ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"` + ThrottledTime uint64 `json:"throttledTime,omitempty"` +} + +type cpuUsage struct { + // Units: nanoseconds. + Total uint64 `json:"total,omitempty"` + Percpu []uint64 `json:"percpu,omitempty"` + Kernel uint64 `json:"kernel"` + User uint64 `json:"user"` +} + +type cpu struct { + Usage cpuUsage `json:"usage,omitempty"` + Throttling throttling `json:"throttling,omitempty"` +} + +type memoryEntry struct { + Limit uint64 `json:"limit"` + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type memory struct { + Cache uint64 `json:"cache,omitempty"` + Usage memoryEntry `json:"usage,omitempty"` + Swap memoryEntry `json:"swap,omitempty"` + Kernel memoryEntry `json:"kernel,omitempty"` + KernelTCP memoryEntry `json:"kernelTCP,omitempty"` + Raw map[string]uint64 `json:"raw,omitempty"` +} + var eventsCommand = cli.Command{ Name: "events", - Usage: "display container events such as OOM notifications, cpu, memory, IO and network stats", + Usage: "display container events such as OOM notifications, cpu, memory, and IO usage statistics", ArgsUsage: ` Where "" is the name for the instance of the container.`, @@ -64,7 +138,7 @@ information is displayed once every 5 seconds.`, if err != nil { fatal(err) } - events <- &event{Type: "stats", ID: container.ID(), Data: s} + events <- &event{Type: "stats", ID: container.ID(), Data: convertLibcontainerStats(s)} close(events) group.Wait() return @@ -95,7 +169,7 @@ information is displayed once every 5 seconds.`, n = nil } case s := <-stats: - events <- &event{Type: "stats", ID: container.ID(), Data: s} + events <- &event{Type: "stats", ID: container.ID(), Data: convertLibcontainerStats(s)} } if n == nil { close(events) @@ -105,3 +179,73 @@ information is displayed once every 5 seconds.`, group.Wait() }, } + +func convertLibcontainerStats(ls *libcontainer.Stats) *stats { + cg := ls.CgroupStats + if cg == nil { + return nil + } + var s stats + s.Pids.Current = cg.PidsStats.Current + s.Pids.Limit = cg.PidsStats.Limit + + s.Cpu.Usage.Kernel = cg.CpuStats.CpuUsage.UsageInKernelmode + s.Cpu.Usage.User = cg.CpuStats.CpuUsage.UsageInUsermode + s.Cpu.Usage.Total = cg.CpuStats.CpuUsage.TotalUsage + s.Cpu.Usage.Percpu = cg.CpuStats.CpuUsage.PercpuUsage + s.Cpu.Throttling.Periods = cg.CpuStats.ThrottlingData.Periods + s.Cpu.Throttling.ThrottledPeriods = cg.CpuStats.ThrottlingData.ThrottledPeriods + s.Cpu.Throttling.ThrottledTime = cg.CpuStats.ThrottlingData.ThrottledTime + + s.Memory.Cache = cg.MemoryStats.Cache + s.Memory.Kernel = convertMemoryEntry(cg.MemoryStats.KernelUsage) + s.Memory.KernelTCP = convertMemoryEntry(cg.MemoryStats.KernelTCPUsage) + s.Memory.Swap = convertMemoryEntry(cg.MemoryStats.SwapUsage) + s.Memory.Usage = convertMemoryEntry(cg.MemoryStats.Usage) + s.Memory.Raw = cg.MemoryStats.Stats + + s.Blkio.IoServiceBytesRecursive = convertBlkioEntry(cg.BlkioStats.IoServiceBytesRecursive) + s.Blkio.IoServicedRecursive = convertBlkioEntry(cg.BlkioStats.IoServicedRecursive) + s.Blkio.IoQueuedRecursive = convertBlkioEntry(cg.BlkioStats.IoQueuedRecursive) + s.Blkio.IoServiceTimeRecursive = convertBlkioEntry(cg.BlkioStats.IoServiceTimeRecursive) + s.Blkio.IoWaitTimeRecursive = convertBlkioEntry(cg.BlkioStats.IoWaitTimeRecursive) + s.Blkio.IoMergedRecursive = convertBlkioEntry(cg.BlkioStats.IoMergedRecursive) + s.Blkio.IoTimeRecursive = convertBlkioEntry(cg.BlkioStats.IoTimeRecursive) + s.Blkio.SectorsRecursive = convertBlkioEntry(cg.BlkioStats.SectorsRecursive) + + s.Hugetlb = make(map[string]hugetlb) + for k, v := range cg.HugetlbStats { + s.Hugetlb[k] = convertHugtlb(v) + } + return &s +} + +func convertHugtlb(c cgroups.HugetlbStats) hugetlb { + return hugetlb{ + Usage: c.Usage, + Max: c.MaxUsage, + Failcnt: c.Failcnt, + } +} + +func convertMemoryEntry(c cgroups.MemoryData) memoryEntry { + return memoryEntry{ + Limit: c.Limit, + Usage: c.Usage, + Max: c.MaxUsage, + Failcnt: c.Failcnt, + } +} + +func convertBlkioEntry(c []cgroups.BlkioStatEntry) []blkioEntry { + var out []blkioEntry + for _, e := range c { + out = append(out, blkioEntry{ + Major: e.Major, + Minor: e.Minor, + Op: e.Op, + Value: e.Value, + }) + } + return out +}