/
syslog.go
163 lines (139 loc) · 3.34 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
152
153
154
155
156
157
158
159
160
161
162
163
package log5go
import (
"fmt"
"net"
"os"
"sync"
"time"
)
var socketTypes = []string{"unixgram", "unix"}
var socketLocations = []string{"/dev/log", "/var/run/syslog", "/var/run/log"}
// SyslogPriority represents a syslog priority level
type SyslogPriority int
// syslog severity levels
const (
SyslogEmergency SyslogPriority = iota
SyslogAlert
SyslogCritical
SyslogError
SyslogWarning
SyslogNotice
SyslogInfo
SyslogDebug
)
// syslog facility levels
const (
SyslogKernel SyslogPriority = iota << 3
SyslogUser
SyslogMail
SyslogDaemon
SyslogAuth
SyslogSyslog
SyslogLpr
SyslogNews
SyslogUUCP
SyslogClock
SyslogAuthpriv
SyslogFTP
SyslogNTP
SyslogLogAudit
SyslogLogAlert
SyslogCron
SyslogLocal0
SyslogLocal1
SyslogLocal2
SyslogLocal3
SyslogLocal4
SyslogLocal5
SyslogLocal6
SyslogLocal7
)
type syslogAppender struct {
sync.Mutex
conn net.Conn
facility SyslogPriority
tag string
hostname string
}
func (a *syslogAppender) Append(msg *[]byte, level LogLevel, tstamp time.Time) error {
a.Lock()
defer a.Unlock()
TerminateMessageWithNewline(msg)
// sanity check
if a.conn == nil {
return fmt.Errorf("connection is not established")
}
pri := calculatePriority(a.facility, level)
hostname := a.calculateHostname()
_, err := fmt.Fprintf(a.conn, "<%d>1 %s %s %s[%d]: %s", pri, tstamp.Format(time.RFC3339Nano), hostname, a.tag, os.Getpid(), *msg)
return err
}
func (a *syslogAppender) calculateHostname() string {
if a.hostname != "" {
return a.hostname
}
// try to get local IP
addrs, err := net.InterfaceAddrs()
if err != nil {
// unlikely to happen, but nothing we can do
}
for _, address := range addrs {
// check the address type and if it is not a loopback the display it
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
a.hostname = ipnet.IP.String()
return a.hostname
}
}
}
// try to use hostname if we can't get an IP addr
host, err := os.Hostname()
if err == nil {
a.hostname = host
return a.hostname
}
// everything failed. just put something in a.addr so we don't call method over and over
a.hostname = "unknown-host"
return a.hostname
}
type syslogFormatter struct {
formatter *StringFormatter
}
func newSyslogFormatter(lines bool) Formatter {
var inner *StringFormatter
if lines {
inner = NewStringFormatter("%p (%c:%n): %m")
} else {
inner = NewStringFormatter("%p: %m")
}
return &syslogFormatter{formatter: inner}
}
func (f *syslogFormatter) Format(tstamp time.Time, level LogLevel, prefix, caller string, line uint, msg string, data Data, out *[]byte) {
f.formatter.Format(tstamp, level, prefix, caller, line, msg, data, out)
}
func (f *syslogFormatter) SetTimeFormat(timeFormat string) {
// NOOP
}
func (f *syslogFormatter) SetLines(lines bool) {
f.formatter.SetLines(lines)
}
func calculatePriority(facility SyslogPriority, level LogLevel) SyslogPriority {
switch {
case level <= LogDebug:
return facility | SyslogDebug
case level <= LogInfo:
return facility | SyslogInfo
case level <= LogNotice:
return facility | SyslogNotice
case level <= LogWarn:
return facility | SyslogWarning
case level <= LogError:
return facility | SyslogError
case level <= LogCritical:
return facility | SyslogCritical
case level <= LogAlert:
return facility | SyslogAlert
default:
return facility | SyslogEmergency
}
}