File: wrap_handlers.go

package info (click to toggle)
golang-github-revel-revel 1.0.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,240 kB
  • sloc: xml: 7; makefile: 7; javascript: 1
file content (98 lines) | stat: -rw-r--r-- 2,626 bytes parent folder | download | duplicates (2)
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
package logger

// FuncHandler returns a Handler that logs records with the given
// function.
import (
	"fmt"
	"reflect"
	"sync"
	"time"
)

// Function handler wraps the declared function and returns the handler for it
func FuncHandler(fn func(r *Record) error) LogHandler {
	return funcHandler(fn)
}

// The type decleration for the function
type funcHandler func(r *Record) error

// The implementation of the Log
func (h funcHandler) Log(r *Record) error {
	return h(r)
}

// This function allows you to do a full declaration for the log,
// it is recommended you use FuncHandler instead
func HandlerFunc(log func(message string, time time.Time, level LogLevel, call CallStack, context ContextMap) error) LogHandler {
	return remoteHandler(log)
}

// The type used for the HandlerFunc
type remoteHandler func(message string, time time.Time, level LogLevel, call CallStack, context ContextMap) error

// The Log implementation
func (c remoteHandler) Log(record *Record) error {
	return c(record.Message, record.Time, record.Level, record.Call, record.Context)
}

// SyncHandler can be wrapped around a handler to guarantee that
// only a single Log operation can proceed at a time. It's necessary
// for thread-safe concurrent writes.
func SyncHandler(h LogHandler) LogHandler {
	var mu sync.Mutex
	return FuncHandler(func(r *Record) error {
		defer mu.Unlock()
		mu.Lock()
		return h.Log(r)
	})
}

// LazyHandler writes all values to the wrapped handler after evaluating
// any lazy functions in the record's context. It is already wrapped
// around StreamHandler and SyslogHandler in this library, you'll only need
// it if you write your own Handler.
func LazyHandler(h LogHandler) LogHandler {
	return FuncHandler(func(r *Record) error {
		for k, v := range r.Context {
			if lz, ok := v.(Lazy); ok {
				value, err := evaluateLazy(lz)
				if err != nil {
					r.Context[errorKey] = "bad lazy " + k
				} else {
					v = value
				}
			}
		}

		return h.Log(r)
	})
}

func evaluateLazy(lz Lazy) (interface{}, error) {
	t := reflect.TypeOf(lz.Fn)

	if t.Kind() != reflect.Func {
		return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
	}

	if t.NumIn() > 0 {
		return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
	}

	if t.NumOut() == 0 {
		return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
	}

	value := reflect.ValueOf(lz.Fn)
	results := value.Call([]reflect.Value{})
	if len(results) == 1 {
		return results[0].Interface(), nil
	} else {
		values := make([]interface{}, len(results))
		for i, v := range results {
			values[i] = v.Interface()
		}
		return values, nil
	}
}