...

Source file src/log/syslog/syslog.go

Documentation: log/syslog

		 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  }
	 320  

View as plain text