github.com/dpiddy/docker@v1.12.2-rc1/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 } 31 32 func init() { 33 if err := logger.RegisterLogDriver(Name, New); err != nil { 34 logrus.Fatal(err) 35 } 36 if err := logger.RegisterLogOptValidator(Name, ValidateLogOpt); err != nil { 37 logrus.Fatal(err) 38 } 39 } 40 41 // New creates new JSONFileLogger which writes to filename passed in 42 // on given context. 43 func New(ctx logger.Context) (logger.Logger, error) { 44 var capval int64 = -1 45 if capacity, ok := ctx.Config["max-size"]; ok { 46 var err error 47 capval, err = units.FromHumanSize(capacity) 48 if err != nil { 49 return nil, err 50 } 51 } 52 var maxFiles = 1 53 if maxFileString, ok := ctx.Config["max-file"]; ok { 54 var err error 55 maxFiles, err = strconv.Atoi(maxFileString) 56 if err != nil { 57 return nil, err 58 } 59 if maxFiles < 1 { 60 return nil, fmt.Errorf("max-file cannot be less than 1") 61 } 62 } 63 64 writer, err := loggerutils.NewRotateFileWriter(ctx.LogPath, capval, maxFiles) 65 if err != nil { 66 return nil, err 67 } 68 69 var extra []byte 70 if attrs := ctx.ExtraAttributes(nil); len(attrs) > 0 { 71 var err error 72 extra, err = json.Marshal(attrs) 73 if err != nil { 74 return nil, err 75 } 76 } 77 78 return &JSONFileLogger{ 79 buf: bytes.NewBuffer(nil), 80 writer: writer, 81 readers: make(map[*logger.LogWatcher]struct{}), 82 extra: extra, 83 }, nil 84 } 85 86 // Log converts logger.Message to jsonlog.JSONLog and serializes it to file. 87 func (l *JSONFileLogger) Log(msg *logger.Message) error { 88 timestamp, err := jsonlog.FastTimeMarshalJSON(msg.Timestamp) 89 if err != nil { 90 return err 91 } 92 l.mu.Lock() 93 err = (&jsonlog.JSONLogs{ 94 Log: append(msg.Line, '\n'), 95 Stream: msg.Source, 96 Created: timestamp, 97 RawAttrs: l.extra, 98 }).MarshalJSONBuf(l.buf) 99 if err != nil { 100 l.mu.Unlock() 101 return err 102 } 103 104 l.buf.WriteByte('\n') 105 _, err = l.writer.Write(l.buf.Bytes()) 106 l.buf.Reset() 107 l.mu.Unlock() 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 }