github.com/rudderlabs/rudder-go-kit@v0.30.0/logger/config.go (about)

     1  package logger
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  
     7  	"go.uber.org/zap/zapcore"
     8  
     9  	"github.com/rudderlabs/rudder-go-kit/config"
    10  )
    11  
    12  // factoryConfig is the configuration for the logger
    13  type factoryConfig struct {
    14  	rootLevel        int                      // the level for the root logger
    15  	enableNameInLog  bool                     // whether to include the logger name in the log message
    16  	enableStackTrace *config.Reloadable[bool] // for fatal logs
    17  
    18  	levelConfig      *syncMap[string, int] // preconfigured log levels for loggers
    19  	levelConfigCache *syncMap[string, int] // cache of all calculated log levels for loggers
    20  
    21  	// zap specific config
    22  	clock zapcore.Clock
    23  }
    24  
    25  // SetLogLevel sets the log level for the given logger name
    26  func (fc *factoryConfig) SetLogLevel(name, levelStr string) error {
    27  	level, ok := levelMap[levelStr]
    28  	if !ok {
    29  		return errors.New("invalid level value : " + levelStr)
    30  	}
    31  	if name == "" {
    32  		fc.rootLevel = level
    33  	} else {
    34  		fc.levelConfig.set(name, level)
    35  	}
    36  	fc.levelConfigCache = newSyncMap[string, int]()
    37  	return nil
    38  }
    39  
    40  // getOrSetLogLevel returns the log level for the given logger name or sets it using the provided function if no level is set
    41  func (fc *factoryConfig) getOrSetLogLevel(name string, parentLevelFunc func() int) int {
    42  	if name == "" {
    43  		return fc.rootLevel
    44  	}
    45  
    46  	if level, found := fc.levelConfigCache.get(name); found {
    47  		return level
    48  	}
    49  	level := func() int { // either get the level from the config or use the parent's level
    50  		if level, ok := fc.levelConfig.get(name); ok {
    51  			return level
    52  		}
    53  		return parentLevelFunc()
    54  	}()
    55  	fc.levelConfigCache.set(name, level) // cache the level
    56  	return level
    57  }
    58  
    59  // newSyncMap creates a new syncMap
    60  func newSyncMap[K comparable, V any]() *syncMap[K, V] {
    61  	return &syncMap[K, V]{m: map[K]V{}}
    62  }
    63  
    64  // syncMap is a thread safe map for getting and setting keys concurrently
    65  type syncMap[K comparable, V any] struct {
    66  	mu sync.RWMutex
    67  	m  map[K]V
    68  }
    69  
    70  func (sm *syncMap[K, V]) get(key K) (V, bool) {
    71  	sm.mu.RLock()
    72  	defer sm.mu.RUnlock()
    73  	v, ok := sm.m[key]
    74  	return v, ok
    75  }
    76  
    77  func (sm *syncMap[K, V]) set(key K, value V) {
    78  	sm.mu.Lock()
    79  	defer sm.mu.Unlock()
    80  	sm.m[key] = value
    81  }