util/metrics/metrics.go (76 lines of code) (raw):
/*
Copyright 2021 The TestGrid Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package metrics provides metric reporting for TestGrid components.
package metrics
import "time"
// Metric contains common metric functions.
type Metric interface {
Name() string
}
// Int64 is an int64 metric.
type Int64 interface {
Metric
Set(int64, ...string)
}
// Counter is a strictly-increasing metric.
type Counter interface {
Metric
Add(int64, ...string)
}
// Duration is a metric describing a length of time
type Duration interface {
Metric
Set(time.Duration, ...string)
}
// Factory is a collection of functions that create metrics
type Factory struct {
NewInt64 func(name, desc string, fields ...string) Int64
NewCounter func(name, desc string, fields ...string) Counter
NewDuration func(name, desc string, fields ...string) Duration
}
// NewCyclic derives a cycle metric from the given metrics
func (f Factory) NewCyclic(componentName string) Cyclic {
fields := []string{"component"}
return Cyclic{
errors: f.NewCounter("errors", "Number of failed updates", fields...),
skips: f.NewCounter("skips", "Number of skipped updates", fields...),
successes: f.NewCounter("successes", "Number of successful updates", fields...),
cycleSeconds: f.NewDuration("cycle_duration", "Seconds required to complete an update", fields...),
fields: []string{componentName},
}
}
// Cyclic is a collection of metrics that measures how long a task takes to complete
type Cyclic struct {
fields []string
errors Counter
skips Counter
successes Counter
cycleSeconds Duration
}
// Start returns a PeriodicReporter that logs metrics when one of its methods are called.
func (p *Cyclic) Start() *CycleReporter {
if p == nil {
return nil
}
return &CycleReporter{metric: p, when: time.Now()}
}
// CycleReporter reports the status of the task that spawned it and how long it took.
type CycleReporter struct {
metric *Cyclic
when time.Time
}
func (pr *CycleReporter) done() {
if pr == nil || pr.metric.cycleSeconds == nil {
return
}
pr.metric.cycleSeconds.Set(time.Since(pr.when), pr.metric.fields...)
}
// Success reports success
func (pr *CycleReporter) Success() {
pr.done()
if pr == nil || pr.metric.successes == nil {
return
}
pr.metric.successes.Add(1, pr.metric.fields...)
}
// Fail reports a failure or unexpected error
func (pr *CycleReporter) Fail() {
pr.done()
if pr == nil || pr.metric.errors == nil {
return
}
pr.metric.errors.Add(1, pr.metric.fields...)
}
// Skip reports a cycle that was skipped due to an expected condition, flag, or configuration
func (pr *CycleReporter) Skip() {
pr.done()
if pr == nil || pr.metric.skips == nil {
return
}
pr.metric.skips.Add(1, pr.metric.fields...)
}