github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/logger/adapter.go (about) 1 package logger // import "github.com/Prakhar-Agarwal-byte/moby/daemon/logger" 2 3 import ( 4 "context" 5 "io" 6 "os" 7 "path/filepath" 8 "sync" 9 "time" 10 11 "github.com/containerd/log" 12 "github.com/Prakhar-Agarwal-byte/moby/api/types/plugins/logdriver" 13 "github.com/Prakhar-Agarwal-byte/moby/pkg/plugingetter" 14 "github.com/pkg/errors" 15 ) 16 17 // pluginAdapter takes a plugin and implements the Logger interface for logger 18 // instances 19 type pluginAdapter struct { 20 driverName string 21 id string 22 plugin logPlugin 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.PLogMetaData != nil 42 a.buf.Source = msg.Source 43 if msg.PLogMetaData != nil { 44 a.buf.PartialLogMetadata = &logdriver.PartialLogEntryMetadata{ 45 Id: msg.PLogMetaData.ID, 46 Last: msg.PLogMetaData.Last, 47 Ordinal: int32(msg.PLogMetaData.Ordinal), 48 } 49 } 50 51 err := a.enc.Encode(&a.buf) 52 a.buf.Reset() 53 54 a.mu.Unlock() 55 56 PutMessage(msg) 57 return err 58 } 59 60 func (a *pluginAdapter) Name() string { 61 return a.driverName 62 } 63 64 func (a *pluginAdapter) Close() error { 65 a.mu.Lock() 66 defer a.mu.Unlock() 67 68 if err := a.plugin.StopLogging(filepath.Join("/", "run", "docker", "logging", a.id)); err != nil { 69 return err 70 } 71 72 if err := a.stream.Close(); err != nil { 73 log.G(context.TODO()).WithError(err).Error("error closing plugin fifo") 74 } 75 if err := os.Remove(a.fifoPath); err != nil && !os.IsNotExist(err) { 76 log.G(context.TODO()).WithError(err).Error("error cleaning up plugin fifo") 77 } 78 79 // may be nil, especially for unit tests 80 if pluginGetter != nil { 81 pluginGetter.Get(a.Name(), extName, plugingetter.Release) 82 } 83 return nil 84 } 85 86 type pluginAdapterWithRead struct { 87 *pluginAdapter 88 } 89 90 func (a *pluginAdapterWithRead) ReadLogs(config ReadConfig) *LogWatcher { 91 watcher := NewLogWatcher() 92 93 go func() { 94 defer close(watcher.Msg) 95 stream, err := a.plugin.ReadLogs(a.logInfo, config) 96 if err != nil { 97 watcher.Err <- errors.Wrap(err, "error getting log reader") 98 return 99 } 100 defer stream.Close() 101 102 dec := logdriver.NewLogEntryDecoder(stream) 103 for { 104 var buf logdriver.LogEntry 105 if err := dec.Decode(&buf); err != nil { 106 if err == io.EOF { 107 return 108 } 109 watcher.Err <- errors.Wrap(err, "error decoding log message") 110 return 111 } 112 113 msg := &Message{ 114 Timestamp: time.Unix(0, buf.TimeNano), 115 Line: buf.Line, 116 Source: buf.Source, 117 } 118 119 // plugin should handle this, but check just in case 120 if !config.Since.IsZero() && msg.Timestamp.Before(config.Since) { 121 continue 122 } 123 if !config.Until.IsZero() && msg.Timestamp.After(config.Until) { 124 return 125 } 126 127 // send the message unless the consumer is gone 128 select { 129 case watcher.Msg <- msg: 130 case <-watcher.WatchConsumerGone(): 131 return 132 } 133 } 134 }() 135 136 return watcher 137 }