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