github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/daemon/logger/adapter.go (about) 1 package logger 2 3 import ( 4 "io" 5 "os" 6 "strings" 7 "sync" 8 "time" 9 10 "github.com/docker/docker/api/types/plugins/logdriver" 11 "github.com/docker/docker/pkg/plugingetter" 12 "github.com/pkg/errors" 13 "github.com/sirupsen/logrus" 14 ) 15 16 // pluginAdapter takes a plugin and implements the Logger interface for logger 17 // instances 18 type pluginAdapter struct { 19 driverName string 20 id string 21 plugin logPlugin 22 basePath string 23 fifoPath string 24 capabilities Capability 25 logInfo Info 26 27 // synchronize access to the log stream and shared buffer 28 mu sync.Mutex 29 enc logdriver.LogEntryEncoder 30 stream io.WriteCloser 31 // buf is shared for each `Log()` call to reduce allocations. 32 // buf must be protected by mutex 33 buf logdriver.LogEntry 34 } 35 36 func (a *pluginAdapter) Log(msg *Message) error { 37 a.mu.Lock() 38 39 a.buf.Line = msg.Line 40 a.buf.TimeNano = msg.Timestamp.UnixNano() 41 a.buf.Partial = msg.Partial 42 a.buf.Source = msg.Source 43 44 err := a.enc.Encode(&a.buf) 45 a.buf.Reset() 46 47 a.mu.Unlock() 48 49 PutMessage(msg) 50 return err 51 } 52 53 func (a *pluginAdapter) Name() string { 54 return a.driverName 55 } 56 57 func (a *pluginAdapter) Close() error { 58 a.mu.Lock() 59 defer a.mu.Unlock() 60 61 if err := a.plugin.StopLogging(strings.TrimPrefix(a.fifoPath, a.basePath)); err != nil { 62 return err 63 } 64 65 if err := a.stream.Close(); err != nil { 66 logrus.WithError(err).Error("error closing plugin fifo") 67 } 68 if err := os.Remove(a.fifoPath); err != nil && !os.IsNotExist(err) { 69 logrus.WithError(err).Error("error cleaning up plugin fifo") 70 } 71 72 // may be nil, especially for unit tests 73 if pluginGetter != nil { 74 pluginGetter.Get(a.Name(), extName, plugingetter.Release) 75 } 76 return nil 77 } 78 79 type pluginAdapterWithRead struct { 80 *pluginAdapter 81 } 82 83 func (a *pluginAdapterWithRead) ReadLogs(config ReadConfig) *LogWatcher { 84 watcher := NewLogWatcher() 85 86 go func() { 87 defer close(watcher.Msg) 88 stream, err := a.plugin.ReadLogs(a.logInfo, config) 89 if err != nil { 90 watcher.Err <- errors.Wrap(err, "error getting log reader") 91 return 92 } 93 defer stream.Close() 94 95 dec := logdriver.NewLogEntryDecoder(stream) 96 for { 97 select { 98 case <-watcher.WatchClose(): 99 return 100 default: 101 } 102 103 var buf logdriver.LogEntry 104 if err := dec.Decode(&buf); err != nil { 105 if err == io.EOF { 106 return 107 } 108 select { 109 case watcher.Err <- errors.Wrap(err, "error decoding log message"): 110 case <-watcher.WatchClose(): 111 } 112 return 113 } 114 115 msg := &Message{ 116 Timestamp: time.Unix(0, buf.TimeNano), 117 Line: buf.Line, 118 Source: buf.Source, 119 } 120 121 // plugin should handle this, but check just in case 122 if !config.Since.IsZero() && msg.Timestamp.Before(config.Since) { 123 continue 124 } 125 if !config.Until.IsZero() && msg.Timestamp.After(config.Until) { 126 return 127 } 128 129 select { 130 case watcher.Msg <- msg: 131 case <-watcher.WatchClose(): 132 // make sure the message we consumed is sent 133 watcher.Msg <- msg 134 return 135 } 136 } 137 }() 138 139 return watcher 140 }