codeberg.org/gruf/go-log@v1.0.6-0.20231202001801-031c3d3d089b/log.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "io" 6 "log" 7 "sync/atomic" 8 _ "unsafe" 9 10 "codeberg.org/gruf/go-byteutil" 11 "codeberg.org/gruf/go-kv" 12 ) 13 14 // stdflags are the log flags we use as a base for all Logger instances. 15 const stdflags = log.Ldate | log.Ltime 16 17 // Logger wraps the stdlib log.Logger to provided levelled logging. 18 type Logger struct { 19 log *log.Logger // underlying standard lib logger 20 lvl uint32 // currently set log level 21 min uint8 // minimum call depth (used by global logger) 22 } 23 24 // New returns a new instance of Logger writing to given output. A 25 // minimum call depth may be specified to skip caller frames in caller info. 26 func New(w io.Writer, min uint8) *Logger { 27 return NewFrom(log.New(w, "", stdflags), 1) 28 } 29 30 // NewFrom returns a new instance of Logger wrapping the provided standard library 31 // logger. A minimum call depth may be specified to skip caller frames in caller info. 32 func NewFrom(log *log.Logger, min uint8) *Logger { 33 return &Logger{ 34 log: log, 35 lvl: uint32(ALL), 36 min: min, 37 } 38 } 39 40 func (l *Logger) Debug(a ...interface{}) { 41 l.Log(2, DEBUG, a...) 42 } 43 44 func (l *Logger) Debugf(s string, a ...interface{}) { 45 l.Logf(2, DEBUG, s, a...) 46 } 47 48 func (l *Logger) DebugFields(fields ...kv.Field) { 49 l.LogFields(2, DEBUG, fields...) 50 } 51 52 func (l *Logger) Info(a ...interface{}) { 53 l.Log(2, INFO, a...) 54 } 55 56 func (l *Logger) Infof(s string, a ...interface{}) { 57 l.Logf(2, INFO, s, a...) 58 } 59 60 func (l *Logger) InfoFields(fields ...kv.Field) { 61 l.LogFields(2, INFO, fields...) 62 } 63 64 func (l *Logger) Warn(a ...interface{}) { 65 l.Log(2, WARN, a...) 66 } 67 68 func (l *Logger) Warnf(s string, a ...interface{}) { 69 l.Logf(2, WARN, s, a...) 70 } 71 72 func (l *Logger) WarnFields(fields ...kv.Field) { 73 l.LogFields(2, WARN, fields...) 74 } 75 76 func (l *Logger) Error(a ...interface{}) { 77 l.Log(2, ERROR, a...) 78 } 79 80 func (l *Logger) Errorf(s string, a ...interface{}) { 81 l.Logf(2, ERROR, s, a...) 82 } 83 84 func (l *Logger) ErrorFields(fields ...kv.Field) { 85 l.LogFields(2, ERROR, fields...) 86 } 87 88 func (l *Logger) Panic(a ...interface{}) { 89 str := fmt.Sprint(a...) 90 l.Log(2, PANIC, str) 91 panic(str) 92 } 93 94 func (l *Logger) Panicf(s string, a ...interface{}) { 95 str := fmt.Sprintf(s, a...) 96 l.Log(2, PANIC, str) 97 panic(str) 98 } 99 100 func (l *Logger) PanicFields(fields ...kv.Field) { 101 str := kv.Fields(fields).String() 102 l.Log(2, PANIC, str) 103 panic(str) 104 } 105 106 // Log calls underlying stdlib log.Logger.Output() to print to the logger with level. Arguments are handled in the manner of fmt.Print. 107 func (l *Logger) Log(calldepth int, lvl LEVEL, a ...interface{}) { 108 if lvl > l.Level() { 109 return // no output 110 } 111 log_output(l.log, 0, int(l.min)+calldepth+1, func(b []byte) []byte { 112 b = append(b, "["+levels[lvl]+"] "...) 113 b = fmt.Append(b, a...) 114 return b 115 }) 116 } 117 118 // Logf calls underlying stdlib log.Logger.Output() to print to the logger with level. Arguments are handled in the manner of fmt.Printf. 119 func (l *Logger) Logf(calldepth int, lvl LEVEL, s string, a ...interface{}) { 120 if lvl > l.Level() { 121 return // no output 122 } 123 log_output(l.log, 0, int(l.min)+calldepth+1, func(b []byte) []byte { 124 b = append(b, "["+levels[lvl]+"] "...) 125 b = fmt.Appendf(b, s, a...) 126 return b 127 }) 128 } 129 130 // Logf calls underlying stdlib log.Logger.Output() to print to the logger with level. Arguments formatted using fv.Fields{}.String(). 131 func (l *Logger) LogFields(calldepth int, lvl LEVEL, fields ...kv.Field) { 132 if lvl > l.Level() { 133 return // no output 134 } 135 log_output(l.log, 0, int(l.min)+calldepth+1, func(b []byte) []byte { 136 buf := byteutil.Buffer{B: b} 137 buf.B = append(buf.B, "["+levels[lvl]+"] "...) 138 kv.Fields(fields).AppendFormat(&buf, false) 139 return buf.B 140 }) 141 } 142 143 // Print calls underlying stdlib log.Logger.Output() to print to the logger. Arguments are handled in the manner of fmt.Print. 144 func (l *Logger) Print(a ...interface{}) { 145 log_output(l.log, 0, int(l.min)+2, func(b []byte) []byte { 146 return fmt.Append(b, a...) 147 }) 148 } 149 150 // Printf calls underlying stdlib log.Logger.Output() to print to the logger. Arguments are handled in the manner of fmt.Printf. 151 func (l *Logger) Printf(s string, a ...interface{}) { 152 log_output(l.log, 0, int(l.min)+2, func(b []byte) []byte { 153 return fmt.Appendf(b, s, a...) 154 }) 155 } 156 157 // PrintFields calls underlying stdlib log.Logger.Output() to print to the logger. Arguments formatted using fv.Fields{}.String(). 158 func (l *Logger) PrintFields(fields ...kv.Field) { 159 log_output(l.log, 0, int(l.min)+2, func(b []byte) []byte { 160 buf := byteutil.Buffer{B: b} 161 kv.Fields(fields).AppendFormat(&buf, false) 162 return buf.B 163 }) 164 } 165 166 // Level returns the minimum logging level for the logger. 167 func (l *Logger) Level() LEVEL { 168 return LEVEL(atomic.LoadUint32(&l.lvl)) 169 } 170 171 // SetLevel sets the minimum logging level for the logger. 172 func (l *Logger) SetLevel(lvl LEVEL) { 173 atomic.StoreUint32(&l.lvl, uint32(lvl)) 174 } 175 176 // IncludeCaller returns whether 'IncludeCaller' is enabled. 177 func (l *Logger) IncludeCaller() bool { 178 return l.log.Flags()&log.Llongfile != 0 179 } 180 181 // SetIncludeCaller enables/disbables logging with added caller information. 182 func (l *Logger) SetIncludeCaller(enabled bool) { 183 flags := stdflags 184 if enabled { 185 flags |= log.Llongfile 186 } 187 l.log.SetFlags(flags) 188 } 189 190 // SetOutput sets the output destination for the logger. 191 func (l *Logger) SetOutput(out io.Writer) { 192 l.log.SetOutput(out) 193 } 194 195 // Logger returns the underlying stdlib log.Logger. 196 func (l *Logger) Logger() *log.Logger { 197 return l.log 198 } 199 200 //go:linkname log_output log.(*Logger).output 201 func log_output(l *log.Logger, pc uintptr, calldepth int, appendOutput func([]byte) []byte) error