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 }