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  }