...
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 cannot
    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) (*Writer, 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	// Otherwise, see the documentation for net.Dial for valid values
   116	// of network and raddr.
   117	func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
   118		if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG {
   119			return nil, errors.New("log/syslog: invalid priority")
   120		}
   121	
   122		if tag == "" {
   123			tag = os.Args[0]
   124		}
   125		hostname, _ := os.Hostname()
   126	
   127		w := &Writer{
   128			priority: priority,
   129			tag:      tag,
   130			hostname: hostname,
   131			network:  network,
   132			raddr:    raddr,
   133		}
   134	
   135		w.mu.Lock()
   136		defer w.mu.Unlock()
   137	
   138		err := w.connect()
   139		if err != nil {
   140			return nil, err
   141		}
   142		return w, err
   143	}
   144	
   145	// connect makes a connection to the syslog server.
   146	// It must be called with w.mu held.
   147	func (w *Writer) connect() (err error) {
   148		if w.conn != nil {
   149			// ignore err from close, it makes sense to continue anyway
   150			w.conn.close()
   151			w.conn = nil
   152		}
   153	
   154		if w.network == "" {
   155			w.conn, err = unixSyslog()
   156			if w.hostname == "" {
   157				w.hostname = "localhost"
   158			}
   159		} else {
   160			var c net.Conn
   161			c, err = net.Dial(w.network, w.raddr)
   162			if err == nil {
   163				w.conn = &netConn{conn: c}
   164				if w.hostname == "" {
   165					w.hostname = c.LocalAddr().String()
   166				}
   167			}
   168		}
   169		return
   170	}
   171	
   172	// Write sends a log message to the syslog daemon.
   173	func (w *Writer) Write(b []byte) (int, error) {
   174		return w.writeAndRetry(w.priority, string(b))
   175	}
   176	
   177	// Close closes a connection to the syslog daemon.
   178	func (w *Writer) Close() error {
   179		w.mu.Lock()
   180		defer w.mu.Unlock()
   181	
   182		if w.conn != nil {
   183			err := w.conn.close()
   184			w.conn = nil
   185			return err
   186		}
   187		return nil
   188	}
   189	
   190	// Emerg logs a message with severity LOG_EMERG, ignoring the severity
   191	// passed to New.
   192	func (w *Writer) Emerg(m string) error {
   193		_, err := w.writeAndRetry(LOG_EMERG, m)
   194		return err
   195	}
   196	
   197	// Alert logs a message with severity LOG_ALERT, ignoring the severity
   198	// passed to New.
   199	func (w *Writer) Alert(m string) error {
   200		_, err := w.writeAndRetry(LOG_ALERT, m)
   201		return err
   202	}
   203	
   204	// Crit logs a message with severity LOG_CRIT, ignoring the severity
   205	// passed to New.
   206	func (w *Writer) Crit(m string) error {
   207		_, err := w.writeAndRetry(LOG_CRIT, m)
   208		return err
   209	}
   210	
   211	// Err logs a message with severity LOG_ERR, ignoring the severity
   212	// passed to New.
   213	func (w *Writer) Err(m string) error {
   214		_, err := w.writeAndRetry(LOG_ERR, m)
   215		return err
   216	}
   217	
   218	// Warning logs a message with severity LOG_WARNING, ignoring the
   219	// severity passed to New.
   220	func (w *Writer) Warning(m string) error {
   221		_, err := w.writeAndRetry(LOG_WARNING, m)
   222		return err
   223	}
   224	
   225	// Notice logs a message with severity LOG_NOTICE, ignoring the
   226	// severity passed to New.
   227	func (w *Writer) Notice(m string) error {
   228		_, err := w.writeAndRetry(LOG_NOTICE, m)
   229		return err
   230	}
   231	
   232	// Info logs a message with severity LOG_INFO, ignoring the severity
   233	// passed to New.
   234	func (w *Writer) Info(m string) error {
   235		_, err := w.writeAndRetry(LOG_INFO, m)
   236		return err
   237	}
   238	
   239	// Debug logs a message with severity LOG_DEBUG, ignoring the severity
   240	// passed to New.
   241	func (w *Writer) Debug(m string) error {
   242		_, err := w.writeAndRetry(LOG_DEBUG, m)
   243		return err
   244	}
   245	
   246	func (w *Writer) writeAndRetry(p Priority, s string) (int, error) {
   247		pr := (w.priority & facilityMask) | (p & severityMask)
   248	
   249		w.mu.Lock()
   250		defer w.mu.Unlock()
   251	
   252		if w.conn != nil {
   253			if n, err := w.write(pr, s); err == nil {
   254				return n, err
   255			}
   256		}
   257		if err := w.connect(); err != nil {
   258			return 0, err
   259		}
   260		return w.write(pr, s)
   261	}
   262	
   263	// write generates and writes a syslog formatted string. The
   264	// format is as follows: <PRI>TIMESTAMP HOSTNAME TAG[PID]: MSG
   265	func (w *Writer) write(p Priority, msg string) (int, error) {
   266		// ensure it ends in a \n
   267		nl := ""
   268		if !strings.HasSuffix(msg, "\n") {
   269			nl = "\n"
   270		}
   271	
   272		err := w.conn.writeString(p, w.hostname, w.tag, msg, nl)
   273		if err != nil {
   274			return 0, err
   275		}
   276		// Note: return the length of the input, not the number of
   277		// bytes printed by Fprintf, because this must behave like
   278		// an io.Writer.
   279		return len(msg), nil
   280	}
   281	
   282	func (n *netConn) writeString(p Priority, hostname, tag, msg, nl string) error {
   283		if n.local {
   284			// Compared to the network form below, the changes are:
   285			//	1. Use time.Stamp instead of time.RFC3339.
   286			//	2. Drop the hostname field from the Fprintf.
   287			timestamp := time.Now().Format(time.Stamp)
   288			_, err := fmt.Fprintf(n.conn, "<%d>%s %s[%d]: %s%s",
   289				p, timestamp,
   290				tag, os.Getpid(), msg, nl)
   291			return err
   292		}
   293		timestamp := time.Now().Format(time.RFC3339)
   294		_, err := fmt.Fprintf(n.conn, "<%d>%s %s %s[%d]: %s%s",
   295			p, timestamp, hostname,
   296			tag, os.Getpid(), msg, nl)
   297		return err
   298	}
   299	
   300	func (n *netConn) close() error {
   301		return n.conn.Close()
   302	}
   303	
   304	// NewLogger creates a log.Logger whose output is written to
   305	// the system log service with the specified priority. The logFlag
   306	// argument is the flag set passed through to log.New to create
   307	// the Logger.
   308	func NewLogger(p Priority, logFlag int) (*log.Logger, error) {
   309		s, err := New(p, "")
   310		if err != nil {
   311			return nil, err
   312		}
   313		return log.New(s, "", logFlag), nil
   314	}
   315	

View as plain text