github.com/neohugo/neohugo@v0.123.8/common/loggers/handlersmisc.go (about) 1 // Copyright 2024 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 "strings" 21 "sync" 22 23 "github.com/bep/logg" 24 "github.com/neohugo/neohugo/identity" 25 ) 26 27 // PanicOnWarningHook panics on warnings. 28 var PanicOnWarningHook = func(e *logg.Entry) error { 29 if e.Level != logg.LevelWarn { 30 return nil 31 } 32 panic(e.Message) //nolint 33 } 34 35 func newLogLevelCounter() *logLevelCounter { 36 return &logLevelCounter{ 37 counters: make(map[logg.Level]int), 38 } 39 } 40 41 func newLogOnceHandler(threshold logg.Level) *logOnceHandler { 42 return &logOnceHandler{ 43 threshold: threshold, 44 seen: make(map[uint64]bool), 45 } 46 } 47 48 func newStopHandler(h ...logg.Handler) *stopHandler { 49 return &stopHandler{ 50 handlers: h, 51 } 52 } 53 54 func newSuppressStatementsHandler(statements map[string]bool) *suppressStatementsHandler { 55 return &suppressStatementsHandler{ 56 statements: statements, 57 } 58 } 59 60 type logLevelCounter struct { 61 mu sync.RWMutex 62 counters map[logg.Level]int 63 } 64 65 func (h *logLevelCounter) HandleLog(e *logg.Entry) error { 66 h.mu.Lock() 67 defer h.mu.Unlock() 68 h.counters[e.Level]++ 69 return nil 70 } 71 72 var errStop = fmt.Errorf("stop") 73 74 type logOnceHandler struct { 75 threshold logg.Level 76 mu sync.Mutex 77 seen map[uint64]bool 78 } 79 80 func (h *logOnceHandler) HandleLog(e *logg.Entry) error { 81 if e.Level < h.threshold { 82 // We typically only want to enable this for warnings and above. 83 // The common use case is that many go routines may log the same error. 84 return nil 85 } 86 h.mu.Lock() 87 defer h.mu.Unlock() 88 hash := identity.HashUint64(e.Level, e.Message, e.Fields) 89 if h.seen[hash] { 90 return errStop 91 } 92 h.seen[hash] = true 93 return nil 94 } 95 96 func (h *logOnceHandler) reset() { 97 h.mu.Lock() 98 defer h.mu.Unlock() 99 h.seen = make(map[uint64]bool) 100 } 101 102 type stopHandler struct { 103 handlers []logg.Handler 104 } 105 106 // HandleLog implements logg.Handler. 107 func (h *stopHandler) HandleLog(e *logg.Entry) error { 108 for _, handler := range h.handlers { 109 if err := handler.HandleLog(e); err != nil { 110 if err == errStop { 111 return nil 112 } 113 return err 114 } 115 } 116 return nil 117 } 118 119 type suppressStatementsHandler struct { 120 statements map[string]bool 121 } 122 123 func (h *suppressStatementsHandler) HandleLog(e *logg.Entry) error { 124 for _, field := range e.Fields { 125 if field.Name == FieldNameStatementID { 126 if h.statements[field.Value.(string)] { 127 return errStop 128 } 129 } 130 } 131 return nil 132 } 133 134 // whiteSpaceTrimmer creates a new log handler that trims whitespace from log messages and string fields. 135 func whiteSpaceTrimmer() logg.Handler { 136 return logg.HandlerFunc(func(e *logg.Entry) error { 137 e.Message = strings.TrimSpace(e.Message) 138 for i, field := range e.Fields { 139 if s, ok := field.Value.(string); ok { 140 e.Fields[i].Value = strings.TrimSpace(s) 141 } 142 } 143 return nil 144 }) 145 }