local_cache.go 3.1 KB

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