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

View as plain text