github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/logger/loggerutils/cache/local_cache.go (about) 1 package cache // import "github.com/docker/docker/daemon/logger/loggerutils/cache" 2 3 import ( 4 "strconv" 5 6 "github.com/docker/docker/api/types/container" 7 "github.com/docker/docker/daemon/logger" 8 "github.com/docker/docker/daemon/logger/local" 9 units "github.com/docker/go-units" 10 "github.com/pkg/errors" 11 "github.com/sirupsen/logrus" 12 ) 13 14 const ( 15 // DriverName is the name of the driver used for local log caching 16 DriverName = local.Name 17 18 cachePrefix = "cache-" 19 cacheDisabledKey = cachePrefix + "disabled" 20 ) 21 22 var builtInCacheLogOpts = map[string]bool{ 23 cacheDisabledKey: true, 24 } 25 26 // WithLocalCache wraps the passed in logger with a logger caches all writes locally 27 // in addition to writing to the passed in logger. 28 func WithLocalCache(l logger.Logger, info logger.Info) (logger.Logger, error) { 29 initLogger, err := logger.GetLogDriver(DriverName) 30 if err != nil { 31 return nil, err 32 } 33 34 cacher, err := initLogger(info) 35 if err != nil { 36 return nil, errors.Wrap(err, "error initializing local log cache driver") 37 } 38 39 if container.LogMode(info.Config["mode"]) == container.LogModeUnset || container.LogMode(info.Config["mode"]) == container.LogModeNonBlock { 40 var size int64 = -1 41 if s, exists := info.Config["max-buffer-size"]; exists { 42 size, err = units.RAMInBytes(s) 43 if err != nil { 44 return nil, err 45 } 46 } 47 cacher = logger.NewRingLogger(cacher, info, size) 48 } 49 50 return &loggerWithCache{ 51 l: l, 52 cache: cacher, 53 }, nil 54 } 55 56 type loggerWithCache struct { 57 l logger.Logger 58 cache logger.Logger 59 } 60 61 var _ logger.SizedLogger = &loggerWithCache{} 62 63 // BufSize returns the buffer size of the underlying logger. 64 // Returns -1 if the logger doesn't match SizedLogger interface. 65 func (l *loggerWithCache) BufSize() int { 66 if sl, ok := l.l.(logger.SizedLogger); ok { 67 return sl.BufSize() 68 } 69 return -1 70 } 71 72 func (l *loggerWithCache) Log(msg *logger.Message) error { 73 // copy the message as the original will be reset once the call to `Log` is complete 74 dup := logger.NewMessage() 75 dumbCopyMessage(dup, msg) 76 77 if err := l.l.Log(msg); err != nil { 78 return err 79 } 80 return l.cache.Log(dup) 81 } 82 83 func (l *loggerWithCache) Name() string { 84 return l.l.Name() 85 } 86 87 func (l *loggerWithCache) ReadLogs(config logger.ReadConfig) *logger.LogWatcher { 88 return l.cache.(logger.LogReader).ReadLogs(config) 89 } 90 91 func (l *loggerWithCache) Close() error { 92 err := l.l.Close() 93 if err := l.cache.Close(); err != nil { 94 logrus.WithError(err).Warn("error while shutting cache logger") 95 } 96 return err 97 } 98 99 // ShouldUseCache reads the log opts to determine if caching should be enabled 100 func ShouldUseCache(cfg map[string]string) bool { 101 if cfg[cacheDisabledKey] == "" { 102 return true 103 } 104 b, err := strconv.ParseBool(cfg[cacheDisabledKey]) 105 if err != nil { 106 // This shouldn't happen since the values are validated before hand. 107 return false 108 } 109 return !b 110 } 111 112 // dumbCopyMessage is a bit of a fake copy but avoids extra allocations which 113 // are not necessary for this use case. 114 func dumbCopyMessage(dst, src *logger.Message) { 115 dst.Source = src.Source 116 dst.Timestamp = src.Timestamp 117 dst.PLogMetaData = src.PLogMetaData 118 dst.Err = src.Err 119 dst.Attrs = src.Attrs 120 dst.Line = append(dst.Line[:0], src.Line...) 121 }