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