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  }