github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/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 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 return err 101 } 102 103 l.buf.WriteByte('\n') 104 _, err = l.writer.Write(l.buf.Bytes()) 105 l.buf.Reset() 106 107 return err 108 } 109 110 // ValidateLogOpt looks for json specific log options max-file & max-size. 111 func ValidateLogOpt(cfg map[string]string) error { 112 for key := range cfg { 113 switch key { 114 case "max-file": 115 case "max-size": 116 case "labels": 117 case "env": 118 default: 119 return fmt.Errorf("unknown log opt '%s' for json-file log driver", key) 120 } 121 } 122 return nil 123 } 124 125 // LogPath returns the location the given json logger logs to. 126 func (l *JSONFileLogger) LogPath() string { 127 return l.writer.LogPath() 128 } 129 130 // Close closes underlying file and signals all readers to stop. 131 func (l *JSONFileLogger) Close() error { 132 l.mu.Lock() 133 err := l.writer.Close() 134 for r := range l.readers { 135 r.Close() 136 delete(l.readers, r) 137 } 138 l.mu.Unlock() 139 return err 140 } 141 142 // Name returns name of this logger. 143 func (l *JSONFileLogger) Name() string { 144 return Name 145 }