github.com/ralexstokes/docker@v1.6.2/daemon/stats.go (about)

     1  package daemon
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"github.com/docker/docker/api/types"
     7  	"github.com/docker/docker/daemon/execdriver"
     8  	"github.com/docker/docker/engine"
     9  	"github.com/docker/libcontainer"
    10  	"github.com/docker/libcontainer/cgroups"
    11  )
    12  
    13  func (daemon *Daemon) ContainerStats(job *engine.Job) engine.Status {
    14  	updates, err := daemon.SubscribeToContainerStats(job.Args[0])
    15  	if err != nil {
    16  		return job.Error(err)
    17  	}
    18  	enc := json.NewEncoder(job.Stdout)
    19  	for v := range updates {
    20  		update := v.(*execdriver.ResourceStats)
    21  		ss := convertToAPITypes(update.Stats)
    22  		ss.MemoryStats.Limit = uint64(update.MemoryLimit)
    23  		ss.Read = update.Read
    24  		ss.CpuStats.SystemUsage = update.SystemUsage
    25  		if err := enc.Encode(ss); err != nil {
    26  			// TODO: handle the specific broken pipe
    27  			daemon.UnsubscribeToContainerStats(job.Args[0], updates)
    28  			return job.Error(err)
    29  		}
    30  	}
    31  	return engine.StatusOK
    32  }
    33  
    34  // convertToAPITypes converts the libcontainer.Stats to the api specific
    35  // structs.  This is done to preserve API compatibility and versioning.
    36  func convertToAPITypes(ls *libcontainer.Stats) *types.Stats {
    37  	s := &types.Stats{}
    38  	if ls.Interfaces != nil {
    39  		s.Network = types.Network{}
    40  		for _, iface := range ls.Interfaces {
    41  			s.Network.RxBytes += iface.RxBytes
    42  			s.Network.RxPackets += iface.RxPackets
    43  			s.Network.RxErrors += iface.RxErrors
    44  			s.Network.RxDropped += iface.RxDropped
    45  			s.Network.TxBytes += iface.TxBytes
    46  			s.Network.TxPackets += iface.TxPackets
    47  			s.Network.TxErrors += iface.TxErrors
    48  			s.Network.TxDropped += iface.TxDropped
    49  		}
    50  	}
    51  	cs := ls.CgroupStats
    52  	if cs != nil {
    53  		s.BlkioStats = types.BlkioStats{
    54  			IoServiceBytesRecursive: copyBlkioEntry(cs.BlkioStats.IoServiceBytesRecursive),
    55  			IoServicedRecursive:     copyBlkioEntry(cs.BlkioStats.IoServicedRecursive),
    56  			IoQueuedRecursive:       copyBlkioEntry(cs.BlkioStats.IoQueuedRecursive),
    57  			IoServiceTimeRecursive:  copyBlkioEntry(cs.BlkioStats.IoServiceTimeRecursive),
    58  			IoWaitTimeRecursive:     copyBlkioEntry(cs.BlkioStats.IoWaitTimeRecursive),
    59  			IoMergedRecursive:       copyBlkioEntry(cs.BlkioStats.IoMergedRecursive),
    60  			IoTimeRecursive:         copyBlkioEntry(cs.BlkioStats.IoTimeRecursive),
    61  			SectorsRecursive:        copyBlkioEntry(cs.BlkioStats.SectorsRecursive),
    62  		}
    63  		cpu := cs.CpuStats
    64  		s.CpuStats = types.CpuStats{
    65  			CpuUsage: types.CpuUsage{
    66  				TotalUsage:        cpu.CpuUsage.TotalUsage,
    67  				PercpuUsage:       cpu.CpuUsage.PercpuUsage,
    68  				UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode,
    69  				UsageInUsermode:   cpu.CpuUsage.UsageInUsermode,
    70  			},
    71  			ThrottlingData: types.ThrottlingData{
    72  				Periods:          cpu.ThrottlingData.Periods,
    73  				ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods,
    74  				ThrottledTime:    cpu.ThrottlingData.ThrottledTime,
    75  			},
    76  		}
    77  		mem := cs.MemoryStats
    78  		s.MemoryStats = types.MemoryStats{
    79  			Usage:    mem.Usage,
    80  			MaxUsage: mem.MaxUsage,
    81  			Stats:    mem.Stats,
    82  			Failcnt:  mem.Failcnt,
    83  		}
    84  	}
    85  	return s
    86  }
    87  
    88  func copyBlkioEntry(entries []cgroups.BlkioStatEntry) []types.BlkioStatEntry {
    89  	out := make([]types.BlkioStatEntry, len(entries))
    90  	for i, re := range entries {
    91  		out[i] = types.BlkioStatEntry{
    92  			Major: re.Major,
    93  			Minor: re.Minor,
    94  			Op:    re.Op,
    95  			Value: re.Value,
    96  		}
    97  	}
    98  	return out
    99  }