github.com/phuslu/log@v1.0.100/syslog.go (about)

     1  package log
     2  
     3  import (
     4  	"net"
     5  	"strconv"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  // SyslogWriter is an Writer that writes logs to a syslog server..
    11  type SyslogWriter struct {
    12  	// Network specifies network of the syslog server
    13  	Network string
    14  
    15  	// Address specifies address of the syslog server
    16  	Address string
    17  
    18  	// Hostname specifies hostname of the syslog message
    19  	Hostname string
    20  
    21  	// Tag specifies tag of the syslog message
    22  	Tag string
    23  
    24  	// Marker specifies prefix of the syslog message, e.g. `@cee:`
    25  	Marker string
    26  
    27  	// Dial specifies the dial function for creating TCP/TLS connections.
    28  	Dial func(network, addr string) (net.Conn, error)
    29  
    30  	mu    sync.Mutex
    31  	conn  net.Conn
    32  	local bool
    33  }
    34  
    35  // Close closes a connection to the syslog server.
    36  func (w *SyslogWriter) Close() (err error) {
    37  	w.mu.Lock()
    38  	defer w.mu.Unlock()
    39  
    40  	if w.conn != nil {
    41  		err = w.conn.Close()
    42  		w.conn = nil
    43  		return
    44  	}
    45  	return
    46  }
    47  
    48  // connect makes a connection to the syslog server.
    49  func (w *SyslogWriter) connect() (err error) {
    50  	if w.conn != nil {
    51  		w.conn.Close()
    52  		w.conn = nil
    53  	}
    54  
    55  	var dial = w.Dial
    56  	if dial == nil {
    57  		dial = net.Dial
    58  	}
    59  
    60  	w.conn, err = dial(w.Network, w.Address)
    61  	if err != nil {
    62  		return
    63  	}
    64  
    65  	w.local = w.Address != "" && w.Address[0] == '/'
    66  
    67  	if w.Hostname == "" {
    68  		if w.local {
    69  			w.Hostname = hostname
    70  		} else {
    71  			w.Hostname = w.conn.LocalAddr().String()
    72  		}
    73  	}
    74  
    75  	return
    76  }
    77  
    78  // WriteEntry implements Writer, sends logs with priority to the syslog server.
    79  func (w *SyslogWriter) WriteEntry(e *Entry) (n int, err error) {
    80  	if w.conn == nil {
    81  		w.mu.Lock()
    82  		if w.conn == nil {
    83  			err = w.connect()
    84  			if err != nil {
    85  				w.mu.Unlock()
    86  				return
    87  			}
    88  		}
    89  		w.mu.Unlock()
    90  	}
    91  
    92  	// convert level to syslog priority
    93  	var priority byte
    94  	switch e.Level {
    95  	case TraceLevel:
    96  		priority = '7' // LOG_DEBUG
    97  	case DebugLevel:
    98  		priority = '7' // LOG_DEBUG
    99  	case InfoLevel:
   100  		priority = '6' // LOG_INFO
   101  	case WarnLevel:
   102  		priority = '4' // LOG_WARNING
   103  	case ErrorLevel:
   104  		priority = '3' // LOG_ERR
   105  	case FatalLevel:
   106  		priority = '2' // LOG_CRIT
   107  	case PanicLevel:
   108  		priority = '1' // LOG_ALERT
   109  	default:
   110  		priority = '6' // LOG_INFO
   111  	}
   112  
   113  	e1 := epool.Get().(*Entry)
   114  	defer func(entry *Entry) {
   115  		if cap(entry.buf) <= bbcap {
   116  			epool.Put(entry)
   117  		}
   118  	}(e1)
   119  
   120  	// <PRI>TIMESTAMP HOSTNAME TAG[PID]: MSG
   121  	e1.buf = append(e1.buf[:0], '<', priority, '>')
   122  	if w.local {
   123  		// Compared to the network form below, the changes are:
   124  		//	1. Use time.Stamp instead of time.RFC3339.
   125  		//	2. Drop the hostname field.
   126  		e1.buf = timeNow().AppendFormat(e1.buf, time.Stamp)
   127  	} else {
   128  		e1.buf = timeNow().AppendFormat(e1.buf, time.RFC3339)
   129  		e1.buf = append(e1.buf, ' ')
   130  		e1.buf = append(e1.buf, w.Hostname...)
   131  	}
   132  	e1.buf = append(e1.buf, ' ')
   133  	e1.buf = append(e1.buf, w.Tag...)
   134  	e1.buf = append(e1.buf, '[')
   135  	e1.buf = strconv.AppendInt(e1.buf, int64(pid), 10)
   136  	e1.buf = append(e1.buf, ']', ':', ' ')
   137  	e1.buf = append(e1.buf, w.Marker...)
   138  	e1.buf = append(e1.buf, e.buf...)
   139  
   140  	w.mu.Lock()
   141  	defer w.mu.Unlock()
   142  
   143  	if w.conn != nil {
   144  		if n, err := w.conn.Write(e1.buf); err == nil {
   145  			return n, err
   146  		}
   147  	}
   148  	if err := w.connect(); err != nil {
   149  		return 0, err
   150  	}
   151  	return w.conn.Write(e1.buf)
   152  }
   153  
   154  var _ Writer = (*SyslogWriter)(nil)