local_cache.go 3.1 KB

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