github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/daemon/stats/collector.go (about)

     1  package stats // import "github.com/docker/docker/daemon/stats"
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/docker/docker/api/types"
     7  	"github.com/docker/docker/container"
     8  	"github.com/docker/docker/pkg/pubsub"
     9  	"github.com/sirupsen/logrus"
    10  )
    11  
    12  // Collect registers the container with the collector and adds it to
    13  // the event loop for collection on the specified interval returning
    14  // a channel for the subscriber to receive on.
    15  func (s *Collector) Collect(c *container.Container) chan interface{} {
    16  	s.m.Lock()
    17  	defer s.m.Unlock()
    18  	publisher, exists := s.publishers[c]
    19  	if !exists {
    20  		publisher = pubsub.NewPublisher(100*time.Millisecond, 1024)
    21  		s.publishers[c] = publisher
    22  	}
    23  	return publisher.Subscribe()
    24  }
    25  
    26  // StopCollection closes the channels for all subscribers and removes
    27  // the container from metrics collection.
    28  func (s *Collector) StopCollection(c *container.Container) {
    29  	s.m.Lock()
    30  	if publisher, exists := s.publishers[c]; exists {
    31  		publisher.Close()
    32  		delete(s.publishers, c)
    33  	}
    34  	s.m.Unlock()
    35  }
    36  
    37  // Unsubscribe removes a specific subscriber from receiving updates for a container's stats.
    38  func (s *Collector) Unsubscribe(c *container.Container, ch chan interface{}) {
    39  	s.m.Lock()
    40  	publisher := s.publishers[c]
    41  	if publisher != nil {
    42  		publisher.Evict(ch)
    43  		if publisher.Len() == 0 {
    44  			delete(s.publishers, c)
    45  		}
    46  	}
    47  	s.m.Unlock()
    48  }
    49  
    50  // Run starts the collectors and will indefinitely collect stats from the supervisor
    51  func (s *Collector) Run() {
    52  	type publishersPair struct {
    53  		container *container.Container
    54  		publisher *pubsub.Publisher
    55  	}
    56  	// we cannot determine the capacity here.
    57  	// it will grow enough in first iteration
    58  	var pairs []publishersPair
    59  
    60  	for {
    61  		// Put sleep at the start so that it will always be hit,
    62  		// preventing a tight loop if no stats are collected.
    63  		time.Sleep(s.interval)
    64  
    65  		// it does not make sense in the first iteration,
    66  		// but saves allocations in further iterations
    67  		pairs = pairs[:0]
    68  
    69  		s.m.Lock()
    70  		for container, publisher := range s.publishers {
    71  			// copy pointers here to release the lock ASAP
    72  			pairs = append(pairs, publishersPair{container, publisher})
    73  		}
    74  		s.m.Unlock()
    75  		if len(pairs) == 0 {
    76  			continue
    77  		}
    78  
    79  		onlineCPUs, err := s.getNumberOnlineCPUs()
    80  		if err != nil {
    81  			logrus.Errorf("collecting system online cpu count: %v", err)
    82  			continue
    83  		}
    84  
    85  		for _, pair := range pairs {
    86  			stats, err := s.supervisor.GetContainerStats(pair.container)
    87  
    88  			switch err.(type) {
    89  			case nil:
    90  				// Sample system CPU usage close to container usage to avoid
    91  				// noise in metric calculations.
    92  				systemUsage, err := s.getSystemCPUUsage()
    93  				if err != nil {
    94  					logrus.WithError(err).WithField("container_id", pair.container.ID).Errorf("collecting system cpu usage")
    95  					continue
    96  				}
    97  
    98  				// FIXME: move to containerd on Linux (not Windows)
    99  				stats.CPUStats.SystemUsage = systemUsage
   100  				stats.CPUStats.OnlineCPUs = onlineCPUs
   101  
   102  				pair.publisher.Publish(*stats)
   103  
   104  			case notRunningErr, notFoundErr:
   105  				// publish empty stats containing only name and ID if not running or not found
   106  				pair.publisher.Publish(types.StatsJSON{
   107  					Name: pair.container.Name,
   108  					ID:   pair.container.ID,
   109  				})
   110  
   111  			default:
   112  				logrus.Errorf("collecting stats for %s: %v", pair.container.ID, err)
   113  			}
   114  		}
   115  	}
   116  }
   117  
   118  type notRunningErr interface {
   119  	error
   120  	Conflict()
   121  }
   122  
   123  type notFoundErr interface {
   124  	error
   125  	NotFound()
   126  }