...

Source file src/github.com/emissary-ingress/emissary/v3/pkg/debug/timer.go

Documentation: github.com/emissary-ingress/emissary/v3/pkg/debug

     1  package debug
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"sync"
     8  	"time"
     9  )
    10  
    11  // The Timer struct can be used to time discrete actions. It tracks min, max, average, and total
    12  // elapsed time for all actions. The Timer struct is thread safe, and the Start() method is designed
    13  // to do proper bookkeeping regardless of concurrent use from multiple goroutines.
    14  //
    15  // Example 1
    16  //
    17  //	var GlobalTimer = NewTimer()
    18  //
    19  //	func foo() {
    20  //	  GlobalTimer.Time(func() {
    21  //	    // ...
    22  //	  })
    23  //	}
    24  //
    25  // Example 2
    26  //
    27  //	func foo() {
    28  //	  stop := GlobalTimer.Start()
    29  //	  defer stop()
    30  //	  ...
    31  //	}
    32  //
    33  // Example 3
    34  //
    35  //	func foo() {
    36  //	  defer GlobalTimer.Start()()
    37  //	  ...
    38  //	}
    39  type Timer struct {
    40  	mutex sync.Mutex    // protects the whole struct
    41  	count int           // counts the number of actions that have been timed
    42  	total time.Duration // tracks the total elapsed time for all actions
    43  	min   time.Duration // the max elapsed time for an action
    44  	max   time.Duration // the min elapsed time for an action
    45  
    46  	clock func() time.Time // The clock function used by the timer.
    47  }
    48  
    49  // The type of the clock function to use for timing.
    50  type ClockFunc func() time.Time
    51  
    52  // The type of the function used to stop timing.
    53  type StopFunc func()
    54  
    55  // The NewTimer function creates a new timer. It uses time.Now as the clock for the timer.
    56  func NewTimer() *Timer {
    57  	return NewTimerWithClock(time.Now)
    58  }
    59  
    60  // The NewTimerWithClock function creates a new timer with the given name and clock.
    61  func NewTimerWithClock(clock ClockFunc) *Timer {
    62  	return &Timer{
    63  		clock: clock,
    64  	}
    65  }
    66  
    67  // The Start() method starts timing an action.
    68  func (t *Timer) Start() StopFunc {
    69  	start := t.clock()
    70  	return func() {
    71  		t.record(start, t.clock())
    72  	}
    73  }
    74  
    75  // Records the timing info for an action.
    76  func (t *Timer) record(start time.Time, stop time.Time) {
    77  	t.withMutex(func() {
    78  		delta := stop.Sub(start)
    79  
    80  		if t.count == 0 {
    81  			// Initialize min and max if this is the first event.
    82  			t.min = delta
    83  			t.max = delta
    84  		} else {
    85  			// Update min and max for subsequent events.
    86  			if delta < t.min {
    87  				t.min = delta
    88  			}
    89  			if delta > t.max {
    90  				t.max = delta
    91  			}
    92  		}
    93  
    94  		t.count++
    95  		t.total += delta
    96  	})
    97  }
    98  
    99  // Convenience function for safely accessing the internals of the struct.
   100  func (t *Timer) withMutex(f func()) {
   101  	t.mutex.Lock()
   102  	defer t.mutex.Unlock()
   103  	f()
   104  }
   105  
   106  // The Copy() method returns a copy of the timer. This can be used to get a consistent snapshot of
   107  // all the Count/Min/Max/Average/Total values.
   108  func (t *Timer) Copy() (result *Timer) {
   109  	t.withMutex(func() {
   110  		result = &Timer{}
   111  		*result = *t // nolint:govet // silence complaint about copying t.mutex
   112  		result.mutex = sync.Mutex{}
   113  	})
   114  	return
   115  }
   116  
   117  // The Count() method returns the number of events that have been timed.
   118  func (t *Timer) Count() (result int) {
   119  	t.withMutex(func() {
   120  		result = t.count
   121  	})
   122  	return
   123  }
   124  
   125  // The Min() method retuns the minimum duration of all timed events.
   126  func (t *Timer) Min() (result time.Duration) {
   127  	t.withMutex(func() {
   128  		result = t.min
   129  	})
   130  	return
   131  }
   132  
   133  // The Max() method returns the maximum duration of all timed events.
   134  func (t *Timer) Max() (result time.Duration) {
   135  	t.withMutex(func() {
   136  		result = t.max
   137  	})
   138  	return
   139  }
   140  
   141  // The Average() method returns the average duration of all timed events.
   142  func (t *Timer) Average() (result time.Duration) {
   143  	t.withMutex(func() {
   144  		if t.count > 0 {
   145  			result = t.total / time.Duration(t.count)
   146  		} else {
   147  			result = 0
   148  		}
   149  	})
   150  	return
   151  }
   152  
   153  // The Total() method returns the total duration of all events.
   154  func (t *Timer) Total() (result time.Duration) {
   155  	t.withMutex(func() {
   156  		result = t.total
   157  	})
   158  	return
   159  }
   160  
   161  // The Time() method is a convenience method that times invocation of the supplied function.
   162  func (t *Timer) Time(f func()) {
   163  	defer t.Start()()
   164  	f()
   165  }
   166  
   167  // The TimedHandler() method wraps the supplied Handler with a Handler that times every request.
   168  func (t *Timer) TimedHandler(h http.Handler) http.Handler {
   169  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   170  		defer t.Start()()
   171  		h.ServeHTTP(w, r)
   172  	})
   173  }
   174  
   175  // The TimedHandlerFunc() method wraps the supplied HandlerFunc with a HandlerFunc that times every request.
   176  func (t *Timer) TimedHandlerFunc(h http.HandlerFunc) http.HandlerFunc {
   177  	return func(w http.ResponseWriter, r *http.Request) {
   178  		defer t.Start()()
   179  		h(w, r)
   180  	}
   181  }
   182  
   183  func (t *Timer) MarshalJSON() ([]byte, error) {
   184  	c := t.Copy()
   185  	return json.Marshal(fmt.Sprintf("%d, %s/%s/%s", c.Count(), c.Min().String(), c.Average().String(), c.Max().String()))
   186  }
   187  

View as plain text