github.com/nalind/docker@v1.5.0/events/events.go (about) 1 package events 2 3 import ( 4 "encoding/json" 5 "sync" 6 "time" 7 8 "github.com/docker/docker/engine" 9 "github.com/docker/docker/pkg/parsers/filters" 10 "github.com/docker/docker/utils" 11 ) 12 13 const eventsLimit = 64 14 15 type listener chan<- *utils.JSONMessage 16 17 type Events struct { 18 mu sync.RWMutex 19 events []*utils.JSONMessage 20 subscribers []listener 21 } 22 23 func New() *Events { 24 return &Events{ 25 events: make([]*utils.JSONMessage, 0, eventsLimit), 26 } 27 } 28 29 // Install installs events public api in docker engine 30 func (e *Events) Install(eng *engine.Engine) error { 31 // Here you should describe public interface 32 jobs := map[string]engine.Handler{ 33 "events": e.Get, 34 "log": e.Log, 35 "subscribers_count": e.SubscribersCount, 36 } 37 for name, job := range jobs { 38 if err := eng.Register(name, job); err != nil { 39 return err 40 } 41 } 42 return nil 43 } 44 45 func (e *Events) Get(job *engine.Job) engine.Status { 46 var ( 47 since = job.GetenvInt64("since") 48 until = job.GetenvInt64("until") 49 timeout = time.NewTimer(time.Unix(until, 0).Sub(time.Now())) 50 ) 51 52 eventFilters, err := filters.FromParam(job.Getenv("filters")) 53 if err != nil { 54 return job.Error(err) 55 } 56 57 // If no until, disable timeout 58 if until == 0 { 59 timeout.Stop() 60 } 61 62 listener := make(chan *utils.JSONMessage) 63 e.subscribe(listener) 64 defer e.unsubscribe(listener) 65 66 job.Stdout.Write(nil) 67 68 // Resend every event in the [since, until] time interval. 69 if since != 0 { 70 if err := e.writeCurrent(job, since, until, eventFilters); err != nil { 71 return job.Error(err) 72 } 73 } 74 75 for { 76 select { 77 case event, ok := <-listener: 78 if !ok { 79 return engine.StatusOK 80 } 81 if err := writeEvent(job, event, eventFilters); err != nil { 82 return job.Error(err) 83 } 84 case <-timeout.C: 85 return engine.StatusOK 86 } 87 } 88 } 89 90 func (e *Events) Log(job *engine.Job) engine.Status { 91 if len(job.Args) != 3 { 92 return job.Errorf("usage: %s ACTION ID FROM", job.Name) 93 } 94 // not waiting for receivers 95 go e.log(job.Args[0], job.Args[1], job.Args[2]) 96 return engine.StatusOK 97 } 98 99 func (e *Events) SubscribersCount(job *engine.Job) engine.Status { 100 ret := &engine.Env{} 101 ret.SetInt("count", e.subscribersCount()) 102 ret.WriteTo(job.Stdout) 103 return engine.StatusOK 104 } 105 106 func writeEvent(job *engine.Job, event *utils.JSONMessage, eventFilters filters.Args) error { 107 isFiltered := func(field string, filter []string) bool { 108 if len(filter) == 0 { 109 return false 110 } 111 for _, v := range filter { 112 if v == field { 113 return false 114 } 115 } 116 return true 117 } 118 119 if isFiltered(event.Status, eventFilters["event"]) || isFiltered(event.From, eventFilters["image"]) || isFiltered(event.ID, eventFilters["container"]) { 120 return nil 121 } 122 123 // When sending an event JSON serialization errors are ignored, but all 124 // other errors lead to the eviction of the listener. 125 if b, err := json.Marshal(event); err == nil { 126 if _, err = job.Stdout.Write(b); err != nil { 127 return err 128 } 129 } 130 return nil 131 } 132 133 func (e *Events) writeCurrent(job *engine.Job, since, until int64, eventFilters filters.Args) error { 134 e.mu.RLock() 135 for _, event := range e.events { 136 if event.Time >= since && (event.Time <= until || until == 0) { 137 if err := writeEvent(job, event, eventFilters); err != nil { 138 e.mu.RUnlock() 139 return err 140 } 141 } 142 } 143 e.mu.RUnlock() 144 return nil 145 } 146 147 func (e *Events) subscribersCount() int { 148 e.mu.RLock() 149 c := len(e.subscribers) 150 e.mu.RUnlock() 151 return c 152 } 153 154 func (e *Events) log(action, id, from string) { 155 e.mu.Lock() 156 now := time.Now().UTC().Unix() 157 jm := &utils.JSONMessage{Status: action, ID: id, From: from, Time: now} 158 if len(e.events) == cap(e.events) { 159 // discard oldest event 160 copy(e.events, e.events[1:]) 161 e.events[len(e.events)-1] = jm 162 } else { 163 e.events = append(e.events, jm) 164 } 165 for _, s := range e.subscribers { 166 // We give each subscriber a 100ms time window to receive the event, 167 // after which we move to the next. 168 select { 169 case s <- jm: 170 case <-time.After(100 * time.Millisecond): 171 } 172 } 173 e.mu.Unlock() 174 } 175 176 func (e *Events) subscribe(l listener) { 177 e.mu.Lock() 178 e.subscribers = append(e.subscribers, l) 179 e.mu.Unlock() 180 } 181 182 // unsubscribe closes and removes the specified listener from the list of 183 // previously registed ones. 184 // It returns a boolean value indicating if the listener was successfully 185 // found, closed and unregistered. 186 func (e *Events) unsubscribe(l listener) bool { 187 e.mu.Lock() 188 for i, subscriber := range e.subscribers { 189 if subscriber == l { 190 close(l) 191 e.subscribers = append(e.subscribers[:i], e.subscribers[i+1:]...) 192 e.mu.Unlock() 193 return true 194 } 195 } 196 e.mu.Unlock() 197 return false 198 }