...
Run Format

Source file src/log/syslog/syslog.go

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

View as plain text