daemon/stats.go
4f174aa7
 package daemon
 
 import (
 	"encoding/json"
 
7fed7d7e
 	"github.com/docker/docker/api/types"
2f46b760
 	"github.com/docker/docker/daemon/execdriver"
4f174aa7
 	"github.com/docker/docker/engine"
2f46b760
 	"github.com/docker/libcontainer"
 	"github.com/docker/libcontainer/cgroups"
4f174aa7
 )
 
 func (daemon *Daemon) ContainerStats(job *engine.Job) engine.Status {
2f46b760
 	updates, err := daemon.SubscribeToContainerStats(job.Args[0])
4f174aa7
 	if err != nil {
 		return job.Error(err)
 	}
 	enc := json.NewEncoder(job.Stdout)
2f46b760
 	for v := range updates {
 		update := v.(*execdriver.ResourceStats)
68ba5f0b
 		ss := convertToAPITypes(update.Stats)
4f174aa7
 		ss.MemoryStats.Limit = uint64(update.MemoryLimit)
 		ss.Read = update.Read
 		ss.CpuStats.SystemUsage = update.SystemUsage
 		if err := enc.Encode(ss); err != nil {
 			// TODO: handle the specific broken pipe
2f46b760
 			daemon.UnsubscribeToContainerStats(job.Args[0], updates)
4f174aa7
 			return job.Error(err)
 		}
 	}
 	return engine.StatusOK
 }
2f46b760
 
68ba5f0b
 // convertToAPITypes converts the libcontainer.Stats to the api specific
2f46b760
 // structs.  This is done to preserve API compatibility and versioning.
68ba5f0b
 func convertToAPITypes(ls *libcontainer.Stats) *types.Stats {
7fed7d7e
 	s := &types.Stats{}
68ba5f0b
 	if ls.Interfaces != nil {
 		s.Network = types.Network{}
 		for _, iface := range ls.Interfaces {
 			s.Network.RxBytes += iface.RxBytes
 			s.Network.RxPackets += iface.RxPackets
 			s.Network.RxErrors += iface.RxErrors
 			s.Network.RxDropped += iface.RxDropped
 			s.Network.TxBytes += iface.TxBytes
 			s.Network.TxPackets += iface.TxPackets
 			s.Network.TxErrors += iface.TxErrors
 			s.Network.TxDropped += iface.TxDropped
2f46b760
 		}
 	}
 	cs := ls.CgroupStats
 	if cs != nil {
7fed7d7e
 		s.BlkioStats = types.BlkioStats{
2f46b760
 			IoServiceBytesRecursive: copyBlkioEntry(cs.BlkioStats.IoServiceBytesRecursive),
 			IoServicedRecursive:     copyBlkioEntry(cs.BlkioStats.IoServicedRecursive),
 			IoQueuedRecursive:       copyBlkioEntry(cs.BlkioStats.IoQueuedRecursive),
 			IoServiceTimeRecursive:  copyBlkioEntry(cs.BlkioStats.IoServiceTimeRecursive),
 			IoWaitTimeRecursive:     copyBlkioEntry(cs.BlkioStats.IoWaitTimeRecursive),
 			IoMergedRecursive:       copyBlkioEntry(cs.BlkioStats.IoMergedRecursive),
 			IoTimeRecursive:         copyBlkioEntry(cs.BlkioStats.IoTimeRecursive),
 			SectorsRecursive:        copyBlkioEntry(cs.BlkioStats.SectorsRecursive),
 		}
 		cpu := cs.CpuStats
7fed7d7e
 		s.CpuStats = types.CpuStats{
 			CpuUsage: types.CpuUsage{
2f46b760
 				TotalUsage:        cpu.CpuUsage.TotalUsage,
 				PercpuUsage:       cpu.CpuUsage.PercpuUsage,
 				UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode,
 				UsageInUsermode:   cpu.CpuUsage.UsageInUsermode,
 			},
7fed7d7e
 			ThrottlingData: types.ThrottlingData{
2f46b760
 				Periods:          cpu.ThrottlingData.Periods,
 				ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods,
 				ThrottledTime:    cpu.ThrottlingData.ThrottledTime,
 			},
 		}
 		mem := cs.MemoryStats
7fed7d7e
 		s.MemoryStats = types.MemoryStats{
2f46b760
 			Usage:    mem.Usage,
 			MaxUsage: mem.MaxUsage,
 			Stats:    mem.Stats,
 			Failcnt:  mem.Failcnt,
 		}
 	}
 	return s
 }
 
7fed7d7e
 func copyBlkioEntry(entries []cgroups.BlkioStatEntry) []types.BlkioStatEntry {
 	out := make([]types.BlkioStatEntry, len(entries))
2f46b760
 	for i, re := range entries {
7fed7d7e
 		out[i] = types.BlkioStatEntry{
2f46b760
 			Major: re.Major,
 			Minor: re.Minor,
 			Op:    re.Op,
 			Value: re.Value,
 		}
 	}
 	return out
 }