github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/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 readers map[*logger.LogWatcher]struct{} // stores the active log followers 29 extra []byte // json-encoded extra attributes 30 closed bool 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(info logger.Info) (logger.Logger, error) { 45 var capval int64 = -1 46 if capacity, ok := info.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 := info.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(info.LogPath, capval, maxFiles) 66 if err != nil { 67 return nil, err 68 } 69 70 var extra []byte 71 attrs, err := info.ExtraAttributes(nil) 72 if err != nil { 73 return nil, err 74 } 75 if len(attrs) > 0 { 76 var err error 77 extra, err = json.Marshal(attrs) 78 if err != nil { 79 return nil, err 80 } 81 } 82 83 return &JSONFileLogger{ 84 buf: bytes.NewBuffer(nil), 85 writer: writer, 86 readers: make(map[*logger.LogWatcher]struct{}), 87 extra: extra, 88 }, nil 89 } 90 91 // Log converts logger.Message to jsonlog.JSONLog and serializes it to file. 92 func (l *JSONFileLogger) Log(msg *logger.Message) error { 93 timestamp, err := jsonlog.FastTimeMarshalJSON(msg.Timestamp) 94 if err != nil { 95 return err 96 } 97 l.mu.Lock() 98 logline := msg.Line 99 if !msg.Partial { 100 logline = append(msg.Line, '\n') 101 } 102 err = (&jsonlog.JSONLogs{ 103 Log: logline, 104 Stream: msg.Source, 105 Created: timestamp, 106 RawAttrs: l.extra, 107 }).MarshalJSONBuf(l.buf) 108 logger.PutMessage(msg) 109 if err != nil { 110 l.mu.Unlock() 111 return err 112 } 113 114 l.buf.WriteByte('\n') 115 _, err = l.writer.Write(l.buf.Bytes()) 116 l.buf.Reset() 117 l.mu.Unlock() 118 119 return err 120 } 121 122 // ValidateLogOpt looks for json specific log options max-file & max-size. 123 func ValidateLogOpt(cfg map[string]string) error { 124 for key := range cfg { 125 switch key { 126 case "max-file": 127 case "max-size": 128 case "labels": 129 case "env": 130 case "env-regex": 131 default: 132 return fmt.Errorf("unknown log opt '%s' for json-file log driver", key) 133 } 134 } 135 return nil 136 } 137 138 // LogPath returns the location the given json logger logs to. 139 func (l *JSONFileLogger) LogPath() string { 140 return l.writer.LogPath() 141 } 142 143 // Close closes underlying file and signals all readers to stop. 144 func (l *JSONFileLogger) Close() error { 145 l.mu.Lock() 146 l.closed = true 147 err := l.writer.Close() 148 for r := range l.readers { 149 r.Close() 150 delete(l.readers, r) 151 } 152 l.mu.Unlock() 153 return err 154 } 155 156 // Name returns name of this logger. 157 func (l *JSONFileLogger) Name() string { 158 return Name 159 }