github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/log/syslog/syslog.go (about)

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