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