Merge lp:~chipaca/snappy/different-logger into lp:~snappy-dev/snappy/snappy-moved-to-github
- different-logger
- Merge into snappy-moved-to-github
Proposed by
John Lenton
Status: | Merged |
---|---|
Approved by: | Sergio Schvezov |
Approved revision: | 456 |
Merged at revision: | 459 |
Proposed branch: | lp:~chipaca/snappy/different-logger |
Merge into: | lp:~snappy-dev/snappy/snappy-moved-to-github |
Prerequisite: | lp:~chipaca/snappy/die-LogError-die |
Diff against target: |
1085 lines (+23/-524) 27 files modified
cmd/snappy/cmd_booted.go (+1/-1) cmd/snappy/cmd_build.go (+1/-1) cmd/snappy/cmd_config.go (+1/-1) cmd/snappy/cmd_first_boot.go (+1/-1) cmd/snappy/cmd_hwassign.go (+1/-1) cmd/snappy/cmd_hwinfo.go (+1/-1) cmd/snappy/cmd_hwunassign.go (+1/-1) cmd/snappy/cmd_info.go (+1/-1) cmd/snappy/cmd_install.go (+1/-1) cmd/snappy/cmd_internal_run_hooks.go (+1/-1) cmd/snappy/cmd_internal_unpack.go (+1/-1) cmd/snappy/cmd_list.go (+1/-1) cmd/snappy/cmd_login.go (+1/-1) cmd/snappy/cmd_purge.go (+1/-1) cmd/snappy/cmd_remove.go (+1/-1) cmd/snappy/cmd_rollback.go (+1/-1) cmd/snappy/cmd_search.go (+1/-1) cmd/snappy/cmd_set.go (+1/-1) cmd/snappy/cmd_update.go (+1/-1) cmd/snappy/cmd_versions.go (+1/-1) cmd/snappy/main.go (+1/-1) debian/control (+0/-1) dependencies.tsv (+0/-1) logger/logger.go (+0/-189) logger/logger_test.go (+0/-310) snappy/dbus.go (+1/-1) systemd/systemd.go (+1/-1) |
To merge this branch: | bzr merge lp:~chipaca/snappy/different-logger |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sergio Schvezov | Approve | ||
Review via email: mp+258664@code.launchpad.net |
Commit message
New, simpler logger.
Description of the change
Everything old is new again.
To post a comment you must log in.
- 454. By John Lenton
-
clean up imports, typos
Revision history for this message
John Lenton (chipaca) wrote : | # |
Revision history for this message
John Lenton (chipaca) wrote : | # |
(and for the record, it is my opinion that if a command is not a verb, and thus fits “unable to $verb”, it's a bug :) )
Revision history for this message
Sergio Schvezov (sergiusens) wrote : | # |
Nice and simple, I think we can drop the loggo dep from debian/control as well now, right?
Revision history for this message
John Lenton (chipaca) wrote : | # |
Correct! Will do that now.
- 455. By John Lenton
-
nuke loggo dependencies
- 456. By John Lenton
-
make vet and lint happy
Revision history for this message
Sergio Schvezov (sergiusens) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'cmd/snappy/cmd_booted.go' |
2 | --- cmd/snappy/cmd_booted.go 2015-05-11 15:56:13 +0000 |
3 | +++ cmd/snappy/cmd_booted.go 2015-05-11 15:56:13 +0000 |
4 | @@ -32,7 +32,7 @@ |
5 | "internal", |
6 | &cmdBooted{}) |
7 | if err != nil { |
8 | - logger.LogAndPanic(err) |
9 | + logger.Panicf("unable to booted: %v", err) |
10 | } |
11 | } |
12 | |
13 | |
14 | === modified file 'cmd/snappy/cmd_build.go' |
15 | --- cmd/snappy/cmd_build.go 2015-05-08 13:41:11 +0000 |
16 | +++ cmd/snappy/cmd_build.go 2015-05-11 15:56:13 +0000 |
17 | @@ -38,7 +38,7 @@ |
18 | longBuildHelp, |
19 | &cmdBuild{}) |
20 | if err != nil { |
21 | - logger.LogAndPanic(err) |
22 | + logger.Panicf("unable to build: %v", err) |
23 | } |
24 | |
25 | cmd.Aliases = append(cmd.Aliases, "bu") |
26 | |
27 | === modified file 'cmd/snappy/cmd_config.go' |
28 | --- cmd/snappy/cmd_config.go 2015-05-08 13:41:11 +0000 |
29 | +++ cmd/snappy/cmd_config.go 2015-05-11 15:56:13 +0000 |
30 | @@ -44,7 +44,7 @@ |
31 | longConfigHelp, |
32 | &cmdConfig{}) |
33 | if err != nil { |
34 | - logger.LogAndPanic(err) |
35 | + logger.Panicf("unable to config: %v", err) |
36 | } |
37 | } |
38 | |
39 | |
40 | === modified file 'cmd/snappy/cmd_first_boot.go' |
41 | --- cmd/snappy/cmd_first_boot.go 2015-05-08 13:41:11 +0000 |
42 | +++ cmd/snappy/cmd_first_boot.go 2015-05-11 15:56:13 +0000 |
43 | @@ -32,7 +32,7 @@ |
44 | "internal", |
45 | &cmdInternalFirstBootOemConfig{}) |
46 | if err != nil { |
47 | - logger.LogAndPanic(err) |
48 | + logger.Panicf("unable to first_boot: %v", err) |
49 | } |
50 | } |
51 | |
52 | |
53 | === modified file 'cmd/snappy/cmd_hwassign.go' |
54 | --- cmd/snappy/cmd_hwassign.go 2015-05-08 13:41:11 +0000 |
55 | +++ cmd/snappy/cmd_hwassign.go 2015-05-11 15:56:13 +0000 |
56 | @@ -42,7 +42,7 @@ |
57 | longHWAssignHelp, |
58 | &cmdHWAssign{}) |
59 | if err != nil { |
60 | - logger.LogAndPanic(err) |
61 | + logger.Panicf("unable to hwassign: %v", err) |
62 | } |
63 | } |
64 | |
65 | |
66 | === modified file 'cmd/snappy/cmd_hwinfo.go' |
67 | --- cmd/snappy/cmd_hwinfo.go 2015-05-08 13:41:11 +0000 |
68 | +++ cmd/snappy/cmd_hwinfo.go 2015-05-11 15:56:13 +0000 |
69 | @@ -42,7 +42,7 @@ |
70 | longHWInfoHelp, |
71 | &cmdHWInfo{}) |
72 | if err != nil { |
73 | - logger.LogAndPanic(err) |
74 | + logger.Panicf("unable to hwinfo: %v", err) |
75 | } |
76 | } |
77 | |
78 | |
79 | === modified file 'cmd/snappy/cmd_hwunassign.go' |
80 | --- cmd/snappy/cmd_hwunassign.go 2015-05-08 13:41:11 +0000 |
81 | +++ cmd/snappy/cmd_hwunassign.go 2015-05-11 15:56:13 +0000 |
82 | @@ -42,7 +42,7 @@ |
83 | longHWUnassignHelp, |
84 | &cmdHWUnassign{}) |
85 | if err != nil { |
86 | - logger.LogAndPanic(err) |
87 | + logger.Panicf("unable to hwunassign: %v", err) |
88 | } |
89 | } |
90 | |
91 | |
92 | === modified file 'cmd/snappy/cmd_info.go' |
93 | --- cmd/snappy/cmd_info.go 2015-05-08 13:41:11 +0000 |
94 | +++ cmd/snappy/cmd_info.go 2015-05-11 15:56:13 +0000 |
95 | @@ -48,7 +48,7 @@ |
96 | longInfoHelp, |
97 | &cmdInfo{}) |
98 | if err != nil { |
99 | - logger.LogAndPanic(err) |
100 | + logger.Panicf("unable to info: %v", err) |
101 | } |
102 | } |
103 | |
104 | |
105 | === modified file 'cmd/snappy/cmd_install.go' |
106 | --- cmd/snappy/cmd_install.go 2015-05-08 13:41:11 +0000 |
107 | +++ cmd/snappy/cmd_install.go 2015-05-11 15:56:13 +0000 |
108 | @@ -43,7 +43,7 @@ |
109 | "Install a snap package", |
110 | &cmdInstall{}) |
111 | if err != nil { |
112 | - logger.LogAndPanic(err) |
113 | + logger.Panicf("unable to install: %v", err) |
114 | } |
115 | } |
116 | |
117 | |
118 | === modified file 'cmd/snappy/cmd_internal_run_hooks.go' |
119 | --- cmd/snappy/cmd_internal_run_hooks.go 2015-05-08 13:41:11 +0000 |
120 | +++ cmd/snappy/cmd_internal_run_hooks.go 2015-05-11 15:56:13 +0000 |
121 | @@ -14,7 +14,7 @@ |
122 | "internal", |
123 | &cmdInternalRunHooks{}) |
124 | if err != nil { |
125 | - logger.LogAndPanic(err) |
126 | + logger.Panicf("unable to internal_run_hooks: %v", err) |
127 | } |
128 | } |
129 | |
130 | |
131 | === modified file 'cmd/snappy/cmd_internal_unpack.go' |
132 | --- cmd/snappy/cmd_internal_unpack.go 2015-05-08 13:41:11 +0000 |
133 | +++ cmd/snappy/cmd_internal_unpack.go 2015-05-11 15:56:13 +0000 |
134 | @@ -151,7 +151,7 @@ |
135 | "internal", |
136 | &cmdInternalUnpack{}) |
137 | if err != nil { |
138 | - logger.LogAndPanic(err) |
139 | + logger.Panicf("unable to internal_unpack: %v", err) |
140 | } |
141 | } |
142 | |
143 | |
144 | === modified file 'cmd/snappy/cmd_list.go' |
145 | --- cmd/snappy/cmd_list.go 2015-05-08 13:41:11 +0000 |
146 | +++ cmd/snappy/cmd_list.go 2015-05-11 15:56:13 +0000 |
147 | @@ -49,7 +49,7 @@ |
148 | longListHelp, |
149 | &cmdList{}) |
150 | if err != nil { |
151 | - logger.LogAndPanic(err) |
152 | + logger.Panicf("unable to list: %v", err) |
153 | } |
154 | |
155 | cmd.Aliases = append(cmd.Aliases, "li") |
156 | |
157 | === modified file 'cmd/snappy/cmd_login.go' |
158 | --- cmd/snappy/cmd_login.go 2015-05-08 13:41:11 +0000 |
159 | +++ cmd/snappy/cmd_login.go 2015-05-11 15:56:13 +0000 |
160 | @@ -44,7 +44,7 @@ |
161 | longLoginHelp, |
162 | &cmdLogin{}) |
163 | if err != nil { |
164 | - logger.LogAndPanic(err) |
165 | + logger.Panicf("unable to login: %v", err) |
166 | } |
167 | } |
168 | |
169 | |
170 | === modified file 'cmd/snappy/cmd_purge.go' |
171 | --- cmd/snappy/cmd_purge.go 2015-05-08 13:41:11 +0000 |
172 | +++ cmd/snappy/cmd_purge.go 2015-05-11 15:56:13 +0000 |
173 | @@ -41,7 +41,7 @@ |
174 | longPurgeHelp, |
175 | &cmdPurge{}) |
176 | if err != nil { |
177 | - logger.LogAndPanic(err) |
178 | + logger.Panicf("unable to purge: %v", err) |
179 | } |
180 | } |
181 | |
182 | |
183 | === modified file 'cmd/snappy/cmd_remove.go' |
184 | --- cmd/snappy/cmd_remove.go 2015-05-08 13:41:11 +0000 |
185 | +++ cmd/snappy/cmd_remove.go 2015-05-11 15:56:13 +0000 |
186 | @@ -36,7 +36,7 @@ |
187 | "Remove a snapp part", |
188 | &cmdRemove{}) |
189 | if err != nil { |
190 | - logger.LogAndPanic(err) |
191 | + logger.Panicf("unable to remove: %v", err) |
192 | } |
193 | } |
194 | |
195 | |
196 | === modified file 'cmd/snappy/cmd_rollback.go' |
197 | --- cmd/snappy/cmd_rollback.go 2015-05-08 13:41:11 +0000 |
198 | +++ cmd/snappy/cmd_rollback.go 2015-05-11 15:56:13 +0000 |
199 | @@ -44,7 +44,7 @@ |
200 | longRollbackHelp, |
201 | &cmdRollback{}) |
202 | if err != nil { |
203 | - logger.LogAndPanic(err) |
204 | + logger.Panicf("unable to rollback: %v", err) |
205 | } |
206 | } |
207 | |
208 | |
209 | === modified file 'cmd/snappy/cmd_search.go' |
210 | --- cmd/snappy/cmd_search.go 2015-05-08 13:41:11 +0000 |
211 | +++ cmd/snappy/cmd_search.go 2015-05-11 15:56:13 +0000 |
212 | @@ -36,7 +36,7 @@ |
213 | "Query the store for available packages", |
214 | &cmdSearch{}) |
215 | if err != nil { |
216 | - logger.LogAndPanic(err) |
217 | + logger.Panicf("unable to search: %v", err) |
218 | } |
219 | |
220 | cmd.Aliases = append(cmd.Aliases, "se") |
221 | |
222 | === modified file 'cmd/snappy/cmd_set.go' |
223 | --- cmd/snappy/cmd_set.go 2015-05-08 13:41:11 +0000 |
224 | +++ cmd/snappy/cmd_set.go 2015-05-11 15:56:13 +0000 |
225 | @@ -44,7 +44,7 @@ |
226 | setHelp, |
227 | &cmdSet{}) |
228 | if err != nil { |
229 | - logger.LogAndPanic(err) |
230 | + logger.Panicf("unable to set: %v", err) |
231 | } |
232 | } |
233 | |
234 | |
235 | === modified file 'cmd/snappy/cmd_update.go' |
236 | --- cmd/snappy/cmd_update.go 2015-05-08 13:41:11 +0000 |
237 | +++ cmd/snappy/cmd_update.go 2015-05-11 15:56:13 +0000 |
238 | @@ -40,7 +40,7 @@ |
239 | "Ensures system is running with latest parts", |
240 | &cmdUpdate{}) |
241 | if err != nil { |
242 | - logger.LogAndPanic(err) |
243 | + logger.Panicf("unable to update: %v", err) |
244 | } |
245 | } |
246 | |
247 | |
248 | === modified file 'cmd/snappy/cmd_versions.go' |
249 | --- cmd/snappy/cmd_versions.go 2015-05-08 13:41:11 +0000 |
250 | +++ cmd/snappy/cmd_versions.go 2015-05-11 15:56:13 +0000 |
251 | @@ -36,7 +36,7 @@ |
252 | longVersionsHelp, |
253 | &cmdVersions{}) |
254 | if err != nil { |
255 | - logger.LogAndPanic(err) |
256 | + logger.Panicf("unable to versions: %v", err) |
257 | } |
258 | } |
259 | |
260 | |
261 | === modified file 'cmd/snappy/main.go' |
262 | --- cmd/snappy/main.go 2015-03-26 13:02:07 +0000 |
263 | +++ cmd/snappy/main.go 2015-05-11 15:56:13 +0000 |
264 | @@ -42,7 +42,7 @@ |
265 | var parser = flags.NewParser(&optionsData, flags.Default) |
266 | |
267 | func init() { |
268 | - err := logger.ActivateLogger() |
269 | + err := logger.SimpleSetup() |
270 | if err != nil { |
271 | fmt.Fprintf(os.Stderr, "WARNING: failed to activate logging: %s\n", err) |
272 | } |
273 | |
274 | === modified file 'debian/control' |
275 | --- debian/control 2015-04-21 22:02:02 +0000 |
276 | +++ debian/control 2015-05-11 15:56:13 +0000 |
277 | @@ -13,7 +13,6 @@ |
278 | golang-go.crypto-dev, |
279 | golang-gocheck-dev, |
280 | golang-goconfigparser-dev, |
281 | - golang-juju-loggo-dev, |
282 | golang-pb-dev, |
283 | golang-yaml.v2-dev |
284 | Standards-Version: 3.9.6 |
285 | |
286 | === modified file 'dependencies.tsv' |
287 | --- dependencies.tsv 2015-03-19 09:33:48 +0000 |
288 | +++ dependencies.tsv 2015-05-11 15:56:13 +0000 |
289 | @@ -2,7 +2,6 @@ |
290 | github.com/blakesmith/ar git c9a977dd0cc1392b023382c7bfa5a22af8d3b730 2013-02-19T04:59:55Z |
291 | github.com/cheggaaa/pb git e8c7cc515bfde3e267957a3b110080ceed51354e 2014-12-02T07:01:21Z |
292 | github.com/jessevdk/go-flags git 15347ef417a300349807983f15af9e65cd2e1b3a 2015-01-25T08:53:51Z |
293 | -github.com/juju/loggo git 4c7cbce140ca070eeb59a28f4bf9507e511711f9 2015-02-26T05:51:10Z |
294 | github.com/mvo5/goconfigparser git 26426272dda20cc76aa1fa44286dc743d2972fe8 2015-02-12T09:37:50Z |
295 | gopkg.in/yaml.v2 git 49c95bdc21843256fb6c4e0d370a05f24a0bf213 2015-02-24T22:57:58Z |
296 | launchpad.net/gocheck bzr gustavo@niemeyer.net-20140225173054-xu9zlkf9kxhvow02 87 |
297 | |
298 | === added directory 'logger' |
299 | === removed directory 'logger' |
300 | === added file 'logger/logger.go' |
301 | --- logger/logger.go 1970-01-01 00:00:00 +0000 |
302 | +++ logger/logger.go 2015-05-11 15:56:13 +0000 |
303 | @@ -0,0 +1,138 @@ |
304 | +/* |
305 | + * Copyright (C) 2014-2015 Canonical Ltd |
306 | + * |
307 | + * This program is free software: you can redistribute it and/or modify |
308 | + * it under the terms of the GNU General Public License version 3 as |
309 | + * published by the Free Software Foundation. |
310 | + * |
311 | + * This program is distributed in the hope that it will be useful, |
312 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
313 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
314 | + * GNU General Public License for more details. |
315 | + * |
316 | + * You should have received a copy of the GNU General Public License |
317 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
318 | + * |
319 | + */ |
320 | + |
321 | +package logger |
322 | + |
323 | +import ( |
324 | + "fmt" |
325 | + "io" |
326 | + "log" |
327 | + "log/syslog" |
328 | + "os" |
329 | + "sync" |
330 | +) |
331 | + |
332 | +// A Logger is a fairly minimal logging tool. |
333 | +type Logger interface { |
334 | + // Notice is for messages that the user should see |
335 | + Notice(msg string) |
336 | + // Debug is for messages that the user should be able to find if they're debugging something |
337 | + Debug(msg string) |
338 | +} |
339 | + |
340 | +const ( |
341 | + // DefaultFlags are passed to the default console log.Logger |
342 | + DefaultFlags = log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile |
343 | + // SyslogFlags are passed to the default syslog log.Logger |
344 | + SyslogFlags = log.Lshortfile |
345 | + // SyslogPriority for the default syslog log.Logger |
346 | + SyslogPriority = syslog.LOG_DEBUG | syslog.LOG_USER |
347 | +) |
348 | + |
349 | +type nullLogger struct{} |
350 | + |
351 | +func (nullLogger) Notice(string) {} |
352 | +func (nullLogger) Debug(string) {} |
353 | + |
354 | +// NullLogger is a logger that does nothing |
355 | +var NullLogger = nullLogger{} |
356 | + |
357 | +var ( |
358 | + logger Logger = NullLogger |
359 | + lock sync.Mutex |
360 | +) |
361 | + |
362 | +// Panicf notifies the user and then panics |
363 | +func Panicf(format string, v ...interface{}) { |
364 | + msg := fmt.Sprintf(format, v...) |
365 | + |
366 | + lock.Lock() |
367 | + defer lock.Unlock() |
368 | + |
369 | + logger.Notice("PANIC " + msg) |
370 | + panic(msg) |
371 | +} |
372 | + |
373 | +// Noticef notifies the user of something |
374 | +func Noticef(format string, v ...interface{}) { |
375 | + msg := fmt.Sprintf(format, v...) |
376 | + |
377 | + lock.Lock() |
378 | + defer lock.Unlock() |
379 | + |
380 | + logger.Notice(msg) |
381 | +} |
382 | + |
383 | +// Debugf records something in the debug log |
384 | +func Debugf(format string, v ...interface{}) { |
385 | + msg := fmt.Sprintf(format, v...) |
386 | + |
387 | + lock.Lock() |
388 | + defer lock.Unlock() |
389 | + |
390 | + logger.Debug(msg) |
391 | +} |
392 | + |
393 | +// SetLogger sets the global logger to the given one |
394 | +func SetLogger(l Logger) { |
395 | + lock.Lock() |
396 | + defer lock.Unlock() |
397 | + |
398 | + logger = l |
399 | +} |
400 | + |
401 | +// ConsoleLog sends Notices to a log.Logger and Debugs to syslog |
402 | +type ConsoleLog struct { |
403 | + log *log.Logger |
404 | + sys *log.Logger |
405 | +} |
406 | + |
407 | +// Debug sends the msg to syslog |
408 | +func (l *ConsoleLog) Debug(msg string) { |
409 | + l.sys.Output(3, "DEBUG: "+msg) |
410 | +} |
411 | + |
412 | +// Notice alerts the user about something, as well as putting it syslog |
413 | +func (l *ConsoleLog) Notice(msg string) { |
414 | + l.sys.Output(3, msg) |
415 | + l.log.Output(3, msg) |
416 | +} |
417 | + |
418 | +// NewConsoleLog creates a ConsoleLog with a log.Logger using the given |
419 | +// io.Writer and flag, and a syslog.Writer. |
420 | +func NewConsoleLog(w io.Writer, flag int) (*ConsoleLog, error) { |
421 | + sys, err := syslog.NewLogger(SyslogPriority, SyslogFlags) |
422 | + if err != nil { |
423 | + return nil, err |
424 | + } |
425 | + |
426 | + return &ConsoleLog{ |
427 | + log: log.New(w, "", flag), |
428 | + sys: sys, |
429 | + }, nil |
430 | +} |
431 | + |
432 | +// SimpleSetup creates the default (console) logger |
433 | +func SimpleSetup() error { |
434 | + l, err := NewConsoleLog(os.Stderr, DefaultFlags) |
435 | + if err != nil { |
436 | + return err |
437 | + } |
438 | + SetLogger(l) |
439 | + |
440 | + return nil |
441 | +} |
442 | |
443 | === removed file 'logger/logger.go' |
444 | --- logger/logger.go 2015-05-11 15:56:13 +0000 |
445 | +++ logger/logger.go 1970-01-01 00:00:00 +0000 |
446 | @@ -1,189 +0,0 @@ |
447 | -/* |
448 | - * Copyright (C) 2014-2015 Canonical Ltd |
449 | - * |
450 | - * This program is free software: you can redistribute it and/or modify |
451 | - * it under the terms of the GNU General Public License version 3 as |
452 | - * published by the Free Software Foundation. |
453 | - * |
454 | - * This program is distributed in the hope that it will be useful, |
455 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
456 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
457 | - * GNU General Public License for more details. |
458 | - * |
459 | - * You should have received a copy of the GNU General Public License |
460 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
461 | - * |
462 | - */ |
463 | - |
464 | -package logger |
465 | - |
466 | -import ( |
467 | - "fmt" |
468 | - "log/syslog" |
469 | - "runtime/debug" |
470 | - "strings" |
471 | - "sync" |
472 | - "time" |
473 | - |
474 | - "github.com/juju/loggo" |
475 | -) |
476 | - |
477 | -// Name used in the prefix for all logged messages |
478 | -const LoggerName = "snappy" |
479 | - |
480 | -// logWriterInterface allows the tests to replace the syslog |
481 | -// implementation. |
482 | -type logWriterInterface interface { |
483 | - // syslog.Writer |
484 | - Debug(m string) error |
485 | - Info(m string) error |
486 | - Warning(m string) error |
487 | - Err(m string) error |
488 | - Crit(m string) error |
489 | -} |
490 | - |
491 | -// LogWriter object that handles writing log entries |
492 | -type LogWriter struct { |
493 | - systemLog logWriterInterface |
494 | -} |
495 | - |
496 | -// Used to ensure that only a single connection to syslog is created |
497 | -var once sync.Once |
498 | - |
499 | -// A single connection to the system logger |
500 | -var syslogConnection logWriterInterface |
501 | - |
502 | -// Write sends the log details specified by the params to the logging |
503 | -// back-end (in this case syslog). |
504 | -func (l *LogWriter) Write(level loggo.Level, name string, filename string, line int, timestamp time.Time, message string) { |
505 | - var f func(string) error |
506 | - |
507 | - record := l.Format(level, name, filename, line, timestamp, message) |
508 | - |
509 | - // map log level to syslog priority |
510 | - switch level { |
511 | - case loggo.DEBUG: |
512 | - f = l.systemLog.Debug |
513 | - |
514 | - case loggo.INFO: |
515 | - f = l.systemLog.Info |
516 | - |
517 | - case loggo.WARNING: |
518 | - f = l.systemLog.Warning |
519 | - |
520 | - case loggo.ERROR: |
521 | - f = l.systemLog.Err |
522 | - |
523 | - case loggo.CRITICAL: |
524 | - f = l.systemLog.Crit |
525 | - } |
526 | - |
527 | - // write the log record. |
528 | - // |
529 | - // Note that with loggo, the actual logging functions never |
530 | - // return errors, so although these syslog functions may fail, |
531 | - // there's not much we can do about it. |
532 | - f(record) |
533 | - |
534 | - if level >= loggo.ERROR { |
535 | - l.logStacktrace(level, name, filename, line, timestamp, f) |
536 | - } |
537 | -} |
538 | - |
539 | -func (l *LogWriter) logStacktrace(level loggo.Level, name string, filename string, line int, timestamp time.Time, f func(string) error) { |
540 | - stack := debug.Stack() |
541 | - |
542 | - str := "Stack trace:" |
543 | - record := l.Format(level, name, filename, line, timestamp, str) |
544 | - f(record) |
545 | - |
546 | - for _, entry := range strings.Split(string(stack), "\n") { |
547 | - if entry == "" { |
548 | - continue |
549 | - } |
550 | - |
551 | - formatted := fmt.Sprintf(" %s", strings.Replace(entry, "\t", " ", -1)) |
552 | - record := l.Format(level, name, filename, line, timestamp, formatted) |
553 | - f(record) |
554 | - } |
555 | -} |
556 | - |
557 | -// Format handles how each log entry should appear. |
558 | -// Note that the timestamp field is not used as syslog adds that for us. |
559 | -func (l *LogWriter) Format(level loggo.Level, module, filename string, line int, timestamp time.Time, message string) string { |
560 | - if level < loggo.ERROR { |
561 | - // keep it relatively succinct for low priority messages |
562 | - return fmt.Sprintf("%s:%s:%s", level, module, message) |
563 | - } |
564 | - |
565 | - return fmt.Sprintf("%s:%s:%s:%d:%s", level, module, filename, line, message) |
566 | -} |
567 | - |
568 | -// A variable to make testing easier |
569 | -var getSyslog = func(priority syslog.Priority, tag string) (w logWriterInterface, err error) { |
570 | - return syslog.New(syslog.LOG_NOTICE|syslog.LOG_LOCAL0, LoggerName) |
571 | -} |
572 | - |
573 | -// newLogWriter creates a new LogWriter, ensuring that only a single |
574 | -// connection to the system logger is created. |
575 | -func newLogWriter() (l *LogWriter, err error) { |
576 | - |
577 | - l = new(LogWriter) |
578 | - |
579 | - once.Do(func() { |
580 | - |
581 | - // Note that the log level here is just the default - Write() |
582 | - // will alter it as needed. |
583 | - syslogConnection, err = getSyslog(syslog.LOG_NOTICE|syslog.LOG_LOCAL0, LoggerName) |
584 | - }) |
585 | - |
586 | - if err != nil { |
587 | - return nil, err |
588 | - } |
589 | - |
590 | - l.systemLog = syslogConnection |
591 | - |
592 | - return l, nil |
593 | -} |
594 | - |
595 | -// ActivateLogger handles creating, configuring and enabling a new syslog logger. |
596 | -func ActivateLogger() (err error) { |
597 | - // Remove any existing loggers of the type we care about. |
598 | - // |
599 | - // No check on the success of these operations is performed since the |
600 | - // loggo API does not allow the existing loggers to be iterated so we |
601 | - // cannot know if there is already a syslog writer registered (for |
602 | - // example if newLogWriter() gets called multiple times). |
603 | - _, _, _ = loggo.RemoveWriter("default") |
604 | - _, _, _ = loggo.RemoveWriter("syslog") |
605 | - |
606 | - writer, err := newLogWriter() |
607 | - if err != nil { |
608 | - return err |
609 | - } |
610 | - |
611 | - // activate our syslog logger |
612 | - err = loggo.RegisterWriter("syslog", writer, loggo.TRACE) |
613 | - if err != nil { |
614 | - return err |
615 | - } |
616 | - |
617 | - logger := loggo.GetLogger(LoggerName) |
618 | - |
619 | - // ensure that all log messages are output |
620 | - logger.SetLogLevel(loggo.TRACE) |
621 | - |
622 | - return nil |
623 | -} |
624 | - |
625 | -// LogAndPanic logs the specified error, including a backtrace, then calls |
626 | -// panic(). |
627 | -func LogAndPanic(err error) { |
628 | - if err == nil { |
629 | - return |
630 | - } |
631 | - |
632 | - logger := loggo.GetLogger(LoggerName) |
633 | - logger.Criticalf(err.Error()) |
634 | - panic(err) |
635 | -} |
636 | |
637 | === added file 'logger/logger_test.go' |
638 | --- logger/logger_test.go 1970-01-01 00:00:00 +0000 |
639 | +++ logger/logger_test.go 2015-05-11 15:56:13 +0000 |
640 | @@ -0,0 +1,104 @@ |
641 | +/* |
642 | + * Copyright (C) 2014-2015 Canonical Ltd |
643 | + * |
644 | + * This program is free software: you can redistribute it and/or modify |
645 | + * it under the terms of the GNU General Public License version 3 as |
646 | + * published by the Free Software Foundation. |
647 | + * |
648 | + * This program is distributed in the hope that it will be useful, |
649 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
650 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
651 | + * GNU General Public License for more details. |
652 | + * |
653 | + * You should have received a copy of the GNU General Public License |
654 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
655 | + * |
656 | + */ |
657 | + |
658 | +package logger |
659 | + |
660 | +import ( |
661 | + "bytes" |
662 | + "log" |
663 | + "testing" |
664 | + |
665 | + . "launchpad.net/gocheck" |
666 | +) |
667 | + |
668 | +// Hook up gocheck into the "go test" runner |
669 | +func Test(t *testing.T) { TestingT(t) } |
670 | + |
671 | +var _ = Suite(&LogSuite{}) |
672 | + |
673 | +type LogSuite struct{} |
674 | + |
675 | +func (s *LogSuite) SetUpTest(c *C) { |
676 | + c.Assert(logger, Equals, NullLogger) |
677 | +} |
678 | + |
679 | +func (s *LogSuite) TearDownTest(c *C) { |
680 | + SetLogger(NullLogger) |
681 | +} |
682 | + |
683 | +func (s *LogSuite) TestDefault(c *C) { |
684 | + if logger != nil { |
685 | + SetLogger(nil) |
686 | + } |
687 | + c.Check(logger, IsNil) |
688 | + |
689 | + err := SimpleSetup() |
690 | + c.Check(err, IsNil) |
691 | + c.Check(logger, NotNil) |
692 | + SetLogger(nil) |
693 | +} |
694 | + |
695 | +func (s *LogSuite) TestNew(c *C) { |
696 | + var buf bytes.Buffer |
697 | + l, err := NewConsoleLog(&buf, DefaultFlags) |
698 | + c.Assert(err, IsNil) |
699 | + c.Assert(l, NotNil) |
700 | + c.Check(l.sys, NotNil) |
701 | + c.Check(l.log, NotNil) |
702 | +} |
703 | + |
704 | +func (s *LogSuite) TestDebugf(c *C) { |
705 | + var logbuf bytes.Buffer |
706 | + var sysbuf bytes.Buffer |
707 | + l, err := NewConsoleLog(&logbuf, DefaultFlags) |
708 | + c.Assert(err, IsNil) |
709 | + |
710 | + l.sys = log.New(&sysbuf, "", SyslogFlags) |
711 | + SetLogger(l) |
712 | + |
713 | + Debugf("xyzzy") |
714 | + c.Check(sysbuf.String(), Matches, `(?m).*logger_test\.go:\d+: DEBUG: xyzzy`) |
715 | + c.Check(logbuf.String(), Equals, "") |
716 | +} |
717 | + |
718 | +func (s *LogSuite) TestNoticef(c *C) { |
719 | + var logbuf bytes.Buffer |
720 | + var sysbuf bytes.Buffer |
721 | + l, err := NewConsoleLog(&logbuf, DefaultFlags) |
722 | + c.Assert(err, IsNil) |
723 | + |
724 | + l.sys = log.New(&sysbuf, "", SyslogFlags) |
725 | + SetLogger(l) |
726 | + |
727 | + Noticef("xyzzy") |
728 | + c.Check(sysbuf.String(), Matches, `(?m).*logger_test\.go:\d+: xyzzy`) |
729 | + c.Check(logbuf.String(), Matches, `(?m).*logger_test\.go:\d+: xyzzy`) |
730 | +} |
731 | + |
732 | +func (s *LogSuite) TestPanicf(c *C) { |
733 | + var logbuf bytes.Buffer |
734 | + var sysbuf bytes.Buffer |
735 | + l, err := NewConsoleLog(&logbuf, DefaultFlags) |
736 | + c.Assert(err, IsNil) |
737 | + |
738 | + l.sys = log.New(&sysbuf, "", SyslogFlags) |
739 | + SetLogger(l) |
740 | + |
741 | + c.Check(func() { Panicf("xyzzy") }, Panics, "xyzzy") |
742 | + c.Check(sysbuf.String(), Matches, `(?m).*logger_test\.go:\d+: PANIC xyzzy`) |
743 | + c.Check(logbuf.String(), Matches, `(?m).*logger_test\.go:\d+: PANIC xyzzy`) |
744 | +} |
745 | |
746 | === removed file 'logger/logger_test.go' |
747 | --- logger/logger_test.go 2015-05-11 15:56:13 +0000 |
748 | +++ logger/logger_test.go 1970-01-01 00:00:00 +0000 |
749 | @@ -1,310 +0,0 @@ |
750 | -/* |
751 | - * Copyright (C) 2014-2015 Canonical Ltd |
752 | - * |
753 | - * This program is free software: you can redistribute it and/or modify |
754 | - * it under the terms of the GNU General Public License version 3 as |
755 | - * published by the Free Software Foundation. |
756 | - * |
757 | - * This program is distributed in the hope that it will be useful, |
758 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
759 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
760 | - * GNU General Public License for more details. |
761 | - * |
762 | - * You should have received a copy of the GNU General Public License |
763 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
764 | - * |
765 | - */ |
766 | - |
767 | -package logger |
768 | - |
769 | -import ( |
770 | - "bytes" |
771 | - "errors" |
772 | - "fmt" |
773 | - "log/syslog" |
774 | - "regexp" |
775 | - "strings" |
776 | - "testing" |
777 | - "time" |
778 | - |
779 | - "github.com/juju/loggo" |
780 | - . "launchpad.net/gocheck" |
781 | -) |
782 | - |
783 | -func Test(t *testing.T) { TestingT(t) } |
784 | - |
785 | -type LoggerTestSuite struct { |
786 | -} |
787 | - |
788 | -var _ = Suite(&LoggerTestSuite{}) |
789 | - |
790 | -type MockLogWriter struct { |
791 | - buf bytes.Buffer |
792 | -} |
793 | - |
794 | -var mockWriter *MockLogWriter |
795 | - |
796 | -var loggoLevels = []string{"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} |
797 | - |
798 | -func mockGetSyslog(priority syslog.Priority, tag string) (w logWriterInterface, err error) { |
799 | - mockWriter = &MockLogWriter{} |
800 | - return mockWriter, nil |
801 | -} |
802 | - |
803 | -func readLines() (lines []string) { |
804 | - lines = strings.Split(string(mockWriter.buf.Bytes()), "\n") |
805 | - |
806 | - // remove the last line if empty due to split. |
807 | - length := len(lines) |
808 | - last := lines[length-1] |
809 | - if last == "" { |
810 | - lines = lines[:length-1] |
811 | - } |
812 | - // clear the buffer to avoid contents accumulating indefinitely |
813 | - mockWriter.buf.Reset() |
814 | - return lines |
815 | -} |
816 | - |
817 | -func (ts *LoggerTestSuite) SetUpTest(c *C) { |
818 | - getSyslog = mockGetSyslog |
819 | -} |
820 | - |
821 | -func (w *MockLogWriter) Debug(m string) error { |
822 | - _, err := w.buf.Write([]byte(fmt.Sprintf("DEBUG: %s\n", m))) |
823 | - return err |
824 | -} |
825 | - |
826 | -func (w *MockLogWriter) Info(m string) error { |
827 | - _, err := w.buf.Write([]byte(fmt.Sprintf("INFO: %s\n", m))) |
828 | - return err |
829 | -} |
830 | - |
831 | -func (w *MockLogWriter) Warning(m string) error { |
832 | - _, err := w.buf.Write([]byte(fmt.Sprintf("WARNING: %s\n", m))) |
833 | - return err |
834 | -} |
835 | - |
836 | -func (w *MockLogWriter) Err(m string) error { |
837 | - _, err := w.buf.Write([]byte(fmt.Sprintf("ERROR: %s\n", m))) |
838 | - return err |
839 | -} |
840 | - |
841 | -func (w *MockLogWriter) Crit(m string) error { |
842 | - _, err := w.buf.Write([]byte(fmt.Sprintf("CRITICAL: %s\n", m))) |
843 | - return err |
844 | -} |
845 | - |
846 | -// Search for value in array and return true if found |
847 | -func sliceContainsString(array []string, value string) bool { |
848 | - str := string(strings.Join(array, "")) |
849 | - |
850 | - return strings.Contains(str, value) |
851 | -} |
852 | - |
853 | -// Return true if array contains the pattern regex. |
854 | -func sliceContainsRegex(array []string, regex string) bool { |
855 | - str := string(strings.Join(array, "")) |
856 | - |
857 | - pattern := regexp.MustCompile(regex) |
858 | - |
859 | - matches := pattern.FindAllStringSubmatch(str, -1) |
860 | - |
861 | - return matches != nil |
862 | -} |
863 | - |
864 | -func (ts *LoggerTestSuite) TestNewLogWriter(c *C) { |
865 | - var w, w2 *LogWriter |
866 | - var err error |
867 | - |
868 | - w, err = newLogWriter() |
869 | - c.Assert(err, IsNil) |
870 | - c.Assert(w, Not(IsNil)) |
871 | - c.Assert(w.systemLog, Not(IsNil)) |
872 | - |
873 | - w2, err = newLogWriter() |
874 | - c.Assert(err, IsNil) |
875 | - c.Assert(w2, Not(IsNil)) |
876 | - c.Assert(w2.systemLog, Not(IsNil)) |
877 | - |
878 | - // There should be a single shared syslog connection, hence the |
879 | - // systemLog objects should be identical. |
880 | - c.Assert(w.systemLog, Equals, w2.systemLog) |
881 | - c.Assert(w.systemLog, DeepEquals, w2.systemLog) |
882 | -} |
883 | - |
884 | -func (ts *LoggerTestSuite) TestWrite(c *C) { |
885 | - w, err := newLogWriter() |
886 | - c.Assert(err, IsNil) |
887 | - c.Assert(w, Not(IsNil)) |
888 | - c.Assert(w.systemLog, Not(IsNil)) |
889 | - |
890 | - t := time.Now() |
891 | - strTime := fmt.Sprintf("%s", t) |
892 | - |
893 | - for _, l := range loggoLevels { |
894 | - level := stringToLogLevel(l) |
895 | - |
896 | - w.Write(level, "module", "filename", 1234, t, "a message") |
897 | - lines := readLines() |
898 | - |
899 | - if level < loggo.ERROR { |
900 | - c.Assert(len(lines), Equals, 1) |
901 | - } else { |
902 | - c.Assert(len(lines) > 1, Equals, true) |
903 | - |
904 | - c.Assert(sliceContainsString(lines, "filename"), Equals, true) |
905 | - c.Assert(sliceContainsString(lines, "1234"), Equals, true) |
906 | - } |
907 | - |
908 | - c.Assert(sliceContainsString(lines, "module"), Equals, true) |
909 | - |
910 | - // We discard the timestamp as syslog adds that itself |
911 | - c.Assert(sliceContainsString(lines, strTime), Equals, false) |
912 | - |
913 | - c.Assert(sliceContainsString(lines, "a message"), Equals, true) |
914 | - } |
915 | - |
916 | -} |
917 | - |
918 | -// Convert a loggo log level string representation into a real log |
919 | -// level. |
920 | -func stringToLogLevel(name string) loggo.Level { |
921 | - level, ok := loggo.ParseLevel(name) |
922 | - |
923 | - if !ok { |
924 | - panic(fmt.Sprintf("unknown loggo level string: %q", name)) |
925 | - } |
926 | - |
927 | - return level |
928 | -} |
929 | - |
930 | -func (ts *LoggerTestSuite) TestFormat(c *C) { |
931 | - w, err := newLogWriter() |
932 | - c.Assert(err, IsNil) |
933 | - c.Assert(w, Not(IsNil)) |
934 | - c.Assert(w.systemLog, Not(IsNil)) |
935 | - |
936 | - for _, l := range loggoLevels { |
937 | - level := stringToLogLevel(l) |
938 | - |
939 | - if level < loggo.ERROR { |
940 | - out := w.Format(level, "module", "filename", 1234, time.Now(), "a message") |
941 | - c.Assert(out, Equals, fmt.Sprintf("%s:%s:%s", l, "module", "a message")) |
942 | - } else { |
943 | - out := w.Format(level, "module", "filename", 1234, time.Now(), "a message") |
944 | - c.Assert(out, Equals, fmt.Sprintf("%s:%s:%s:%d:%s", l, "module", "filename", 1234, "a message")) |
945 | - } |
946 | - } |
947 | -} |
948 | - |
949 | -func (ts *LoggerTestSuite) TestLogStackTrace(c *C) { |
950 | - var output []string |
951 | - |
952 | - w, err := newLogWriter() |
953 | - c.Assert(err, IsNil) |
954 | - c.Assert(w, Not(IsNil)) |
955 | - |
956 | - f := func(s string) error { |
957 | - output = append(output, s) |
958 | - return nil |
959 | - } |
960 | - |
961 | - t := time.Now() |
962 | - strTime := fmt.Sprintf("%s", t) |
963 | - |
964 | - w.logStacktrace(loggo.DEBUG, "name", "filename", 9876, t, f) |
965 | - |
966 | - c.Assert(sliceContainsString(output, "Stack trace"), Equals, true) |
967 | - c.Assert(sliceContainsString(output, "name"), Equals, true) |
968 | - c.Assert(sliceContainsString(output, "filename"), Equals, true) |
969 | - c.Assert(sliceContainsString(output, "9876"), Equals, true) |
970 | - |
971 | - // We discard the timestamp as syslog adds that itself |
972 | - c.Assert(sliceContainsString(output, strTime), Equals, false) |
973 | -} |
974 | - |
975 | -func (ts *LoggerTestSuite) checkLogLevel(c *C, level, msg string) { |
976 | - err := ActivateLogger() |
977 | - c.Assert(err, IsNil) |
978 | - |
979 | - expectBacktrace := (level == "ERROR" || level == "CRITICAL") |
980 | - |
981 | - logger := loggo.GetLogger("snappy") |
982 | - c.Assert(logger, Not(IsNil)) |
983 | - |
984 | - switch level { |
985 | - case "DEBUG": |
986 | - c.Assert(logger.IsDebugEnabled(), Equals, true) |
987 | - logger.Debugf(msg) |
988 | - |
989 | - case "INFO": |
990 | - c.Assert(logger.IsInfoEnabled(), Equals, true) |
991 | - logger.Infof(msg) |
992 | - |
993 | - case "WARNING": |
994 | - c.Assert(logger.IsWarningEnabled(), Equals, true) |
995 | - logger.Warningf(msg) |
996 | - |
997 | - case "ERROR": |
998 | - c.Assert(logger.IsErrorEnabled(), Equals, true) |
999 | - logger.Errorf(msg) |
1000 | - |
1001 | - case "CRITICAL": |
1002 | - // loggo doesn't provide a IsCriticalEnabled() |
1003 | - c.Assert(logger.IsErrorEnabled(), Equals, true) |
1004 | - logger.Criticalf(msg) |
1005 | - } |
1006 | - |
1007 | - lines := readLines() |
1008 | - |
1009 | - if expectBacktrace { |
1010 | - c.Assert(len(lines) > 1, Equals, true) |
1011 | - } else { |
1012 | - c.Assert(len(lines), Equals, 1) |
1013 | - } |
1014 | - |
1015 | - needle := fmt.Sprintf("%s.*%s", level, msg) |
1016 | - c.Assert(sliceContainsRegex(lines, needle), Equals, true) |
1017 | - |
1018 | - c.Assert(sliceContainsString(lines, "Stack trace"), Equals, expectBacktrace) |
1019 | -} |
1020 | - |
1021 | -func (ts *LoggerTestSuite) TestLogLevels(c *C) { |
1022 | - msg := "an error message" |
1023 | - |
1024 | - for _, level := range loggoLevels { |
1025 | - ts.checkLogLevel(c, level, msg) |
1026 | - } |
1027 | -} |
1028 | - |
1029 | -func (ts *LoggerTestSuite) TestLogAndPanic(c *C) { |
1030 | - level := "CRITICAL" |
1031 | - msg := "I am a fatal error" |
1032 | - |
1033 | - panicked := false |
1034 | - |
1035 | - err := ActivateLogger() |
1036 | - c.Assert(err, IsNil) |
1037 | - |
1038 | - // If the specified error is nil, no panic is expected and no |
1039 | - // log entry should be added. |
1040 | - func() { |
1041 | - defer func() { |
1042 | - if r := recover(); r != nil { |
1043 | - panicked = true |
1044 | - } |
1045 | - }() |
1046 | - LogAndPanic(nil) |
1047 | - }() |
1048 | - |
1049 | - c.Assert(panicked, Equals, false) |
1050 | - c.Assert(len(readLines()), Equals, 0) |
1051 | - |
1052 | - err = errors.New(msg) |
1053 | - |
1054 | - // expect a panic... |
1055 | - c.Assert(func() { LogAndPanic(err) }, Panics, err) |
1056 | - |
1057 | - // ... and a log entry |
1058 | - ts.checkLogLevel(c, level, msg) |
1059 | -} |
1060 | |
1061 | === modified file 'snappy/dbus.go' |
1062 | --- snappy/dbus.go 2015-04-19 01:24:03 +0000 |
1063 | +++ snappy/dbus.go 2015-05-11 15:56:13 +0000 |
1064 | @@ -75,7 +75,7 @@ |
1065 | } |
1066 | if err := t.Execute(&templateOut, wrapperData); err != nil { |
1067 | // this can never happen, except we forget a variable |
1068 | - logger.LogAndPanic(err) |
1069 | + logger.Panicf("unable to execute template: %v", err) |
1070 | } |
1071 | |
1072 | return templateOut.String(), nil |
1073 | |
1074 | === modified file 'systemd/systemd.go' |
1075 | --- systemd/systemd.go 2015-04-22 21:13:25 +0000 |
1076 | +++ systemd/systemd.go 2015-05-11 15:56:13 +0000 |
1077 | @@ -216,7 +216,7 @@ |
1078 | } |
1079 | if err := t.Execute(&templateOut, wrapperData); err != nil { |
1080 | // this can never happen, except we forget a variable |
1081 | - logger.LogAndPanic(err) |
1082 | + logger.Panicf("unable to execute template: %v", err) |
1083 | } |
1084 | |
1085 | return templateOut.String() |
Just for the record:
perl -pi -w -e '$c=$ARGV; $c=~s|^ (?:.*/) ?cmd_(\ w+?)(?: _test)? \.go$|$ 1|; s/logger\ .LogAndPanic\ (err\)/ log.Panic( "unable to $c: %v", err)/; s|snappy/ logger| snappy/ log|' cmd/snappy/cmd_*.go