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
|
package log
import (
"fmt"
"os"
"regexp"
"strings"
"sync"
"github.com/evilsocket/islazy/tui"
)
type MessageCallback = func(verbosity Verbosity, message string)
var (
// Level represents the current verbosity level of the logging system.
Level = INFO
// Output represents the log output file path if filled or, if empty, stdout.
Output = ""
// NoEffects disables all effects and colors if set to true.
NoEffects = false
// OnFatal represents the callback/action to execute on Fatal messages.
OnFatal = ExitOnFatal
// A custom callback to execute for every log message.
Callback = dummyCallback
lock = &sync.Mutex{}
currMessage = ""
currLevel = INFO
writer = os.Stdout
reEffects = []*regexp.Regexp{
regexp.MustCompile("\x033\\[\\d+m"),
regexp.MustCompile("\\\\e\\[\\d+m"),
regexp.MustCompile("\x1b\\[\\d+m"),
}
)
// Open initializes the logging system.
func Open() (err error) {
if Output != "" {
writer, err = os.OpenFile(Output, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644)
}
return
}
// Close finalizes the logging system.
func Close() {
if writer != os.Stdout {
writer.Close()
}
}
func dummyCallback(verbosity Verbosity, message string) {
}
func removeEffects(s string) string {
for _, re := range reEffects {
s = re.ReplaceAllString(s, "")
}
return s
}
func emit(v Verbosity, s string) {
// remove all effects if found
plain := removeEffects(s)
Callback(v, plain)
if NoEffects {
s = plain
}
fmt.Fprintf(writer, "%s\n", s)
}
func do(v Verbosity, format string, args ...interface{}) {
lock.Lock()
defer lock.Unlock()
if Level > v {
return
}
logLine := Format
currLevel = v
currMessage = format
if args != nil {
currMessage = fmt.Sprintf(format, args...)
}
// process token -> callback
for token, cb := range Tokens {
logLine = strings.Replace(logLine, token, cb(), -1)
}
// process token -> effect
for token, effect := range Effects {
logLine = strings.Replace(logLine, token, effect, -1)
}
// make sure an user error does not screw the log
if tui.HasEffect(logLine) && !strings.HasSuffix(logLine, tui.RESET) {
logLine += tui.RESET
}
emit(v, logLine)
}
// Raw emits a message without format to the logs.
func Raw(format string, args ...interface{}) {
lock.Lock()
defer lock.Unlock()
currMessage = fmt.Sprintf(format, args...)
emit(INFO, currMessage)
}
// Debug emits a debug message.
func Debug(format string, args ...interface{}) {
do(DEBUG, format, args...)
}
// Info emits an informative message.
func Info(format string, args ...interface{}) {
do(INFO, format, args...)
}
// Important emits an important informative message.
func Important(format string, args ...interface{}) {
do(IMPORTANT, format, args...)
}
// Warning emits a warning message.
func Warning(format string, args ...interface{}) {
do(WARNING, format, args...)
}
// Error emits an error message.
func Error(format string, args ...interface{}) {
do(ERROR, format, args...)
}
// Fatal emits a fatal error message and calls the log.OnFatal callback.
func Fatal(format string, args ...interface{}) {
do(FATAL, format, args...)
OnFatal()
}
|