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