github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/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 "strconv" 11 "sync" 12 13 "github.com/Sirupsen/logrus" 14 "github.com/docker/docker/daemon/logger" 15 "github.com/docker/docker/daemon/logger/loggerutils" 16 "github.com/docker/docker/pkg/jsonlog" 17 "github.com/docker/go-units" 18 ) 19 20 // Name is the name of the file that the jsonlogger logs to. 21 const Name = "json-file" 22 23 // JSONFileLogger is Logger implementation for default Docker logging. 24 type JSONFileLogger struct { 25 buf *bytes.Buffer 26 writer *loggerutils.RotateFileWriter 27 mu sync.Mutex 28 ctx logger.Context 29 readers map[*logger.LogWatcher]struct{} // stores the active log followers 30 extra []byte // json-encoded extra attributes 31 } 32 33 func init() { 34 if err := logger.RegisterLogDriver(Name, New); err != nil { 35 logrus.Fatal(err) 36 } 37 if err := logger.RegisterLogOptValidator(Name, ValidateLogOpt); err != nil { 38 logrus.Fatal(err) 39 } 40 } 41 42 // New creates new JSONFileLogger which writes to filename passed in 43 // on given context. 44 func New(ctx logger.Context) (logger.Logger, error) { 45 var capval int64 = -1 46 if capacity, ok := ctx.Config["max-size"]; ok { 47 var err error 48 capval, err = units.FromHumanSize(capacity) 49 if err != nil { 50 return nil, err 51 } 52 } 53 var maxFiles = 1 54 if maxFileString, ok := ctx.Config["max-file"]; ok { 55 var err error 56 maxFiles, err = strconv.Atoi(maxFileString) 57 if err != nil { 58 return nil, err 59 } 60 if maxFiles < 1 { 61 return nil, fmt.Errorf("max-file cannot be less than 1") 62 } 63 } 64 65 writer, err := loggerutils.NewRotateFileWriter(ctx.LogPath, capval, maxFiles) 66 if err != nil { 67 return nil, err 68 } 69 70 var extra []byte 71 if attrs := ctx.ExtraAttributes(nil); len(attrs) > 0 { 72 var err error 73 extra, err = json.Marshal(attrs) 74 if err != nil { 75 return nil, err 76 } 77 } 78 79 return &JSONFileLogger{ 80 buf: bytes.NewBuffer(nil), 81 writer: writer, 82 readers: make(map[*logger.LogWatcher]struct{}), 83 extra: extra, 84 }, nil 85 } 86 87 // Log converts logger.Message to jsonlog.JSONLog and serializes it to file. 88 func (l *JSONFileLogger) Log(msg *logger.Message) error { 89 timestamp, err := jsonlog.FastTimeMarshalJSON(msg.Timestamp) 90 if err != nil { 91 return err 92 } 93 l.mu.Lock() 94 defer l.mu.Unlock() 95 err = (&jsonlog.JSONLogs{ 96 Log: append(msg.Line, '\n'), 97 Stream: msg.Source, 98 Created: timestamp, 99 RawAttrs: l.extra, 100 }).MarshalJSONBuf(l.buf) 101 if err != nil { 102 return err 103 } 104 105 l.buf.WriteByte('\n') 106 _, err = l.writer.Write(l.buf.Bytes()) 107 l.buf.Reset() 108 109 return err 110 } 111 112 // ValidateLogOpt looks for json specific log options max-file & max-size. 113 func ValidateLogOpt(cfg map[string]string) error { 114 for key := range cfg { 115 switch key { 116 case "max-file": 117 case "max-size": 118 case "labels": 119 case "env": 120 default: 121 return fmt.Errorf("unknown log opt '%s' for json-file log driver", key) 122 } 123 } 124 return nil 125 } 126 127 // LogPath returns the location the given json logger logs to. 128 func (l *JSONFileLogger) LogPath() string { 129 return l.writer.LogPath() 130 } 131 132 // Close closes underlying file and signals all readers to stop. 133 func (l *JSONFileLogger) Close() error { 134 l.mu.Lock() 135 err := l.writer.Close() 136 for r := range l.readers { 137 r.Close() 138 delete(l.readers, r) 139 } 140 l.mu.Unlock() 141 return err 142 } 143 144 // Name returns name of this logger. 145 func (l *JSONFileLogger) Name() string { 146 return Name 147 }