Run Format

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

View as plain text