1 package log
2
3 import (
4 "bytes"
5 e "errors"
6 "fmt"
7 "strings"
8 "sync"
9
10 "text/template"
11
12 "github.com/go-errors/errors"
13 "golang.org/x/net/context"
14 )
15
16
17
18
19 const (
20 LevelDebug = iota
21 LevelInfo = iota
22 LevelWarning = iota
23 LevelError = iota
24 )
25
26
27 const (
28 LevelNameDebug = "debug"
29 LevelNameInfo = "info"
30 LevelNameWarning = "warning"
31 LevelNameError = "error"
32 )
33
34
35 var (
36 LevelNameMap = map[string]int{
37 LevelNameDebug: LevelDebug,
38 LevelNameInfo: LevelInfo,
39 LevelNameWarning: LevelWarning,
40 LevelNameError: LevelError,
41 }
42
43 LevelNameMapR = map[int]string{
44 LevelDebug: LevelNameDebug,
45 LevelInfo: LevelNameInfo,
46 LevelWarning: LevelNameWarning,
47 LevelError: LevelNameError,
48 }
49 )
50
51
52 var (
53 ErrAdapterAlreadyRegistered = e.New("adapter already registered")
54 ErrFormatEmpty = e.New("format is empty")
55 ErrExcludeLevelNameInvalid = e.New("exclude bypass-level is invalid")
56 ErrNoAdapterConfigured = e.New("no default adapter configured")
57 ErrAdapterIsNil = e.New("adapter is nil")
58 ErrConfigurationNotLoaded = e.New("can not configure because configuration is not loaded")
59 )
60
61
62 var (
63 includeFilters = make(map[string]bool)
64 useIncludeFilters = false
65 excludeFilters = make(map[string]bool)
66 useExcludeFilters = false
67
68 adapters = make(map[string]LogAdapter)
69
70
71 excludeBypassLevel = -1
72 )
73
74
75 func AddIncludeFilter(noun string) {
76 includeFilters[noun] = true
77 useIncludeFilters = true
78 }
79
80
81 func RemoveIncludeFilter(noun string) {
82 delete(includeFilters, noun)
83 if len(includeFilters) == 0 {
84 useIncludeFilters = false
85 }
86 }
87
88
89 func AddExcludeFilter(noun string) {
90 excludeFilters[noun] = true
91 useExcludeFilters = true
92 }
93
94
95 func RemoveExcludeFilter(noun string) {
96 delete(excludeFilters, noun)
97 if len(excludeFilters) == 0 {
98 useExcludeFilters = false
99 }
100 }
101
102 func AddAdapter(name string, la LogAdapter) {
103 if _, found := adapters[name]; found == true {
104 Panic(ErrAdapterAlreadyRegistered)
105 }
106
107 if la == nil {
108 Panic(ErrAdapterIsNil)
109 }
110
111 adapters[name] = la
112
113 if GetDefaultAdapterName() == "" {
114 SetDefaultAdapterName(name)
115 }
116 }
117
118 func ClearAdapters() {
119 adapters = make(map[string]LogAdapter)
120 SetDefaultAdapterName("")
121 }
122
123 type LogAdapter interface {
124 Debugf(lc *LogContext, message *string) error
125 Infof(lc *LogContext, message *string) error
126 Warningf(lc *LogContext, message *string) error
127 Errorf(lc *LogContext, message *string) error
128 }
129
130
131
132
133 type MessageContext struct {
134 Level *string
135 Noun *string
136 Message *string
137 ExcludeBypass bool
138 }
139
140 type LogContext struct {
141 Logger *Logger
142 Ctx context.Context
143 }
144
145 type Logger struct {
146 isConfigured bool
147 an string
148 la LogAdapter
149 t *template.Template
150 systemLevel int
151 noun string
152 }
153
154 func NewLoggerWithAdapterName(noun string, adapterName string) (l *Logger) {
155 l = &Logger{
156 noun: noun,
157 an: adapterName,
158 }
159
160 return l
161 }
162
163 func NewLogger(noun string) (l *Logger) {
164 l = NewLoggerWithAdapterName(noun, "")
165
166 return l
167 }
168
169 func (l *Logger) Noun() string {
170 return l.noun
171 }
172
173 func (l *Logger) Adapter() LogAdapter {
174 return l.la
175 }
176
177 var (
178 configureMutex sync.Mutex
179 )
180
181 func (l *Logger) doConfigure(force bool) {
182 configureMutex.Lock()
183 defer configureMutex.Unlock()
184
185 if l.isConfigured == true && force == false {
186 return
187 }
188
189 if IsConfigurationLoaded() == false {
190 Panic(ErrConfigurationNotLoaded)
191 }
192
193 if l.an == "" {
194 l.an = GetDefaultAdapterName()
195 }
196
197
198
199
200 if l.an != "" {
201 la, found := adapters[l.an]
202 if found == false {
203 Panic(fmt.Errorf("adapter is not valid: %s", l.an))
204 }
205
206 l.la = la
207 }
208
209
210
211 systemLevel, found := LevelNameMap[levelName]
212 if found == false {
213 Panic(fmt.Errorf("log-level not valid: [%s]", levelName))
214 }
215
216 l.systemLevel = systemLevel
217
218
219
220 if format == "" {
221 Panic(ErrFormatEmpty)
222 }
223
224 if t, err := template.New("logItem").Parse(format); err != nil {
225 Panic(err)
226 } else {
227 l.t = t
228 }
229
230 l.isConfigured = true
231 }
232
233 func (l *Logger) flattenMessage(lc *MessageContext, format *string, args []interface{}) (string, error) {
234 m := fmt.Sprintf(*format, args...)
235
236 lc.Message = &m
237
238 var b bytes.Buffer
239 if err := l.t.Execute(&b, *lc); err != nil {
240 return "", err
241 }
242
243 return b.String(), nil
244 }
245
246 func (l *Logger) allowMessage(noun string, level int) bool {
247 if _, found := includeFilters[noun]; found == true {
248 return true
249 }
250
251
252
253 if useIncludeFilters == true {
254 return false
255 }
256
257 if _, found := excludeFilters[noun]; found == true {
258 return false
259 }
260
261 return true
262 }
263
264 func (l *Logger) makeLogContext(ctx context.Context) *LogContext {
265 return &LogContext{
266 Ctx: ctx,
267 Logger: l,
268 }
269 }
270
271 type LogMethod func(lc *LogContext, message *string) error
272
273 func (l *Logger) log(ctx context.Context, level int, lm LogMethod, format string, args []interface{}) error {
274 if l.systemLevel > level {
275 return nil
276 }
277
278
279
280
281
282
283 canExcludeBypass := level >= excludeBypassLevel && excludeBypassLevel != -1
284 didExcludeBypass := false
285
286 n := l.Noun()
287
288 if l.allowMessage(n, level) == false {
289 if canExcludeBypass == false {
290 return nil
291 } else {
292 didExcludeBypass = true
293 }
294 }
295
296 levelName, found := LevelNameMapR[level]
297 if found == false {
298 Panic(fmt.Errorf("level not valid: (%d)", level))
299 }
300
301 levelName = strings.ToUpper(levelName)
302
303 lc := &MessageContext{
304 Level: &levelName,
305 Noun: &n,
306 ExcludeBypass: didExcludeBypass,
307 }
308
309 if s, err := l.flattenMessage(lc, &format, args); err != nil {
310 return err
311 } else {
312 lc := l.makeLogContext(ctx)
313 if err := lm(lc, &s); err != nil {
314 panic(err)
315 }
316
317 return e.New(s)
318 }
319 }
320
321 func (l *Logger) Debugf(ctx context.Context, format string, args ...interface{}) {
322 l.doConfigure(false)
323
324 if l.la != nil {
325 l.log(ctx, LevelDebug, l.la.Debugf, format, args)
326 }
327 }
328
329 func (l *Logger) Infof(ctx context.Context, format string, args ...interface{}) {
330 l.doConfigure(false)
331
332 if l.la != nil {
333 l.log(ctx, LevelInfo, l.la.Infof, format, args)
334 }
335 }
336
337 func (l *Logger) Warningf(ctx context.Context, format string, args ...interface{}) {
338 l.doConfigure(false)
339
340 if l.la != nil {
341 l.log(ctx, LevelWarning, l.la.Warningf, format, args)
342 }
343 }
344
345 func (l *Logger) mergeStack(err interface{}, format string, args []interface{}) (string, []interface{}) {
346 if format != "" {
347 format += "\n%s"
348 } else {
349 format = "%s"
350 }
351
352 var stackified *errors.Error
353 stackified, ok := err.(*errors.Error)
354 if ok == false {
355 stackified = errors.Wrap(err, 2)
356 }
357
358 args = append(args, stackified.ErrorStack())
359
360 return format, args
361 }
362
363 func (l *Logger) Errorf(ctx context.Context, errRaw interface{}, format string, args ...interface{}) {
364 l.doConfigure(false)
365
366 var err interface{}
367
368 if errRaw != nil {
369 _, ok := errRaw.(*errors.Error)
370 if ok == true {
371 err = errRaw
372 } else {
373 err = errors.Wrap(errRaw, 1)
374 }
375 }
376
377 if l.la != nil {
378 if errRaw != nil {
379 format, args = l.mergeStack(err, format, args)
380 }
381
382 l.log(ctx, LevelError, l.la.Errorf, format, args)
383 }
384 }
385
386 func (l *Logger) ErrorIff(ctx context.Context, errRaw interface{}, format string, args ...interface{}) {
387 if errRaw == nil {
388 return
389 }
390
391 var err interface{}
392
393 _, ok := errRaw.(*errors.Error)
394 if ok == true {
395 err = errRaw
396 } else {
397 err = errors.Wrap(errRaw, 1)
398 }
399
400 l.Errorf(ctx, err, format, args...)
401 }
402
403 func (l *Logger) Panicf(ctx context.Context, errRaw interface{}, format string, args ...interface{}) {
404 l.doConfigure(false)
405
406 var err interface{}
407
408 _, ok := errRaw.(*errors.Error)
409 if ok == true {
410 err = errRaw
411 } else {
412 err = errors.Wrap(errRaw, 1)
413 }
414
415 if l.la != nil {
416 format, args = l.mergeStack(err, format, args)
417 err = l.log(ctx, LevelError, l.la.Errorf, format, args)
418 }
419
420 Panic(err.(error))
421 }
422
423 func (l *Logger) PanicIff(ctx context.Context, errRaw interface{}, format string, args ...interface{}) {
424 if errRaw == nil {
425 return
426 }
427
428 var err interface{}
429
430 _, ok := errRaw.(*errors.Error)
431 if ok == true {
432 err = errRaw
433 } else {
434 err = errors.Wrap(errRaw, 1)
435 }
436
437 l.Panicf(ctx, err.(error), format, args...)
438 }
439
440 func Wrap(err interface{}) *errors.Error {
441 es, ok := err.(*errors.Error)
442 if ok == true {
443 return es
444 } else {
445 return errors.Wrap(err, 1)
446 }
447 }
448
449 func Errorf(message string, args ...interface{}) *errors.Error {
450 err := fmt.Errorf(message, args...)
451 return errors.Wrap(err, 1)
452 }
453
454 func Panic(err interface{}) {
455 _, ok := err.(*errors.Error)
456 if ok == true {
457 panic(err)
458 } else {
459 panic(errors.Wrap(err, 1))
460 }
461 }
462
463 func Panicf(message string, args ...interface{}) {
464 err := Errorf(message, args...)
465 Panic(err)
466 }
467
468 func PanicIf(err interface{}) {
469 if err == nil {
470 return
471 }
472
473 _, ok := err.(*errors.Error)
474 if ok == true {
475 panic(err)
476 } else {
477 panic(errors.Wrap(err, 1))
478 }
479 }
480
481
482
483
484 func Is(actual, against error) bool {
485
486 if _, ok := actual.(*errors.Error); ok == false {
487 return actual == against
488 }
489
490 return errors.Is(actual, against)
491 }
492
493
494
495 func PrintError(err error) {
496 wrapped := Wrap(err)
497 fmt.Printf("Stack:\n\n%s\n", wrapped.ErrorStack())
498 }
499
500
501
502 func PrintErrorf(err error, format string, args ...interface{}) {
503 wrapped := Wrap(err)
504
505 fmt.Printf(format, args...)
506 fmt.Printf("\n")
507 fmt.Printf("Stack:\n\n%s\n", wrapped.ErrorStack())
508 }
509
510 func init() {
511 if format == "" {
512 format = defaultFormat
513 }
514
515 if levelName == "" {
516 levelName = defaultLevelName
517 }
518
519 if includeNouns != "" {
520 for _, noun := range strings.Split(includeNouns, ",") {
521 AddIncludeFilter(noun)
522 }
523 }
524
525 if excludeNouns != "" {
526 for _, noun := range strings.Split(excludeNouns, ",") {
527 AddExcludeFilter(noun)
528 }
529 }
530
531 if excludeBypassLevelName != "" {
532 var found bool
533 if excludeBypassLevel, found = LevelNameMap[excludeBypassLevelName]; found == false {
534 panic(ErrExcludeLevelNameInvalid)
535 }
536 }
537 }
538
View as plain text