github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/log/timed_level.go (about)

     1  package log
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"time"
     7  )
     8  
     9  // LevelSetter is a function that sets the log-level.
    10  type LevelSetter func(ctx context.Context, logLevel string)
    11  
    12  // TimedLevel is an object capable of setting a log-level for a given time
    13  // period and then resetting it to a default.
    14  type TimedLevel interface {
    15  	sync.Locker
    16  
    17  	// Get returns the current level and the time left until that level
    18  	// is reset to default. An empty string and zero is returned if
    19  	// no level has been set or if it has expired already.
    20  	Get() (string, time.Duration)
    21  
    22  	// Set sets a new log-level that will be active for the given duration. If the
    23  	// duration is zero, then the log-level will be active until the next call to
    24  	// Set. If level is the empty string, then duration is ignored and the log-level
    25  	// will be reset to default.
    26  	Set(ctx context.Context, level string, duration time.Duration)
    27  
    28  	// Reset restores the log-level to its default value
    29  	Reset(ctx context.Context)
    30  }
    31  
    32  type timedLevel struct {
    33  	sync.Mutex
    34  	setter       LevelSetter
    35  	tempLevel    string
    36  	defaultLevel string
    37  	timer        *time.Timer
    38  	expires      *time.Time
    39  }
    40  
    41  // NewTimedLevel returns a new TimedLevel for the given default level and setter.
    42  func NewTimedLevel(defaultLevel string, setter LevelSetter) TimedLevel {
    43  	return &timedLevel{
    44  		setter:       setter,
    45  		defaultLevel: defaultLevel,
    46  	}
    47  }
    48  
    49  func (tl *timedLevel) Get() (string, time.Duration) {
    50  	tl.Lock()
    51  	defer tl.Unlock()
    52  	if tl.tempLevel == "" || tl.expires == nil {
    53  		return tl.tempLevel, 0
    54  	}
    55  	remain := time.Until(*tl.expires)
    56  	if remain <= 0 {
    57  		return "", 0
    58  	}
    59  	return tl.tempLevel, remain
    60  }
    61  
    62  func (tl *timedLevel) Set(ctx context.Context, level string, duration time.Duration) {
    63  	if level == "" {
    64  		tl.Reset(ctx)
    65  		return
    66  	}
    67  
    68  	tl.Lock()
    69  	defer tl.Unlock()
    70  
    71  	if tl.timer != nil {
    72  		tl.timer.Stop()
    73  	}
    74  
    75  	tl.setter(ctx, level)
    76  	tl.tempLevel = level
    77  	if duration == 0 {
    78  		tl.expires = nil
    79  		tl.timer = nil
    80  		return
    81  	}
    82  
    83  	exTime := time.Now().Add(duration)
    84  	tl.expires = &exTime
    85  	if tl.timer == nil {
    86  		tl.timer = time.AfterFunc(duration, func() {
    87  			tl.Reset(ctx)
    88  		})
    89  	} else {
    90  		tl.timer.Reset(duration)
    91  	}
    92  }
    93  
    94  // Reset restores the log-level to its default value.
    95  func (tl *timedLevel) Reset(ctx context.Context) {
    96  	tl.Lock()
    97  	defer tl.Unlock()
    98  	tl.expires = nil
    99  	tl.tempLevel = ""
   100  	tl.setter(ctx, tl.defaultLevel)
   101  }