github.com/yogeshlonkar/moby@v1.13.2-0.20201203103638-c0b64beaea94/daemon/logger/jsonfilelog/jsonfilelog.go (about) 1 // Package jsonfilelog provides the default Logger implementation for 2 // Docker logging. This logger logs to files on the host server in the 3 // JSON format. 4 package jsonfilelog 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "io" 11 "strconv" 12 "sync" 13 14 "github.com/sirupsen/logrus" 15 "github.com/docker/docker/daemon/logger" 16 "github.com/docker/docker/daemon/logger/loggerutils" 17 "github.com/docker/docker/pkg/jsonlog" 18 "github.com/docker/go-units" 19 "github.com/pkg/errors" 20 ) 21 22 // Name is the name of the file that the jsonlogger logs to. 23 const Name = "json-file" 24 25 // JSONFileLogger is Logger implementation for default Docker logging. 26 type JSONFileLogger struct { 27 extra []byte // json-encoded extra attributes 28 29 mu sync.RWMutex 30 buf *bytes.Buffer // avoids allocating a new buffer on each call to `Log()` 31 closed bool 32 writer *loggerutils.RotateFileWriter 33 readers map[*logger.LogWatcher]struct{} // stores the active log followers 34 } 35 36 func init() { 37 if err := logger.RegisterLogDriver(Name, New); err != nil { 38 logrus.Fatal(err) 39 } 40 if err := logger.RegisterLogOptValidator(Name, ValidateLogOpt); err != nil { 41 logrus.Fatal(err) 42 } 43 } 44 45 // New creates new JSONFileLogger which writes to filename passed in 46 // on given context. 47 func New(ctx logger.Context) (logger.Logger, error) { 48 var capval int64 = -1 49 if capacity, ok := ctx.Config["max-size"]; ok { 50 var err error 51 capval, err = units.FromHumanSize(capacity) 52 if err != nil { 53 return nil, err 54 } 55 } 56 var maxFiles = 1 57 if maxFileString, ok := ctx.Config["max-file"]; ok { 58 var err error 59 maxFiles, err = strconv.Atoi(maxFileString) 60 if err != nil { 61 return nil, err 62 } 63 if maxFiles < 1 { 64 return nil, fmt.Errorf("max-file cannot be less than 1") 65 } 66 } 67 68 writer, err := loggerutils.NewRotateFileWriter(ctx.LogPath, capval, maxFiles) 69 if err != nil { 70 return nil, err 71 } 72 73 var extra []byte 74 if attrs := ctx.ExtraAttributes(nil); len(attrs) > 0 { 75 var err error 76 extra, err = json.Marshal(attrs) 77 if err != nil { 78 return nil, err 79 } 80 } 81 82 return &JSONFileLogger{ 83 buf: bytes.NewBuffer(nil), 84 writer: writer, 85 readers: make(map[*logger.LogWatcher]struct{}), 86 extra: extra, 87 }, nil 88 } 89 90 // Log converts logger.Message to jsonlog.JSONLog and serializes it to file. 91 func (l *JSONFileLogger) Log(msg *logger.Message) error { 92 l.mu.Lock() 93 err := writeMessageBuf(l.writer, msg, l.extra, l.buf) 94 l.buf.Reset() 95 l.mu.Unlock() 96 return err 97 } 98 99 func writeMessageBuf(w io.Writer, m *logger.Message, extra json.RawMessage, buf *bytes.Buffer) error { 100 if err := marshalMessage(m, extra, buf); err != nil { 101 return err 102 } 103 if _, err := w.Write(buf.Bytes()); err != nil { 104 return errors.Wrap(err, "error writing log entry") 105 } 106 return nil 107 } 108 109 func marshalMessage(msg *logger.Message, extra json.RawMessage, buf *bytes.Buffer) error { 110 timestamp, err := jsonlog.FastTimeMarshalJSON(msg.Timestamp) 111 if err != nil { 112 return err 113 } 114 logLine := msg.Line 115 if !msg.Partial { 116 logLine = append(msg.Line, '\n') 117 } 118 err = (&jsonlog.JSONLogs{ 119 Log: logLine, 120 Stream: msg.Source, 121 Created: timestamp, 122 RawAttrs: extra, 123 }).MarshalJSONBuf(buf) 124 if err != nil { 125 return errors.Wrap(err, "error writing log message to buffer") 126 } 127 err = buf.WriteByte('\n') 128 return errors.Wrap(err, "error finalizing log buffer") 129 } 130 131 // ValidateLogOpt looks for json specific log options max-file & max-size. 132 func ValidateLogOpt(cfg map[string]string) error { 133 for key := range cfg { 134 switch key { 135 case "max-file": 136 case "max-size": 137 case "labels": 138 case "env": 139 default: 140 return fmt.Errorf("unknown log opt '%s' for json-file log driver", key) 141 } 142 } 143 return nil 144 } 145 146 // LogPath returns the location the given json logger logs to. 147 func (l *JSONFileLogger) LogPath() string { 148 return l.writer.LogPath() 149 } 150 151 // Close closes underlying file and signals all readers to stop. 152 func (l *JSONFileLogger) Close() error { 153 l.mu.Lock() 154 err := l.writer.Close() 155 for r := range l.readers { 156 r.Close() 157 delete(l.readers, r) 158 } 159 l.mu.Unlock() 160 return err 161 } 162 163 // Name returns name of this logger. 164 func (l *JSONFileLogger) Name() string { 165 return Name 166 }