github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/log/syslog/syslog.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build !windows && !plan9 6 // +build !windows,!plan9 7 8 package syslog 9 10 import ( 11 "errors" 12 "fmt" 13 "log" 14 "net" 15 "os" 16 "strings" 17 "sync" 18 "time" 19 ) 20 21 // The Priority is a combination of the syslog facility and 22 // severity. For example, LOG_ALERT | LOG_FTP sends an alert severity 23 // message from the FTP facility. The default severity is LOG_EMERG; 24 // the default facility is LOG_KERN. 25 type Priority int 26 27 const severityMask = 0x07 28 const facilityMask = 0xf8 29 30 const ( 31 // Severity. 32 33 // From /usr/include/sys/syslog.h. 34 // These are the same on Linux, BSD, and OS X. 35 LOG_EMERG Priority = iota 36 LOG_ALERT 37 LOG_CRIT 38 LOG_ERR 39 LOG_WARNING 40 LOG_NOTICE 41 LOG_INFO 42 LOG_DEBUG 43 ) 44 45 const ( 46 // Facility. 47 48 // From /usr/include/sys/syslog.h. 49 // These are the same up to LOG_FTP on Linux, BSD, and OS X. 50 LOG_KERN Priority = iota << 3 51 LOG_USER 52 LOG_MAIL 53 LOG_DAEMON 54 LOG_AUTH 55 LOG_SYSLOG 56 LOG_LPR 57 LOG_NEWS 58 LOG_UUCP 59 LOG_CRON 60 LOG_AUTHPRIV 61 LOG_FTP 62 _ // unused 63 _ // unused 64 _ // unused 65 _ // unused 66 LOG_LOCAL0 67 LOG_LOCAL1 68 LOG_LOCAL2 69 LOG_LOCAL3 70 LOG_LOCAL4 71 LOG_LOCAL5 72 LOG_LOCAL6 73 LOG_LOCAL7 74 ) 75 76 // A Writer is a connection to a syslog server. 77 type Writer struct { 78 priority Priority 79 tag string 80 hostname string 81 network string 82 raddr string 83 84 mu sync.Mutex // guards conn 85 conn serverConn 86 } 87 88 // This interface and the separate syslog_unix.go file exist for 89 // Solaris support as implemented by gccgo. On Solaris you cannot 90 // simply open a TCP connection to the syslog daemon. The gccgo 91 // sources have a syslog_solaris.go file that implements unixSyslog to 92 // return a type that satisfies this interface and simply calls the C 93 // library syslog function. 94 type serverConn interface { 95 writeString(p Priority, hostname, tag, s, nl string) error 96 close() error 97 } 98 99 type netConn struct { 100 local bool 101 conn net.Conn 102 } 103 104 // New establishes a new connection to the system log daemon. Each 105 // write to the returned writer sends a log message with the given 106 // priority (a combination of the syslog facility and severity) and 107 // prefix tag. If tag is empty, the os.Args[0] is used. 108 func New(priority Priority, tag string) (*Writer, error) { 109 return Dial("", "", priority, tag) 110 } 111 112 // Dial establishes a connection to a log daemon by connecting to 113 // address raddr on the specified network. Each write to the returned 114 // writer sends a log message with the facility and severity 115 // (from priority) and tag. If tag is empty, the os.Args[0] is used. 116 // If network is empty, Dial will connect to the local syslog server. 117 // Otherwise, see the documentation for net.Dial for valid values 118 // of network and raddr. 119 func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) { 120 if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG { 121 return nil, errors.New("log/syslog: invalid priority") 122 } 123 124 if tag == "" { 125 tag = os.Args[0] 126 } 127 hostname, _ := os.Hostname() 128 129 w := &Writer{ 130 priority: priority, 131 tag: tag, 132 hostname: hostname, 133 network: network, 134 raddr: raddr, 135 } 136 137 w.mu.Lock() 138 defer w.mu.Unlock() 139 140 err := w.connect() 141 if err != nil { 142 return nil, err 143 } 144 return w, err 145 } 146 147 // connect makes a connection to the syslog server. 148 // It must be called with w.mu held. 149 func (w *Writer) connect() (err error) { 150 if w.conn != nil { 151 // ignore err from close, it makes sense to continue anyway 152 w.conn.close() 153 w.conn = nil 154 } 155 156 if w.network == "" { 157 w.conn, err = unixSyslog() 158 if w.hostname == "" { 159 w.hostname = "localhost" 160 } 161 } else { 162 var c net.Conn 163 c, err = net.Dial(w.network, w.raddr) 164 if err == nil { 165 w.conn = &netConn{ 166 conn: c, 167 local: w.network == "unixgram" || w.network == "unix", 168 } 169 if w.hostname == "" { 170 w.hostname = c.LocalAddr().String() 171 } 172 } 173 } 174 return 175 } 176 177 // Write sends a log message to the syslog daemon. 178 func (w *Writer) Write(b []byte) (int, error) { 179 return w.writeAndRetry(w.priority, string(b)) 180 } 181 182 // Close closes a connection to the syslog daemon. 183 func (w *Writer) Close() error { 184 w.mu.Lock() 185 defer w.mu.Unlock() 186 187 if w.conn != nil { 188 err := w.conn.close() 189 w.conn = nil 190 return err 191 } 192 return nil 193 } 194 195 // Emerg logs a message with severity LOG_EMERG, ignoring the severity 196 // passed to New. 197 func (w *Writer) Emerg(m string) error { 198 _, err := w.writeAndRetry(LOG_EMERG, m) 199 return err 200 } 201 202 // Alert logs a message with severity LOG_ALERT, ignoring the severity 203 // passed to New. 204 func (w *Writer) Alert(m string) error { 205 _, err := w.writeAndRetry(LOG_ALERT, m) 206 return err 207 } 208 209 // Crit logs a message with severity LOG_CRIT, ignoring the severity 210 // passed to New. 211 func (w *Writer) Crit(m string) error { 212 _, err := w.writeAndRetry(LOG_CRIT, m) 213 return err 214 } 215 216 // Err logs a message with severity LOG_ERR, ignoring the severity 217 // passed to New. 218 func (w *Writer) Err(m string) error { 219 _, err := w.writeAndRetry(LOG_ERR, m) 220 return err 221 } 222 223 // Warning logs a message with severity LOG_WARNING, ignoring the 224 // severity passed to New. 225 func (w *Writer) Warning(m string) error { 226 _, err := w.writeAndRetry(LOG_WARNING, m) 227 return err 228 } 229 230 // Notice logs a message with severity LOG_NOTICE, ignoring the 231 // severity passed to New. 232 func (w *Writer) Notice(m string) error { 233 _, err := w.writeAndRetry(LOG_NOTICE, m) 234 return err 235 } 236 237 // Info logs a message with severity LOG_INFO, ignoring the severity 238 // passed to New. 239 func (w *Writer) Info(m string) error { 240 _, err := w.writeAndRetry(LOG_INFO, m) 241 return err 242 } 243 244 // Debug logs a message with severity LOG_DEBUG, ignoring the severity 245 // passed to New. 246 func (w *Writer) Debug(m string) error { 247 _, err := w.writeAndRetry(LOG_DEBUG, m) 248 return err 249 } 250 251 func (w *Writer) writeAndRetry(p Priority, s string) (int, error) { 252 pr := (w.priority & facilityMask) | (p & severityMask) 253 254 w.mu.Lock() 255 defer w.mu.Unlock() 256 257 if w.conn != nil { 258 if n, err := w.write(pr, s); err == nil { 259 return n, err 260 } 261 } 262 if err := w.connect(); err != nil { 263 return 0, err 264 } 265 return w.write(pr, s) 266 } 267 268 // write generates and writes a syslog formatted string. The 269 // format is as follows: <PRI>TIMESTAMP HOSTNAME TAG[PID]: MSG 270 func (w *Writer) write(p Priority, msg string) (int, error) { 271 // ensure it ends in a \n 272 nl := "" 273 if !strings.HasSuffix(msg, "\n") { 274 nl = "\n" 275 } 276 277 err := w.conn.writeString(p, w.hostname, w.tag, msg, nl) 278 if err != nil { 279 return 0, err 280 } 281 // Note: return the length of the input, not the number of 282 // bytes printed by Fprintf, because this must behave like 283 // an io.Writer. 284 return len(msg), nil 285 } 286 287 func (n *netConn) writeString(p Priority, hostname, tag, msg, nl string) error { 288 if n.local { 289 // Compared to the network form below, the changes are: 290 // 1. Use time.Stamp instead of time.RFC3339. 291 // 2. Drop the hostname field from the Fprintf. 292 timestamp := time.Now().Format(time.Stamp) 293 _, err := fmt.Fprintf(n.conn, "<%d>%s %s[%d]: %s%s", 294 p, timestamp, 295 tag, os.Getpid(), msg, nl) 296 return err 297 } 298 timestamp := time.Now().Format(time.RFC3339) 299 _, err := fmt.Fprintf(n.conn, "<%d>%s %s %s[%d]: %s%s", 300 p, timestamp, hostname, 301 tag, os.Getpid(), msg, nl) 302 return err 303 } 304 305 func (n *netConn) close() error { 306 return n.conn.Close() 307 } 308 309 // NewLogger creates a log.Logger whose output is written to the 310 // system log service with the specified priority, a combination of 311 // the syslog facility and severity. The logFlag argument is the flag 312 // set passed through to log.New to create the Logger. 313 func NewLogger(p Priority, logFlag int) (*log.Logger, error) { 314 s, err := New(p, "") 315 if err != nil { 316 return nil, err 317 } 318 return log.New(s, "", logFlag), nil 319 }