go.dedis.ch/onet/v4@v4.0.0-pre1/log/loggers.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "os" 6 7 ct "github.com/daviddengcn/go-colortext" 8 "golang.org/x/xerrors" 9 ) 10 11 // LoggerInfo is a structure that should be used when creating a logger. 12 // It contains parameters about how to log (with time, colors, ...) and 13 // embeds the Logger interface, which should define how the logger should log. 14 type LoggerInfo struct { 15 // These are information-debugging levels that can be turned on or off. 16 // Every logging greater than 'debugLvl' will be discarded . So you can 17 // Log at different levels and easily turn on or off the amount of logging 18 // generated by adjusting the 'debugLvl' variable. 19 DebugLvl int 20 // If 'showTime' is true, it will print the time for each line displayed 21 // by the logger. 22 ShowTime bool 23 // If 'AbsoluteFilePath' is true, it will print the absolute file path 24 // instead of the base. 25 AbsoluteFilePath bool 26 // If 'useColors' is true, logs will be colored (defaults to monochrome 27 // output). It also controls padding, since colorful output is higly 28 // correlated with humans who like their log lines padded. 29 UseColors bool 30 // If 'padding' is true, it will nicely pad the line that is written. 31 Padding bool 32 } 33 34 // Logger is the interface that specifies how loggers 35 // will receive and display messages. 36 type Logger interface { 37 Log(level int, msg string) 38 Close() 39 GetLoggerInfo() *LoggerInfo 40 } 41 42 const ( 43 // DefaultStdDebugLvl is the default debug level for the standard logger 44 DefaultStdDebugLvl = 1 45 // DefaultStdShowTime is the default value for 'showTime' for the standard logger 46 DefaultStdShowTime = false 47 // DefaultStdAbsoluteFilePath is the default to show absolute path for the standard logger 48 DefaultStdAbsoluteFilePath = false 49 // DefaultStdUseColors is the default value for 'useColors' for the standard logger 50 DefaultStdUseColors = false 51 // DefaultStdPadding is the default value for 'padding' for the standard logger 52 DefaultStdPadding = true 53 ) 54 55 var ( 56 // concurrent access is protected by debugMut 57 loggers = make(map[int]Logger) 58 loggersCounter int 59 ) 60 61 // RegisterLogger will register a callback that will receive a copy of every 62 // message, fully formatted. It returns the key assigned to the logger (used 63 // to unregister the logger). 64 func RegisterLogger(l Logger) int { 65 debugMut.Lock() 66 defer debugMut.Unlock() 67 key := loggersCounter 68 loggers[key] = l 69 loggersCounter++ 70 return key 71 } 72 73 // UnregisterLogger takes the key it was assigned and returned by 74 // 'RegisterLogger', closes the corresponding Logger and removes it from the 75 // loggers. 76 func UnregisterLogger(key int) { 77 debugMut.Lock() 78 defer debugMut.Unlock() 79 if l, ok := loggers[key]; ok { 80 l.Close() 81 delete(loggers, key) 82 } 83 } 84 85 type fileLogger struct { 86 lInfo *LoggerInfo 87 file *os.File 88 } 89 90 func (fl *fileLogger) Log(level int, msg string) { 91 if _, err := fl.file.WriteString(msg); err != nil { 92 panic(err) 93 } 94 } 95 96 func (fl *fileLogger) Close() { 97 fl.file.Close() 98 } 99 100 func (fl *fileLogger) GetLoggerInfo() *LoggerInfo { 101 return fl.lInfo 102 } 103 104 // NewFileLogger creates a logger that writes into the file with 105 // the given path and is using the given LoggerInfo. 106 // It returns the logger. 107 func NewFileLogger(lInfo *LoggerInfo, path string) (Logger, error) { 108 // Override file if it already exists. 109 file, err := os.Create(path) 110 if err != nil { 111 return nil, xerrors.Errorf("creating file: %v", err) 112 } 113 return &fileLogger{ 114 lInfo: lInfo, 115 file: file, 116 }, nil 117 } 118 119 type stdLogger struct { 120 lInfo *LoggerInfo 121 } 122 123 func (sl *stdLogger) Log(lvl int, msg string) { 124 if sl.lInfo.UseColors { 125 bright := lvl < 0 126 lvlAbs := lvl 127 if bright { 128 lvlAbs *= -1 129 } 130 131 switch lvl { 132 case lvlPrint: 133 ct.Foreground(ct.White, true) 134 case lvlInfo: 135 ct.Foreground(ct.White, true) 136 case lvlWarning: 137 ct.Foreground(ct.Green, true) 138 case lvlError: 139 ct.Foreground(ct.Red, false) 140 case lvlFatal: 141 ct.Foreground(ct.Red, true) 142 case lvlPanic: 143 ct.Foreground(ct.Red, true) 144 default: 145 if lvl != 0 { 146 if lvlAbs <= 5 { 147 colors := []ct.Color{ct.Yellow, ct.Cyan, ct.Green, ct.Blue, ct.Cyan} 148 ct.Foreground(colors[lvlAbs-1], bright) 149 } 150 } 151 } 152 } 153 154 if lvl < lvlInfo { 155 fmt.Fprint(stdErr, msg) 156 } else { 157 fmt.Fprint(stdOut, msg) 158 } 159 160 if sl.lInfo.UseColors { 161 ct.ResetColor() 162 } 163 } 164 165 func (sl *stdLogger) Close() {} 166 167 func (sl *stdLogger) GetLoggerInfo() *LoggerInfo { 168 return sl.lInfo 169 } 170 171 // Not public + not taking a LoggerInfo as argument because we don't want 172 // multiple stdLoggers. 173 func newStdLogger() (Logger, error) { 174 lInfo := &LoggerInfo{ 175 DebugLvl: DefaultStdDebugLvl, 176 UseColors: DefaultStdUseColors, 177 ShowTime: DefaultStdShowTime, 178 AbsoluteFilePath: DefaultStdAbsoluteFilePath, 179 Padding: DefaultStdPadding, 180 } 181 return &stdLogger{lInfo: lInfo}, nil 182 }