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