github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/daemon/logger/journald/journald.go (about)

     1  // +build linux
     2  
     3  // Package journald provides the log driver for forwarding server logs
     4  // to endpoints that receive the systemd format.
     5  package journald
     6  
     7  import (
     8  	"fmt"
     9  	"sync"
    10  
    11  	"github.com/Sirupsen/logrus"
    12  	"github.com/coreos/go-systemd/journal"
    13  	"github.com/docker/docker/daemon/logger"
    14  )
    15  
    16  const name = "journald"
    17  
    18  type journald struct {
    19  	vars    map[string]string // additional variables and values to send to the journal along with the log message
    20  	readers readerList
    21  }
    22  
    23  type readerList struct {
    24  	mu      sync.Mutex
    25  	readers map[*logger.LogWatcher]*logger.LogWatcher
    26  }
    27  
    28  func init() {
    29  	if err := logger.RegisterLogDriver(name, New); err != nil {
    30  		logrus.Fatal(err)
    31  	}
    32  	if err := logger.RegisterLogOptValidator(name, validateLogOpt); err != nil {
    33  		logrus.Fatal(err)
    34  	}
    35  }
    36  
    37  // New creates a journald logger using the configuration passed in on
    38  // the context.
    39  func New(ctx logger.Context) (logger.Logger, error) {
    40  	if !journal.Enabled() {
    41  		return nil, fmt.Errorf("journald is not enabled on this host")
    42  	}
    43  	// Strip a leading slash so that people can search for
    44  	// CONTAINER_NAME=foo rather than CONTAINER_NAME=/foo.
    45  	name := ctx.ContainerName
    46  	if name[0] == '/' {
    47  		name = name[1:]
    48  	}
    49  	vars := map[string]string{
    50  		"CONTAINER_ID":      ctx.ContainerID[:12],
    51  		"CONTAINER_ID_FULL": ctx.ContainerID,
    52  		"CONTAINER_NAME":    name}
    53  	return &journald{vars: vars, readers: readerList{readers: make(map[*logger.LogWatcher]*logger.LogWatcher)}}, nil
    54  }
    55  
    56  // We don't actually accept any options, but we have to supply a callback for
    57  // the factory to pass the (probably empty) configuration map to.
    58  func validateLogOpt(cfg map[string]string) error {
    59  	for key := range cfg {
    60  		switch key {
    61  		default:
    62  			return fmt.Errorf("unknown log opt '%s' for journald log driver", key)
    63  		}
    64  	}
    65  	return nil
    66  }
    67  
    68  func (s *journald) Log(msg *logger.Message) error {
    69  	if msg.Source == "stderr" {
    70  		return journal.Send(string(msg.Line), journal.PriErr, s.vars)
    71  	}
    72  	return journal.Send(string(msg.Line), journal.PriInfo, s.vars)
    73  }
    74  
    75  func (s *journald) Name() string {
    76  	return name
    77  }