github.com/darciopacifico/docker@v1.9.0-rc1/daemon/logger/syslog/syslog.go (about) 1 // +build linux 2 3 // Package syslog provides the logdriver for forwarding server logs to syslog endpoints. 4 package syslog 5 6 import ( 7 "errors" 8 "fmt" 9 "log/syslog" 10 "net" 11 "net/url" 12 "os" 13 "path" 14 "strconv" 15 "strings" 16 17 "github.com/Sirupsen/logrus" 18 "github.com/docker/docker/daemon/logger" 19 "github.com/docker/docker/daemon/logger/loggerutils" 20 "github.com/docker/docker/pkg/urlutil" 21 ) 22 23 const name = "syslog" 24 25 var facilities = map[string]syslog.Priority{ 26 "kern": syslog.LOG_KERN, 27 "user": syslog.LOG_USER, 28 "mail": syslog.LOG_MAIL, 29 "daemon": syslog.LOG_DAEMON, 30 "auth": syslog.LOG_AUTH, 31 "syslog": syslog.LOG_SYSLOG, 32 "lpr": syslog.LOG_LPR, 33 "news": syslog.LOG_NEWS, 34 "uucp": syslog.LOG_UUCP, 35 "cron": syslog.LOG_CRON, 36 "authpriv": syslog.LOG_AUTHPRIV, 37 "ftp": syslog.LOG_FTP, 38 "local0": syslog.LOG_LOCAL0, 39 "local1": syslog.LOG_LOCAL1, 40 "local2": syslog.LOG_LOCAL2, 41 "local3": syslog.LOG_LOCAL3, 42 "local4": syslog.LOG_LOCAL4, 43 "local5": syslog.LOG_LOCAL5, 44 "local6": syslog.LOG_LOCAL6, 45 "local7": syslog.LOG_LOCAL7, 46 } 47 48 type syslogger struct { 49 writer *syslog.Writer 50 } 51 52 func init() { 53 if err := logger.RegisterLogDriver(name, New); err != nil { 54 logrus.Fatal(err) 55 } 56 if err := logger.RegisterLogOptValidator(name, ValidateLogOpt); err != nil { 57 logrus.Fatal(err) 58 } 59 } 60 61 // New creates a syslog logger using the configuration passed in on 62 // the context. Supported context configuration variables are 63 // syslog-address, syslog-facility, & syslog-tag. 64 func New(ctx logger.Context) (logger.Logger, error) { 65 tag, err := loggerutils.ParseLogTag(ctx, "{{.ID}}") 66 if err != nil { 67 return nil, err 68 } 69 70 proto, address, err := parseAddress(ctx.Config["syslog-address"]) 71 if err != nil { 72 return nil, err 73 } 74 75 facility, err := parseFacility(ctx.Config["syslog-facility"]) 76 if err != nil { 77 return nil, err 78 } 79 80 log, err := syslog.Dial( 81 proto, 82 address, 83 facility, 84 path.Base(os.Args[0])+"/"+tag, 85 ) 86 if err != nil { 87 return nil, err 88 } 89 90 return &syslogger{ 91 writer: log, 92 }, nil 93 } 94 95 func (s *syslogger) Log(msg *logger.Message) error { 96 if msg.Source == "stderr" { 97 return s.writer.Err(string(msg.Line)) 98 } 99 return s.writer.Info(string(msg.Line)) 100 } 101 102 func (s *syslogger) Close() error { 103 return s.writer.Close() 104 } 105 106 func (s *syslogger) Name() string { 107 return name 108 } 109 110 func parseAddress(address string) (string, string, error) { 111 if address == "" { 112 return "", "", nil 113 } 114 if !urlutil.IsTransportURL(address) { 115 return "", "", fmt.Errorf("syslog-address should be in form proto://address, got %v", address) 116 } 117 url, err := url.Parse(address) 118 if err != nil { 119 return "", "", err 120 } 121 122 // unix socket validation 123 if url.Scheme == "unix" { 124 if _, err := os.Stat(url.Path); err != nil { 125 return "", "", err 126 } 127 return url.Scheme, url.Path, nil 128 } 129 130 // here we process tcp|udp 131 host := url.Host 132 if _, _, err := net.SplitHostPort(host); err != nil { 133 if !strings.Contains(err.Error(), "missing port in address") { 134 return "", "", err 135 } 136 host = host + ":514" 137 } 138 139 return url.Scheme, host, nil 140 } 141 142 // ValidateLogOpt looks for syslog specific log options 143 // syslog-address, syslog-facility, & syslog-tag. 144 func ValidateLogOpt(cfg map[string]string) error { 145 for key := range cfg { 146 switch key { 147 case "syslog-address": 148 case "syslog-facility": 149 case "syslog-tag": 150 case "tag": 151 default: 152 return fmt.Errorf("unknown log opt '%s' for syslog log driver", key) 153 } 154 } 155 if _, _, err := parseAddress(cfg["syslog-address"]); err != nil { 156 return err 157 } 158 if _, err := parseFacility(cfg["syslog-facility"]); err != nil { 159 return err 160 } 161 return nil 162 } 163 164 func parseFacility(facility string) (syslog.Priority, error) { 165 if facility == "" { 166 return syslog.LOG_DAEMON, nil 167 } 168 169 if syslogFacility, valid := facilities[facility]; valid { 170 return syslogFacility, nil 171 } 172 173 fInt, err := strconv.Atoi(facility) 174 if err == nil && 0 <= fInt && fInt <= 23 { 175 return syslog.Priority(fInt << 3), nil 176 } 177 178 return syslog.Priority(0), errors.New("invalid syslog facility") 179 }