github.com/cilium/cilium@v1.16.2/pkg/spanstat/spanstat.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package spanstat
     5  
     6  import (
     7  	"github.com/cilium/cilium/pkg/lock"
     8  	"github.com/cilium/cilium/pkg/logging"
     9  	"github.com/cilium/cilium/pkg/logging/logfields"
    10  	"github.com/cilium/cilium/pkg/safetime"
    11  	"github.com/cilium/cilium/pkg/time"
    12  )
    13  
    14  var (
    15  	subSystem = "spanstat"
    16  	log       = logging.DefaultLogger.WithField(logfields.LogSubsys, subSystem)
    17  )
    18  
    19  // SpanStat measures the total duration of all time spent in between Start()
    20  // and Stop() calls.
    21  type SpanStat struct {
    22  	mutex           lock.RWMutex
    23  	spanStart       time.Time
    24  	successDuration time.Duration
    25  	failureDuration time.Duration
    26  }
    27  
    28  // Start creates a new SpanStat and starts it
    29  func Start() *SpanStat {
    30  	s := &SpanStat{}
    31  	return s.Start()
    32  }
    33  
    34  // Start starts a new span
    35  func (s *SpanStat) Start() *SpanStat {
    36  	s.mutex.Lock()
    37  	defer s.mutex.Unlock()
    38  	s.spanStart = time.Now()
    39  	return s
    40  }
    41  
    42  // EndError calls End() based on the value of err
    43  func (s *SpanStat) EndError(err error) *SpanStat {
    44  	s.mutex.Lock()
    45  	defer s.mutex.Unlock()
    46  	return s.end(err == nil)
    47  }
    48  
    49  // End ends the current span and adds the measured duration to the total
    50  // cumulated duration, and to the success or failure cumulated duration
    51  // depending on the given success flag
    52  func (s *SpanStat) End(success bool) *SpanStat {
    53  	s.mutex.Lock()
    54  	defer s.mutex.Unlock()
    55  	return s.end(success)
    56  }
    57  
    58  // must be called with Lock() held
    59  func (s *SpanStat) end(success bool) *SpanStat {
    60  	if !s.spanStart.IsZero() {
    61  		d, _ := safetime.TimeSinceSafe(s.spanStart, log)
    62  		if success {
    63  			s.successDuration += d
    64  		} else {
    65  			s.failureDuration += d
    66  		}
    67  	}
    68  	s.spanStart = time.Time{}
    69  	return s
    70  }
    71  
    72  // Total returns the total duration of all spans measured, including both
    73  // successes and failures
    74  func (s *SpanStat) Total() time.Duration {
    75  	s.mutex.RLock()
    76  	defer s.mutex.RUnlock()
    77  	return s.successDuration + s.failureDuration
    78  }
    79  
    80  // SuccessTotal returns the total duration of all successful spans measured
    81  func (s *SpanStat) SuccessTotal() time.Duration {
    82  	s.mutex.RLock()
    83  	defer s.mutex.RUnlock()
    84  	return s.successDuration
    85  }
    86  
    87  // FailureTotal returns the total duration of all unsuccessful spans measured
    88  func (s *SpanStat) FailureTotal() time.Duration {
    89  	s.mutex.RLock()
    90  	defer s.mutex.RUnlock()
    91  	return s.failureDuration
    92  }
    93  
    94  // Reset rests the duration measurements
    95  func (s *SpanStat) Reset() {
    96  	s.mutex.Lock()
    97  	defer s.mutex.Unlock()
    98  	s.successDuration = 0
    99  	s.failureDuration = 0
   100  }
   101  
   102  // Seconds returns the number of seconds represents by the spanstat. If a span
   103  // is still open, it is closed first.
   104  func (s *SpanStat) Seconds() float64 {
   105  	s.mutex.Lock()
   106  	defer s.mutex.Unlock()
   107  	if !s.spanStart.IsZero() {
   108  		s.end(true)
   109  	}
   110  
   111  	total := s.successDuration + s.failureDuration
   112  	return total.Seconds()
   113  }