gopkg.in/dotcloud/docker.v1@v1.13.1/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  	logline := msg.Line
    94  	if !msg.Partial {
    95  		logline = append(msg.Line, '\n')
    96  	}
    97  	err = (&jsonlog.JSONLogs{
    98  		Log:      logline,
    99  		Stream:   msg.Source,
   100  		Created:  timestamp,
   101  		RawAttrs: l.extra,
   102  	}).MarshalJSONBuf(l.buf)
   103  	if err != nil {
   104  		l.mu.Unlock()
   105  		return err
   106  	}
   107  
   108  	l.buf.WriteByte('\n')
   109  	_, err = l.writer.Write(l.buf.Bytes())
   110  	l.buf.Reset()
   111  	l.mu.Unlock()
   112  
   113  	return err
   114  }
   115  
   116  // ValidateLogOpt looks for json specific log options max-file & max-size.
   117  func ValidateLogOpt(cfg map[string]string) error {
   118  	for key := range cfg {
   119  		switch key {
   120  		case "max-file":
   121  		case "max-size":
   122  		case "labels":
   123  		case "env":
   124  		default:
   125  			return fmt.Errorf("unknown log opt '%s' for json-file log driver", key)
   126  		}
   127  	}
   128  	return nil
   129  }
   130  
   131  // LogPath returns the location the given json logger logs to.
   132  func (l *JSONFileLogger) LogPath() string {
   133  	return l.writer.LogPath()
   134  }
   135  
   136  // Close closes underlying file and signals all readers to stop.
   137  func (l *JSONFileLogger) Close() error {
   138  	l.mu.Lock()
   139  	err := l.writer.Close()
   140  	for r := range l.readers {
   141  		r.Close()
   142  		delete(l.readers, r)
   143  	}
   144  	l.mu.Unlock()
   145  	return err
   146  }
   147  
   148  // Name returns name of this logger.
   149  func (l *JSONFileLogger) Name() string {
   150  	return Name
   151  }