github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/daemon/logger/loggerutils/cache/local_cache.go (about) 1 package cache // import "github.com/demonoid81/moby/daemon/logger/loggerutils/cache" 2 3 import ( 4 "strconv" 5 6 "github.com/demonoid81/moby/api/types/container" 7 "github.com/demonoid81/moby/daemon/logger" 8 "github.com/demonoid81/moby/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 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 func (l *loggerWithCache) Log(msg *logger.Message) error { 62 // copy the message as the original will be reset once the call to `Log` is complete 63 dup := logger.NewMessage() 64 dumbCopyMessage(dup, msg) 65 66 if err := l.l.Log(msg); err != nil { 67 return err 68 } 69 return l.cache.Log(dup) 70 } 71 72 func (l *loggerWithCache) Name() string { 73 return l.l.Name() 74 } 75 76 func (l *loggerWithCache) ReadLogs(config logger.ReadConfig) *logger.LogWatcher { 77 return l.cache.(logger.LogReader).ReadLogs(config) 78 } 79 80 func (l *loggerWithCache) Close() error { 81 err := l.l.Close() 82 if err := l.cache.Close(); err != nil { 83 logrus.WithError(err).Warn("error while shutting cache logger") 84 } 85 return err 86 } 87 88 // ShouldUseCache reads the log opts to determine if caching should be enabled 89 func ShouldUseCache(cfg map[string]string) bool { 90 if cfg[cacheDisabledKey] == "" { 91 return true 92 } 93 b, err := strconv.ParseBool(cfg[cacheDisabledKey]) 94 if err != nil { 95 // This shouldn't happen since the values are validated before hand. 96 return false 97 } 98 return !b 99 } 100 101 // dumbCopyMessage is a bit of a fake copy but avoids extra allocations which 102 // are not necessary for this use case. 103 func dumbCopyMessage(dst, src *logger.Message) { 104 dst.Source = src.Source 105 dst.Timestamp = src.Timestamp 106 dst.PLogMetaData = src.PLogMetaData 107 dst.Err = src.Err 108 dst.Attrs = src.Attrs 109 dst.Line = append(dst.Line[:0], src.Line...) 110 }