github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/common/loggers/logger.go (about) 1 // Copyright 2023 The Hugo Authors. All rights reserved. 2 // Some functions in this file (see comments) is based on the Go source code, 3 // copyright The Go Authors and governed by a BSD-style license. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package loggers 17 18 import ( 19 "fmt" 20 "io" 21 "os" 22 "strings" 23 "time" 24 25 "github.com/bep/logg" 26 "github.com/bep/logg/handlers/multi" 27 "github.com/gohugoio/hugo/common/terminal" 28 ) 29 30 var ( 31 reservedFieldNamePrefix = "__h_field_" 32 // FieldNameCmd is the name of the field that holds the command name. 33 FieldNameCmd = reservedFieldNamePrefix + "_cmd" 34 // Used to suppress statements. 35 FieldNameStatementID = reservedFieldNamePrefix + "__h_field_statement_id" 36 ) 37 38 // Options defines options for the logger. 39 type Options struct { 40 Level logg.Level 41 Stdout io.Writer 42 Stderr io.Writer 43 Distinct bool 44 StoreErrors bool 45 HandlerPost func(e *logg.Entry) error 46 SuppressStatements map[string]bool 47 } 48 49 // New creates a new logger with the given options. 50 func New(opts Options) Logger { 51 if opts.Stdout == nil { 52 opts.Stdout = os.Stdout 53 } 54 if opts.Stderr == nil { 55 opts.Stderr = os.Stdout 56 } 57 if opts.Level == 0 { 58 opts.Level = logg.LevelWarn 59 } 60 61 var logHandler logg.Handler 62 if terminal.PrintANSIColors(os.Stdout) { 63 logHandler = newDefaultHandler(opts.Stdout, opts.Stderr) 64 } else { 65 logHandler = newNoColoursHandler(opts.Stdout, opts.Stderr, false, nil) 66 } 67 68 errorsw := &strings.Builder{} 69 logCounters := newLogLevelCounter() 70 handlers := []logg.Handler{ 71 whiteSpaceTrimmer(), 72 logHandler, 73 logCounters, 74 } 75 76 if opts.HandlerPost != nil { 77 var hookHandler logg.HandlerFunc = func(e *logg.Entry) error { 78 opts.HandlerPost(e) 79 return nil 80 } 81 handlers = append(handlers, hookHandler) 82 } 83 84 if opts.StoreErrors { 85 h := newNoColoursHandler(io.Discard, errorsw, true, func(e *logg.Entry) bool { 86 return e.Level >= logg.LevelError 87 }) 88 89 handlers = append(handlers, h) 90 } 91 92 logHandler = multi.New(handlers...) 93 94 var logOnce *logOnceHandler 95 if opts.Distinct { 96 logOnce = newLogOnceHandler(logg.LevelWarn) 97 logHandler = newStopHandler(logOnce, logHandler) 98 } 99 100 if opts.SuppressStatements != nil && len(opts.SuppressStatements) > 0 { 101 logHandler = newStopHandler(newSuppressStatementsHandler(opts.SuppressStatements), logHandler) 102 } 103 104 logger := logg.New( 105 logg.Options{ 106 Level: opts.Level, 107 Handler: logHandler, 108 }, 109 ) 110 111 l := logger.WithLevel(opts.Level) 112 113 reset := func() { 114 logCounters.mu.Lock() 115 defer logCounters.mu.Unlock() 116 logCounters.counters = make(map[logg.Level]int) 117 errorsw.Reset() 118 if logOnce != nil { 119 logOnce.reset() 120 } 121 } 122 123 return &logAdapter{ 124 logCounters: logCounters, 125 errors: errorsw, 126 reset: reset, 127 out: opts.Stdout, 128 level: opts.Level, 129 logger: logger, 130 debugl: l.WithLevel(logg.LevelDebug), 131 infol: l.WithLevel(logg.LevelInfo), 132 warnl: l.WithLevel(logg.LevelWarn), 133 errorl: l.WithLevel(logg.LevelError), 134 } 135 } 136 137 // NewDefault creates a new logger with the default options. 138 func NewDefault() Logger { 139 opts := Options{ 140 Distinct: true, 141 Level: logg.LevelWarn, 142 Stdout: os.Stdout, 143 Stderr: os.Stdout, 144 } 145 return New(opts) 146 } 147 148 func LevelLoggerToWriter(l logg.LevelLogger) io.Writer { 149 return logWriter{l: l} 150 } 151 152 type Logger interface { 153 Debugf(format string, v ...any) 154 Debugln(v ...any) 155 Error() logg.LevelLogger 156 Errorf(format string, v ...any) 157 Errorln(v ...any) 158 Errors() string 159 Errorsf(id, format string, v ...any) 160 Info() logg.LevelLogger 161 InfoCommand(command string) logg.LevelLogger 162 Infof(format string, v ...any) 163 Infoln(v ...any) 164 Level() logg.Level 165 LoggCount(logg.Level) int 166 Logger() logg.Logger 167 Out() io.Writer 168 Printf(format string, v ...any) 169 Println(v ...any) 170 PrintTimerIfDelayed(start time.Time, name string) 171 Reset() 172 Warn() logg.LevelLogger 173 WarnCommand(command string) logg.LevelLogger 174 Warnf(format string, v ...any) 175 Warnln(v ...any) 176 Deprecatef(fail bool, format string, v ...any) 177 } 178 179 type logAdapter struct { 180 logCounters *logLevelCounter 181 errors *strings.Builder 182 reset func() 183 out io.Writer 184 level logg.Level 185 logger logg.Logger 186 debugl logg.LevelLogger 187 infol logg.LevelLogger 188 warnl logg.LevelLogger 189 errorl logg.LevelLogger 190 } 191 192 func (l *logAdapter) Debugf(format string, v ...any) { 193 l.debugl.Logf(format, v...) 194 } 195 196 func (l *logAdapter) Debugln(v ...any) { 197 l.debugl.Logf(l.sprint(v...)) 198 } 199 200 func (l *logAdapter) Info() logg.LevelLogger { 201 return l.infol 202 } 203 204 func (l *logAdapter) InfoCommand(command string) logg.LevelLogger { 205 return l.infol.WithField(FieldNameCmd, command) 206 } 207 208 func (l *logAdapter) Infof(format string, v ...any) { 209 l.infol.Logf(format, v...) 210 } 211 212 func (l *logAdapter) Infoln(v ...any) { 213 l.infol.Logf(l.sprint(v...)) 214 } 215 216 func (l *logAdapter) Level() logg.Level { 217 return l.level 218 } 219 220 func (l *logAdapter) LoggCount(level logg.Level) int { 221 l.logCounters.mu.RLock() 222 defer l.logCounters.mu.RUnlock() 223 return l.logCounters.counters[level] 224 } 225 226 func (l *logAdapter) Logger() logg.Logger { 227 return l.logger 228 } 229 230 func (l *logAdapter) Out() io.Writer { 231 return l.out 232 } 233 234 // PrintTimerIfDelayed prints a time statement to the FEEDBACK logger 235 // if considerable time is spent. 236 func (l *logAdapter) PrintTimerIfDelayed(start time.Time, name string) { 237 elapsed := time.Since(start) 238 milli := int(1000 * elapsed.Seconds()) 239 if milli < 500 { 240 return 241 } 242 l.Printf("%s in %v ms", name, milli) 243 } 244 245 func (l *logAdapter) Printf(format string, v ...any) { 246 // Add trailing newline if not present. 247 if !strings.HasSuffix(format, "\n") { 248 format += "\n" 249 } 250 fmt.Fprintf(l.out, format, v...) 251 } 252 253 func (l *logAdapter) Println(v ...any) { 254 fmt.Fprintln(l.out, v...) 255 } 256 257 func (l *logAdapter) Reset() { 258 l.reset() 259 } 260 261 func (l *logAdapter) Warn() logg.LevelLogger { 262 return l.warnl 263 } 264 265 func (l *logAdapter) Warnf(format string, v ...any) { 266 l.warnl.Logf(format, v...) 267 } 268 269 func (l *logAdapter) WarnCommand(command string) logg.LevelLogger { 270 return l.warnl.WithField(FieldNameCmd, command) 271 } 272 273 func (l *logAdapter) Warnln(v ...any) { 274 l.warnl.Logf(l.sprint(v...)) 275 } 276 277 func (l *logAdapter) Error() logg.LevelLogger { 278 return l.errorl 279 } 280 281 func (l *logAdapter) Errorf(format string, v ...any) { 282 l.errorl.Logf(format, v...) 283 } 284 285 func (l *logAdapter) Errorln(v ...any) { 286 l.errorl.Logf(l.sprint(v...)) 287 } 288 289 func (l *logAdapter) Errors() string { 290 return l.errors.String() 291 } 292 293 func (l *logAdapter) Errorsf(id, format string, v ...any) { 294 l.errorl.WithField(FieldNameStatementID, id).Logf(format, v...) 295 } 296 297 func (l *logAdapter) sprint(v ...any) string { 298 return strings.TrimRight(fmt.Sprintln(v...), "\n") 299 } 300 301 func (l *logAdapter) Deprecatef(fail bool, format string, v ...any) { 302 format = "DEPRECATED: " + format 303 if fail { 304 l.errorl.Logf(format, v...) 305 } else { 306 l.warnl.Logf(format, v...) 307 } 308 } 309 310 type logWriter struct { 311 l logg.LevelLogger 312 } 313 314 func (w logWriter) Write(p []byte) (n int, err error) { 315 w.l.Log(logg.String(string(p))) 316 return len(p), nil 317 }