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
} |