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 }