...
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 provides a simple interface to the system log
     8	// service. It can send messages to the syslog daemon using UNIX
     9	// domain sockets, UDP or TCP.
    10	//
    11	// Only one call to Dial is necessary. On write failures,
    12	// the syslog client will attempt to reconnect to the server
    13	// and write again.
    14	package syslog
    15	
    16	import (
    17		"errors"
    18		"fmt"
    19		"log"
    20		"net"
    21		"os"
    22		"strings"
    23		"sync"
    24		"time"
    25	)
    26	
    27	// The Priority is a combination of the syslog facility and
    28	// severity. For example, LOG_ALERT | LOG_FTP sends an alert severity
    29	// message from the FTP facility. The default severity is LOG_EMERG;
    30	// the default facility is LOG_KERN.
    31	type Priority int
    32	
    33	const severityMask = 0x07
    34	const facilityMask = 0xf8
    35	
    36	const (
    37		// Severity.
    38	
    39		// From /usr/include/sys/syslog.h.
    40		// These are the same on Linux, BSD, and OS X.
    41		LOG_EMERG Priority = iota
    42		LOG_ALERT
    43		LOG_CRIT
    44		LOG_ERR
    45		LOG_WARNING
    46		LOG_NOTICE
    47		LOG_INFO
    48		LOG_DEBUG
    49	)
    50	
    51	const (
    52		// Facility.
    53	
    54		// From /usr/include/sys/syslog.h.
    55		// These are the same up to LOG_FTP on Linux, BSD, and OS X.
    56		LOG_KERN Priority = iota << 3
    57		LOG_USER
    58		LOG_MAIL
    59		LOG_DAEMON
    60		LOG_AUTH
    61		LOG_SYSLOG
    62		LOG_LPR
    63		LOG_NEWS
    64		LOG_UUCP
    65		LOG_CRON
    66		LOG_AUTHPRIV
    67		LOG_FTP
    68		_ // unused
    69		_ // unused
    70		_ // unused
    71		_ // unused
    72		LOG_LOCAL0
    73		LOG_LOCAL1
    74		LOG_LOCAL2
    75		LOG_LOCAL3
    76		LOG_LOCAL4
    77		LOG_LOCAL5
    78		LOG_LOCAL6
    79		LOG_LOCAL7
    80	)
    81	
    82	// A Writer is a connection to a syslog server.
    83	type Writer struct {
    84		priority Priority
    85		tag      string
    86		hostname string
    87		network  string
    88		raddr    string
    89	
    90		mu   sync.Mutex // guards conn
    91		conn serverConn
    92	}
    93	
    94	// This interface and the separate syslog_unix.go file exist for
    95	// Solaris support as implemented by gccgo.  On Solaris you can not
    96	// simply open a TCP connection to the syslog daemon.  The gccgo
    97	// sources have a syslog_solaris.go file that implements unixSyslog to
    98	// return a type that satisfies this interface and simply calls the C
    99	// library syslog function.
   100	type serverConn interface {
   101		writeString(p Priority, hostname, tag, s, nl string) error
   102		close() error
   103	}
   104	
   105	type netConn struct {
   106		local bool
   107		conn  net.Conn
   108	}
   109	
   110	// New establishes a new connection to the system log daemon.  Each
   111	// write to the returned writer sends a log message with the given
   112	// priority and prefix.
   113	func New(priority Priority, tag string) (w *Writer, err error) {
   114		return Dial("", "", priority, tag)
   115	}
   116	
   117	// Dial establishes a connection to a log daemon by connecting to
   118	// address raddr on the specified network.  Each write to the returned
   119	// writer sends a log message with the given facility, severity and
   120	// tag.
   121	// If network is empty, Dial will connect to the local syslog server.
   122	func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
   123		if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG {
   124			return nil, errors.New("log/syslog: invalid priority")
   125		}
   126	
   127		if tag == "" {
   128			tag = os.Args[0]
   129		}
   130		hostname, _ := os.Hostname()
   131	
   132		w := &Writer{
   133			priority: priority,
   134			tag:      tag,
   135			hostname: hostname,
   136			network:  network,
   137			raddr:    raddr,
   138		}
   139	
   140		w.mu.Lock()
   141		defer w.mu.Unlock()
   142	
   143		err := w.connect()
   144		if err != nil {
   145			return nil, err
   146		}
   147		return w, err
   148	}
   149	
   150	// connect makes a connection to the syslog server.
   151	// It must be called with w.mu held.
   152	func (w *Writer) connect() (err error) {
   153		if w.conn != nil {
   154			// ignore err from close, it makes sense to continue anyway
   155			w.conn.close()
   156			w.conn = nil
   157		}
   158	
   159		if w.network == "" {
   160			w.conn, err = unixSyslog()
   161			if w.hostname == "" {
   162				w.hostname = "localhost"
   163			}
   164		} else {
   165			var c net.Conn
   166			c, err = net.Dial(w.network, w.raddr)
   167			if err == nil {
   168				w.conn = &netConn{conn: c}
   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) (err 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) (err 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) (err 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) (err 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) (err 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) (err 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) (err 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) (err 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
   310	// the system log service with the specified priority. The logFlag
   311	// argument is the flag set passed through to log.New to create
   312	// 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