github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/zlog/dynamic_level.go (about) 1 package zlog 2 3 import ( 4 "fmt" 5 "strings" 6 7 "go.uber.org/zap/zapcore" 8 ) 9 10 type dynamicLevelCore struct { 11 zapcore.Core 12 baseLevel zapcore.LevelEnabler 13 dynLevel *Level 14 levelFunc perLoggerLevelFunc 15 } 16 17 type perLoggerLevelFunc func(name string) (Level, bool) 18 19 func buildPerLoggerLevelFunc(levelRules []string) (perLoggerLevelFunc, error) { 20 if len(levelRules) == 0 { 21 return nil, nil 22 } 23 tree := &radixTree[Level]{} 24 for _, rule := range levelRules { 25 tmp := strings.Split(rule, "=") 26 if len(tmp) != 2 { 27 return nil, fmt.Errorf("invalid per logger level rule: %s", rule) 28 } 29 loggerName, levelName := tmp[0], tmp[1] 30 var level Level 31 if !unmarshalLevel(&level, levelName) { 32 return nil, fmt.Errorf("unrecognized level: %s", levelName) 33 } 34 tree.root.insert(loggerName, level) 35 } 36 return tree.search, nil 37 } 38 39 func (c *dynamicLevelCore) Enabled(level zapcore.Level) bool { 40 // Dynamic level takes higher priority. 41 if c.dynLevel != nil { 42 return c.dynLevel.Enabled(level) 43 } 44 // If per logger level func is configured, leave the filtering work to c.Check. 45 if c.levelFunc != nil { 46 return true 47 } 48 return c.baseLevel.Enabled(level) 49 } 50 51 func (c *dynamicLevelCore) With(fields []zapcore.Field) zapcore.Core { 52 clone := c.clone() 53 clone.Core = clone.Core.With(fields) 54 return clone 55 } 56 57 func (c *dynamicLevelCore) Check(entry zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { 58 var entryLevel = entry.Level 59 60 // Dynamic level takes higher priority. 61 if c.dynLevel != nil { 62 if *c.dynLevel > entryLevel { 63 return ce 64 } 65 return c.Core.Check(entry, ce) 66 } 67 68 // Check per logger levels. 69 if c.levelFunc != nil && entry.LoggerName != "" { 70 level, found := c.levelFunc(entry.LoggerName) 71 if found { 72 if level > entryLevel { 73 return ce 74 } 75 return c.Core.Check(entry, ce) 76 } 77 } 78 79 // Check the configured base level. 80 if !c.baseLevel.Enabled(entry.Level) { 81 return ce 82 } 83 return c.Core.Check(entry, ce) 84 } 85 86 func (c *dynamicLevelCore) clone() *dynamicLevelCore { 87 return &dynamicLevelCore{ 88 Core: c.Core, 89 baseLevel: c.baseLevel, 90 dynLevel: c.dynLevel, 91 levelFunc: c.levelFunc, 92 } 93 } 94 95 func (c *dynamicLevelCore) changeLevel(level Level) *dynamicLevelCore { 96 if c.dynLevel != nil && *c.dynLevel == level { 97 return c 98 } 99 100 clone := c.clone() 101 clone.dynLevel = &level 102 return clone 103 } 104 105 func changeLevel(level Level) func(zapcore.Core) zapcore.Core { 106 return func(core zapcore.Core) zapcore.Core { 107 if dyn, ok := core.(*dynamicLevelCore); ok { 108 return dyn.changeLevel(level) 109 } 110 return &dynamicLevelCore{ 111 Core: core, 112 baseLevel: level, 113 dynLevel: &level, 114 } 115 } 116 } 117 118 // for testing 119 func unwrapDynamicLevelCore(core zapcore.Core) zapcore.Core { 120 for { 121 wrapped, ok := core.(*dynamicLevelCore) 122 if !ok { 123 return core 124 } 125 core = wrapped.Core 126 } 127 }