package jsonfilelog import ( "bytes" "io" "os" "sync" "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/logger" "github.com/docker/docker/pkg/jsonlog" "github.com/docker/docker/pkg/timeutils" ) const ( Name = "json-file" ) // JSONFileLogger is Logger implementation for default docker logging: // JSON objects to file type JSONFileLogger struct { buf *bytes.Buffer f *os.File // store for closing mu sync.Mutex // protects buffer ctx logger.Context } func init() { if err := logger.RegisterLogDriver(Name, New); err != nil { logrus.Fatal(err) } } // New creates new JSONFileLogger which writes to filename func New(ctx logger.Context) (logger.Logger, error) { log, err := os.OpenFile(ctx.LogPath, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600) if err != nil { return nil, err } return &JSONFileLogger{ f: log, buf: bytes.NewBuffer(nil), ctx: ctx, }, nil } // Log converts logger.Message to jsonlog.JSONLog and serializes it to file func (l *JSONFileLogger) Log(msg *logger.Message) error { l.mu.Lock() defer l.mu.Unlock() timestamp, err := timeutils.FastMarshalJSON(msg.Timestamp) if err != nil { return err } err = (&jsonlog.JSONLogBytes{Log: append(msg.Line, '\n'), Stream: msg.Source, Created: timestamp}).MarshalJSONBuf(l.buf) if err != nil { return err } l.buf.WriteByte('\n') _, err = l.buf.WriteTo(l.f) if err != nil { // this buffer is screwed, replace it with another to avoid races l.buf = bytes.NewBuffer(nil) return err } return nil } func (l *JSONFileLogger) GetReader() (io.Reader, error) { return os.Open(l.ctx.LogPath) } func (l *JSONFileLogger) LogPath() string { return l.ctx.LogPath } // Close closes underlying file func (l *JSONFileLogger) Close() error { return l.f.Close() } // Name returns name of this logger func (l *JSONFileLogger) Name() string { return Name }