github.com/GoogleCloudPlatform/testgrid@v0.0.174/util/metrics/metrics.go (about)

     1  /*
     2  Copyright 2021 The TestGrid Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package metrics provides metric reporting for TestGrid components.
    18  package metrics
    19  
    20  import "time"
    21  
    22  // Metric contains common metric functions.
    23  type Metric interface {
    24  	Name() string
    25  }
    26  
    27  // Int64 is an int64 metric.
    28  type Int64 interface {
    29  	Metric
    30  	Set(int64, ...string)
    31  }
    32  
    33  // Counter is a strictly-increasing metric.
    34  type Counter interface {
    35  	Metric
    36  	Add(int64, ...string)
    37  }
    38  
    39  // Duration is a metric describing a length of time
    40  type Duration interface {
    41  	Metric
    42  	Set(time.Duration, ...string)
    43  }
    44  
    45  // Factory is a collection of functions that create metrics
    46  type Factory struct {
    47  	NewInt64    func(name, desc string, fields ...string) Int64
    48  	NewCounter  func(name, desc string, fields ...string) Counter
    49  	NewDuration func(name, desc string, fields ...string) Duration
    50  }
    51  
    52  // NewCyclic derives a cycle metric from the given metrics
    53  func (f Factory) NewCyclic(componentName string) Cyclic {
    54  	fields := []string{"component"}
    55  	return Cyclic{
    56  		errors:       f.NewCounter("errors", "Number of failed updates", fields...),
    57  		skips:        f.NewCounter("skips", "Number of skipped updates", fields...),
    58  		successes:    f.NewCounter("successes", "Number of successful updates", fields...),
    59  		cycleSeconds: f.NewDuration("cycle_duration", "Seconds required to complete an update", fields...),
    60  		fields:       []string{componentName},
    61  	}
    62  }
    63  
    64  // Cyclic is a collection of metrics that measures how long a task takes to complete
    65  type Cyclic struct {
    66  	fields       []string
    67  	errors       Counter
    68  	skips        Counter
    69  	successes    Counter
    70  	cycleSeconds Duration
    71  }
    72  
    73  // Start returns a PeriodicReporter that logs metrics when one of its methods are called.
    74  func (p *Cyclic) Start() *CycleReporter {
    75  	if p == nil {
    76  		return nil
    77  	}
    78  	return &CycleReporter{metric: p, when: time.Now()}
    79  }
    80  
    81  // CycleReporter reports the status of the task that spawned it and how long it took.
    82  type CycleReporter struct {
    83  	metric *Cyclic
    84  	when   time.Time
    85  }
    86  
    87  func (pr *CycleReporter) done() {
    88  	if pr == nil || pr.metric.cycleSeconds == nil {
    89  		return
    90  	}
    91  	pr.metric.cycleSeconds.Set(time.Since(pr.when), pr.metric.fields...)
    92  }
    93  
    94  // Success reports success
    95  func (pr *CycleReporter) Success() {
    96  	pr.done()
    97  	if pr == nil || pr.metric.successes == nil {
    98  		return
    99  	}
   100  	pr.metric.successes.Add(1, pr.metric.fields...)
   101  }
   102  
   103  // Fail reports a failure or unexpected error
   104  func (pr *CycleReporter) Fail() {
   105  	pr.done()
   106  	if pr == nil || pr.metric.errors == nil {
   107  		return
   108  	}
   109  	pr.metric.errors.Add(1, pr.metric.fields...)
   110  }
   111  
   112  // Skip reports a cycle that was skipped due to an expected condition, flag, or configuration
   113  func (pr *CycleReporter) Skip() {
   114  	pr.done()
   115  	if pr == nil || pr.metric.skips == nil {
   116  		return
   117  	}
   118  	pr.metric.skips.Add(1, pr.metric.fields...)
   119  }