github.com/lyft/flytestdlib@v0.3.12-0.20210213045714-8cdd111ecda1/promutils/labeled/stopwatch.go (about) 1 package labeled 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/lyft/flytestdlib/contextutils" 8 "github.com/lyft/flytestdlib/promutils" 9 ) 10 11 type StopWatch struct { 12 *promutils.StopWatchVec 13 14 // We use SummaryVec for emitting StopWatchVec, this computes percentiles per metric tags combination on the client- 15 // side. This makes it impossible to aggregate percentiles across tags (e.g. to have system-wide view). When enabled 16 // through a flag in the constructor, we initialize this additional untagged stopwatch to compute percentiles 17 // across tags. 18 promutils.StopWatch 19 20 additionalLabels []contextutils.Key 21 } 22 23 // Start creates a new Instance of the StopWatch called a Timer that is closeable/stoppable. 24 // Common pattern to time a scope would be 25 // { 26 // timer := stopWatch.Start(ctx) 27 // defer timer.Stop() 28 // .... 29 // } 30 func (c StopWatch) Start(ctx context.Context) Timer { 31 w, err := c.StopWatchVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, c.additionalLabels...)...)) 32 if err != nil { 33 panic(err.Error()) 34 } 35 36 if c.StopWatch.Observer == nil { 37 return w.Start() 38 } 39 40 return timer{ 41 Timers: []Timer{ 42 w.Start(), 43 c.StopWatch.Start(), 44 }, 45 } 46 } 47 48 // Observes specified duration between the start and end time. The data point will be labeled with values from context. 49 // See labeled.SetMetricsKeys for information about to configure that. 50 func (c StopWatch) Observe(ctx context.Context, start, end time.Time) { 51 w, err := c.StopWatchVec.GetMetricWith(contextutils.Values(ctx, append(metricKeys, c.additionalLabels...)...)) 52 if err != nil { 53 panic(err.Error()) 54 } 55 w.Observe(start, end) 56 57 if c.StopWatch.Observer != nil { 58 c.StopWatch.Observe(start, end) 59 } 60 } 61 62 // This method observes the elapsed duration since the creation of the timer. The timer is created using a StopWatch. 63 // The data point will be labeled with values from context. See labeled.SetMetricsKeys for information about to 64 // configure that. 65 func (c StopWatch) Time(ctx context.Context, f func()) { 66 t := c.Start(ctx) 67 f() 68 t.Stop() 69 } 70 71 // Creates a new labeled stopwatch. Label keys must be set before instantiating a counter. See labeled.SetMetricsKeys 72 // for information about to configure that. 73 func NewStopWatch(name, description string, scale time.Duration, scope promutils.Scope, opts ...MetricOption) StopWatch { 74 if len(metricKeys) == 0 { 75 panic(ErrNeverSet) 76 } 77 78 sw := StopWatch{} 79 80 for _, opt := range opts { 81 if _, emitUnableMetric := opt.(EmitUnlabeledMetricOption); emitUnableMetric { 82 sw.StopWatch = scope.MustNewStopWatch(GetUnlabeledMetricName(name), description, scale) 83 } else if additionalLabels, casted := opt.(AdditionalLabelsOption); casted { 84 sw.StopWatchVec = scope.MustNewStopWatchVec(name, description, scale, 85 append(metricStringKeys, additionalLabels.Labels...)...) 86 sw.additionalLabels = contextutils.MetricKeysFromStrings(additionalLabels.Labels) 87 } 88 } 89 90 if sw.StopWatchVec == nil { 91 sw.StopWatchVec = scope.MustNewStopWatchVec(name, description, scale, metricStringKeys...) 92 } 93 94 return sw 95 }