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