1 package log
2
3 import (
4 "bytes"
5 "fmt"
6 "log/syslog"
7 "net"
8 "os"
9 "strings"
10 "sync"
11 "testing"
12 "time"
13
14 "github.com/jmhodges/clock"
15 "github.com/letsencrypt/boulder/test"
16 )
17
18 const stdoutLevel = 7
19 const syslogLevel = 7
20
21 func setup(t *testing.T) *impl {
22
23
24 writer, err := syslog.Dial("udp", "127.0.0.1:65530", syslog.LOG_INFO|syslog.LOG_LOCAL0, "")
25 test.AssertNotError(t, err, "Could not construct syslog object")
26
27 logger, err := New(writer, stdoutLevel, syslogLevel)
28 test.AssertNotError(t, err, "Could not construct syslog object")
29 impl, ok := logger.(*impl)
30 if !ok {
31 t.Fatalf("Wrong type returned from New: %T", logger)
32 }
33 return impl
34 }
35
36 func TestConstruction(t *testing.T) {
37 t.Parallel()
38 _ = setup(t)
39 }
40
41 func TestSingleton(t *testing.T) {
42 t.Parallel()
43 log1 := Get()
44 test.AssertNotNil(t, log1, "Logger shouldn't be nil")
45
46 log2 := Get()
47 test.AssertEquals(t, log1, log2)
48
49 audit := setup(t)
50
51
52 err := Set(audit)
53 test.AssertError(t, err, "Can't re-set")
54
55
56 log4 := Get()
57
58
59 test.AssertNotEquals(t, log4, audit)
60
61
62 test.AssertEquals(t, log4, log2)
63 test.AssertEquals(t, log4, log1)
64 }
65
66 func TestConstructionNil(t *testing.T) {
67 t.Parallel()
68 _, err := New(nil, stdoutLevel, syslogLevel)
69 test.AssertError(t, err, "Nil shouldn't be permitted.")
70 }
71
72 func TestEmit(t *testing.T) {
73 t.Parallel()
74 log := setup(t)
75
76 log.AuditInfo("test message")
77 }
78
79 func TestEmitEmpty(t *testing.T) {
80 t.Parallel()
81 log := setup(t)
82
83 log.AuditInfo("")
84 }
85
86 func TestStdoutLogger(t *testing.T) {
87 stdout := bytes.NewBuffer(nil)
88 stderr := bytes.NewBuffer(nil)
89 logger := &impl{
90 &stdoutWriter{
91 prefix: "prefix ",
92 level: 7,
93 clkFormat: "2006-01-02",
94 clk: clock.NewFake(),
95 stdout: stdout,
96 stderr: stderr,
97 },
98 }
99
100 logger.AuditErr("Error Audit")
101 logger.Warning("Warning log")
102 logger.Info("Info log")
103
104 test.AssertEquals(t, stdout.String(), "1970-01-01 prefix 6 log.test pcbo7wk Info log\n")
105 test.AssertEquals(t, stderr.String(), "1970-01-01 prefix 3 log.test 46_ghQg [AUDIT] Error Audit\n1970-01-01 prefix 4 log.test 97r2xAw Warning log\n")
106 }
107
108 func TestSyslogMethods(t *testing.T) {
109 t.Parallel()
110 impl := setup(t)
111
112 impl.AuditInfo("audit-logger_test.go: audit-info")
113 impl.AuditErr("audit-logger_test.go: audit-err")
114 impl.Debug("audit-logger_test.go: debug")
115 impl.Err("audit-logger_test.go: err")
116 impl.Info("audit-logger_test.go: info")
117 impl.Warning("audit-logger_test.go: warning")
118 impl.AuditInfof("audit-logger_test.go: %s", "audit-info")
119 impl.AuditErrf("audit-logger_test.go: %s", "audit-err")
120 impl.Debugf("audit-logger_test.go: %s", "debug")
121 impl.Errf("audit-logger_test.go: %s", "err")
122 impl.Infof("audit-logger_test.go: %s", "info")
123 impl.Warningf("audit-logger_test.go: %s", "warning")
124 }
125
126 func TestAuditObject(t *testing.T) {
127 t.Parallel()
128
129 log := NewMock()
130
131
132 log.AuditObject("Prefix", "String")
133 if len(log.GetAllMatching("[AUDIT]")) != 1 {
134 t.Errorf("Failed to audit log simple object")
135 }
136
137
138 log.Clear()
139 log.AuditObject("Prefix", t)
140 if len(log.GetAllMatching("[AUDIT]")) != 1 {
141 t.Errorf("Failed to audit log system object")
142 }
143
144
145 log.Clear()
146 type validObj struct {
147 A string
148 B string
149 }
150 var valid = validObj{A: "B", B: "C"}
151 log.AuditObject("Prefix", valid)
152 if len(log.GetAllMatching("[AUDIT]")) != 1 {
153 t.Errorf("Failed to audit log complex object")
154 }
155
156
157 log.Clear()
158 type invalidObj struct {
159 A chan string
160 }
161
162 var invalid = invalidObj{A: make(chan string)}
163 log.AuditObject("Prefix", invalid)
164 if len(log.GetAllMatching("[AUDIT]")) != 1 {
165 t.Errorf("Failed to audit log unserializable object %v", log.GetAllMatching("[AUDIT]"))
166 }
167 }
168
169 func TestTransmission(t *testing.T) {
170 t.Parallel()
171
172 l, err := newUDPListener("127.0.0.1:0")
173 test.AssertNotError(t, err, "Failed to open log server")
174 defer func() {
175 err = l.Close()
176 test.AssertNotError(t, err, "listener.Close returned error")
177 }()
178
179 fmt.Printf("Going to %s\n", l.LocalAddr().String())
180 writer, err := syslog.Dial("udp", l.LocalAddr().String(), syslog.LOG_INFO|syslog.LOG_LOCAL0, "")
181 test.AssertNotError(t, err, "Failed to find connect to log server")
182
183 impl, err := New(writer, stdoutLevel, syslogLevel)
184 test.AssertNotError(t, err, "Failed to construct audit logger")
185
186 data := make([]byte, 128)
187
188 impl.AuditInfo("audit-logger_test.go: audit-info")
189 _, _, err = l.ReadFrom(data)
190 test.AssertNotError(t, err, "Failed to find packet")
191
192 impl.AuditErr("audit-logger_test.go: audit-err")
193 _, _, err = l.ReadFrom(data)
194 test.AssertNotError(t, err, "Failed to find packet")
195
196 impl.Debug("audit-logger_test.go: debug")
197 _, _, err = l.ReadFrom(data)
198 test.AssertNotError(t, err, "Failed to find packet")
199
200 impl.Err("audit-logger_test.go: err")
201 _, _, err = l.ReadFrom(data)
202 test.AssertNotError(t, err, "Failed to find packet")
203
204 impl.Info("audit-logger_test.go: info")
205 _, _, err = l.ReadFrom(data)
206 test.AssertNotError(t, err, "Failed to find packet")
207
208 impl.Warning("audit-logger_test.go: warning")
209 _, _, err = l.ReadFrom(data)
210 test.AssertNotError(t, err, "Failed to find packet")
211
212 impl.AuditInfof("audit-logger_test.go: %s", "audit-info")
213 _, _, err = l.ReadFrom(data)
214 test.AssertNotError(t, err, "Failed to find packet")
215
216 impl.AuditErrf("audit-logger_test.go: %s", "audit-err")
217 _, _, err = l.ReadFrom(data)
218 test.AssertNotError(t, err, "Failed to find packet")
219
220 impl.Debugf("audit-logger_test.go: %s", "debug")
221 _, _, err = l.ReadFrom(data)
222 test.AssertNotError(t, err, "Failed to find packet")
223
224 impl.Errf("audit-logger_test.go: %s", "err")
225 _, _, err = l.ReadFrom(data)
226 test.AssertNotError(t, err, "Failed to find packet")
227
228 impl.Infof("audit-logger_test.go: %s", "info")
229 _, _, err = l.ReadFrom(data)
230 test.AssertNotError(t, err, "Failed to find packet")
231
232 impl.Warningf("audit-logger_test.go: %s", "warning")
233 _, _, err = l.ReadFrom(data)
234 test.AssertNotError(t, err, "Failed to find packet")
235 }
236
237 func TestSyslogLevels(t *testing.T) {
238 t.Parallel()
239
240 l, err := newUDPListener("127.0.0.1:0")
241 test.AssertNotError(t, err, "Failed to open log server")
242 defer func() {
243 err = l.Close()
244 test.AssertNotError(t, err, "listener.Close returned error")
245 }()
246
247 fmt.Printf("Going to %s\n", l.LocalAddr().String())
248 writer, err := syslog.Dial("udp", l.LocalAddr().String(), syslog.LOG_INFO|syslog.LOG_LOCAL0, "")
249 test.AssertNotError(t, err, "Failed to find connect to log server")
250
251
252 impl, err := New(writer, stdoutLevel, int(syslog.LOG_DEBUG))
253 test.AssertNotError(t, err, "Failed to construct audit logger")
254
255 data := make([]byte, 512)
256
257
258 impl.Debug("log_test.go: debug")
259 _, _, err = l.ReadFrom(data)
260 test.AssertNotError(t, err, "Failed to find packet")
261 test.Assert(t, strings.Contains(string(data), "log_test.go: debug"), "Failed to find log message")
262
263
264 impl, err = New(writer, stdoutLevel, int(syslog.LOG_INFO))
265 test.AssertNotError(t, err, "Failed to construct audit logger")
266
267
268 impl.Debug("log_test.go: debug")
269 n, _, err := l.ReadFrom(data)
270 if n != 0 && err == nil {
271 t.Error("Failed to withhold debug log message")
272 }
273 }
274
275 func newUDPListener(addr string) (*net.UDPConn, error) {
276 l, err := net.ListenPacket("udp", addr)
277 if err != nil {
278 return nil, err
279 }
280 err = l.SetDeadline(time.Now().Add(100 * time.Millisecond))
281 if err != nil {
282 return nil, err
283 }
284 err = l.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
285 if err != nil {
286 return nil, err
287 }
288 err = l.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
289 if err != nil {
290 return nil, err
291 }
292 return l.(*net.UDPConn), nil
293 }
294
295
296
297 func TestStdoutFailure(t *testing.T) {
298
299 saved := os.Stdout
300
301
302 _, w, err := os.Pipe()
303 test.AssertNotError(t, err, "failed to create pipe")
304 os.Stdout = w
305
306
307 log := setup(t)
308
309
310
311 err = os.Stdout.Close()
312 test.AssertNotError(t, err, "failed to close stdout")
313
314
315
316
317 defer func() {
318 if recovered := recover(); recovered == nil {
319 t.Errorf("log.AuditInfo with Stdout closed did not panic")
320 }
321
322
323 os.Stdout = saved
324 }()
325
326
327 log.AuditInfo("This should cause a panic, stdout is closed!")
328 }
329
330 func TestLogAtLevelEscapesNewlines(t *testing.T) {
331 var buf bytes.Buffer
332 w := &bothWriter{sync.Mutex{},
333 nil,
334 &stdoutWriter{
335 stdout: &buf,
336 clk: clock.NewFake(),
337 level: 6,
338 },
339 -1,
340 }
341 w.logAtLevel(6, "foo\nbar")
342
343 test.Assert(t, strings.Contains(buf.String(), "foo\\nbar"), "failed to escape newline")
344 }
345
View as plain text