github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/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/api/types/versions/v1p20"
     9  	"github.com/docker/docker/daemon/execdriver"
    10  	"github.com/docker/docker/pkg/version"
    11  )
    12  
    13  // ContainerStatsConfig holds information for configuring the runtime
    14  // behavior of a daemon.ContainerStats() call.
    15  type ContainerStatsConfig struct {
    16  	Stream    bool
    17  	OutStream io.Writer
    18  	Stop      <-chan bool
    19  	Version   version.Version
    20  }
    21  
    22  // ContainerStats writes information about the container to the stream
    23  // given in the config object.
    24  func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStatsConfig) error {
    25  	container, err := daemon.GetContainer(prefixOrName)
    26  	if err != nil {
    27  		return err
    28  	}
    29  
    30  	// If the container is not running and requires no stream, return an empty stats.
    31  	if !container.IsRunning() && !config.Stream {
    32  		return json.NewEncoder(config.OutStream).Encode(&types.Stats{})
    33  	}
    34  
    35  	if config.Stream {
    36  		// Write an empty chunk of data.
    37  		// This is to ensure that the HTTP status code is sent immediately,
    38  		// even if the container has not yet produced any data.
    39  		config.OutStream.Write(nil)
    40  	}
    41  
    42  	var preCPUStats types.CPUStats
    43  	getStatJSON := func(v interface{}) *types.StatsJSON {
    44  		update := v.(*execdriver.ResourceStats)
    45  		ss := convertStatsToAPITypes(update.Stats)
    46  		ss.PreCPUStats = preCPUStats
    47  		ss.MemoryStats.Limit = uint64(update.MemoryLimit)
    48  		ss.Read = update.Read
    49  		ss.CPUStats.SystemUsage = update.SystemUsage
    50  		preCPUStats = ss.CPUStats
    51  		return ss
    52  	}
    53  
    54  	enc := json.NewEncoder(config.OutStream)
    55  
    56  	updates := daemon.subscribeToContainerStats(container)
    57  	defer daemon.unsubscribeToContainerStats(container, updates)
    58  
    59  	noStreamFirstFrame := true
    60  	for {
    61  		select {
    62  		case v, ok := <-updates:
    63  			if !ok {
    64  				return nil
    65  			}
    66  
    67  			var statsJSON interface{}
    68  			statsJSONPost120 := getStatJSON(v)
    69  			if config.Version.LessThan("1.21") {
    70  				var (
    71  					rxBytes   uint64
    72  					rxPackets uint64
    73  					rxErrors  uint64
    74  					rxDropped uint64
    75  					txBytes   uint64
    76  					txPackets uint64
    77  					txErrors  uint64
    78  					txDropped uint64
    79  				)
    80  				for _, v := range statsJSONPost120.Networks {
    81  					rxBytes += v.RxBytes
    82  					rxPackets += v.RxPackets
    83  					rxErrors += v.RxErrors
    84  					rxDropped += v.RxDropped
    85  					txBytes += v.TxBytes
    86  					txPackets += v.TxPackets
    87  					txErrors += v.TxErrors
    88  					txDropped += v.TxDropped
    89  				}
    90  				statsJSON = &v1p20.StatsJSON{
    91  					Stats: statsJSONPost120.Stats,
    92  					Network: types.NetworkStats{
    93  						RxBytes:   rxBytes,
    94  						RxPackets: rxPackets,
    95  						RxErrors:  rxErrors,
    96  						RxDropped: rxDropped,
    97  						TxBytes:   txBytes,
    98  						TxPackets: txPackets,
    99  						TxErrors:  txErrors,
   100  						TxDropped: txDropped,
   101  					},
   102  				}
   103  			} else {
   104  				statsJSON = statsJSONPost120
   105  			}
   106  
   107  			if !config.Stream && noStreamFirstFrame {
   108  				// prime the cpu stats so they aren't 0 in the final output
   109  				noStreamFirstFrame = false
   110  				continue
   111  			}
   112  
   113  			if err := enc.Encode(statsJSON); err != nil {
   114  				return err
   115  			}
   116  
   117  			if !config.Stream {
   118  				return nil
   119  			}
   120  		case <-config.Stop:
   121  			return nil
   122  		}
   123  	}
   124  }