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  }