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)