handlersmisc.go - hugo - [fork] hugo port for 9front
 (HTM) git clone https://git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       handlersmisc.go (3439B)
       ---
            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/gohugoio/hugo/common/hashing"
           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)
           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 := hashing.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 }