github.com/torfuzx/docker@v1.8.1/daemon/stats.go (about)

     1  package daemon
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  
     7  	"github.com/docker/docker/api/types"
     8  	"github.com/docker/docker/daemon/execdriver"
     9  	"github.com/docker/libnetwork/sandbox"
    10  	"github.com/opencontainers/runc/libcontainer"
    11  )
    12  
    13  type ContainerStatsConfig struct {
    14  	Stream    bool
    15  	OutStream io.Writer
    16  	Stop      <-chan bool
    17  }
    18  
    19  func (daemon *Daemon) ContainerStats(name string, config *ContainerStatsConfig) error {
    20  	updates, err := daemon.SubscribeToContainerStats(name)
    21  	if err != nil {
    22  		return err
    23  	}
    24  
    25  	if config.Stream {
    26  		config.OutStream.Write(nil)
    27  	}
    28  
    29  	var preCpuStats types.CpuStats
    30  	getStat := func(v interface{}) *types.Stats {
    31  		update := v.(*execdriver.ResourceStats)
    32  		// Retrieve the nw statistics from libnetwork and inject them in the Stats
    33  		if nwStats, err := daemon.getNetworkStats(name); err == nil {
    34  			update.Stats.Interfaces = nwStats
    35  		}
    36  		ss := convertStatsToAPITypes(update.Stats)
    37  		ss.PreCpuStats = preCpuStats
    38  		ss.MemoryStats.Limit = uint64(update.MemoryLimit)
    39  		ss.Read = update.Read
    40  		ss.CpuStats.SystemUsage = update.SystemUsage
    41  		preCpuStats = ss.CpuStats
    42  		return ss
    43  	}
    44  
    45  	enc := json.NewEncoder(config.OutStream)
    46  
    47  	defer daemon.UnsubscribeToContainerStats(name, updates)
    48  
    49  	noStreamFirstFrame := true
    50  	for {
    51  		select {
    52  		case v, ok := <-updates:
    53  			if !ok {
    54  				return nil
    55  			}
    56  
    57  			s := getStat(v)
    58  			if !config.Stream && noStreamFirstFrame {
    59  				// prime the cpu stats so they aren't 0 in the final output
    60  				noStreamFirstFrame = false
    61  				continue
    62  			}
    63  
    64  			if err := enc.Encode(s); err != nil {
    65  				return err
    66  			}
    67  
    68  			if !config.Stream {
    69  				return nil
    70  			}
    71  		case <-config.Stop:
    72  			return nil
    73  		}
    74  	}
    75  }
    76  
    77  func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInterface, error) {
    78  	var list []*libcontainer.NetworkInterface
    79  
    80  	c, err := daemon.Get(name)
    81  	if err != nil {
    82  		return list, err
    83  	}
    84  
    85  	nw, err := daemon.netController.NetworkByID(c.NetworkSettings.NetworkID)
    86  	if err != nil {
    87  		return list, err
    88  	}
    89  	ep, err := nw.EndpointByID(c.NetworkSettings.EndpointID)
    90  	if err != nil {
    91  		return list, err
    92  	}
    93  
    94  	stats, err := ep.Statistics()
    95  	if err != nil {
    96  		return list, err
    97  	}
    98  
    99  	// Convert libnetwork nw stats into libcontainer nw stats
   100  	for ifName, ifStats := range stats {
   101  		list = append(list, convertLnNetworkStats(ifName, ifStats))
   102  	}
   103  
   104  	return list, nil
   105  }
   106  
   107  func convertLnNetworkStats(name string, stats *sandbox.InterfaceStatistics) *libcontainer.NetworkInterface {
   108  	n := &libcontainer.NetworkInterface{Name: name}
   109  	n.RxBytes = stats.RxBytes
   110  	n.RxPackets = stats.RxPackets
   111  	n.RxErrors = stats.RxErrors
   112  	n.RxDropped = stats.RxDropped
   113  	n.TxBytes = stats.TxBytes
   114  	n.TxPackets = stats.TxPackets
   115  	n.TxErrors = stats.TxErrors
   116  	n.TxDropped = stats.TxDropped
   117  	return n
   118  }