blob: a603a10999000d5c1840f66d63d8107c3115642a [file] [log] [blame]
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package event
import (
"context"
"fmt"
"time"
)
// A Metric represents a kind of recorded measurement.
type Metric interface {
Descriptor() *MetricDescriptor
}
// A MetricDescriptor describes a metric.
type MetricDescriptor struct {
namespace string
name string
description string
// TODO: deal with units. Follow otel, or define Go types for common units.
// We don't need a time unit because we'll use time.Duration, and the only
// other unit otel currently defines (besides dimensionless) is bytes.
}
// NewMetricDescriptor creates a MetricDescriptor with the given name.
// The namespace defaults to the import path of the caller of NewMetricDescriptor.
// Use SetNamespace to provide a different one.
// Neither the name nor the namespace can be empty.
func NewMetricDescriptor(name, description string) *MetricDescriptor {
return newMetricDescriptor(name, description)
}
func newMetricDescriptor(name, description string) *MetricDescriptor {
if name == "" {
panic("name cannot be empty")
}
return &MetricDescriptor{
name: name,
namespace: scanStack().Space,
description: description,
}
}
// SetNamespace sets the namespace of m to a non-empty string.
func (m *MetricDescriptor) SetNamespace(ns string) {
if ns == "" {
panic("namespace cannot be empty")
}
m.namespace = ns
}
func (m *MetricDescriptor) String() string {
return fmt.Sprintf("Metric(\"%s/%s\")", m.namespace, m.name)
}
func (m *MetricDescriptor) Name() string { return m.name }
func (m *MetricDescriptor) Namespace() string { return m.namespace }
func (m *MetricDescriptor) Description() string { return m.description }
// A Counter is a metric that counts something cumulatively.
type Counter struct {
*MetricDescriptor
}
// NewCounter creates a counter with the given name.
func NewCounter(name, description string) *Counter {
return &Counter{newMetricDescriptor(name, description)}
}
// Descriptor returns the receiver's MetricDescriptor.
func (c *Counter) Descriptor() *MetricDescriptor {
return c.MetricDescriptor
}
// Record delivers a metric event with the given metric, value and labels to the
// exporter in the context.
func (c *Counter) Record(ctx context.Context, v int64, labels ...Label) {
ev := New(ctx, MetricKind)
if ev != nil {
record(ev, c, Int64(MetricVal, v))
ev.Labels = append(ev.Labels, labels...)
ev.Deliver()
}
}
// A FloatGauge records a single floating-point value that may go up or down.
// TODO(generics): Gauge[T]
type FloatGauge struct {
*MetricDescriptor
}
// NewFloatGauge creates a new FloatGauge with the given name.
func NewFloatGauge(name, description string) *FloatGauge {
return &FloatGauge{newMetricDescriptor(name, description)}
}
// Descriptor returns the receiver's MetricDescriptor.
func (g *FloatGauge) Descriptor() *MetricDescriptor {
return g.MetricDescriptor
}
// Record converts its argument into a Value and returns a MetricValue with the
// receiver and the value. It is intended to be used as an argument to
// Builder.Metric.
func (g *FloatGauge) Record(ctx context.Context, v float64, labels ...Label) {
ev := New(ctx, MetricKind)
if ev != nil {
record(ev, g, Float64(MetricVal, v))
ev.Labels = append(ev.Labels, labels...)
ev.Deliver()
}
}
// A DurationDistribution records a distribution of durations.
// TODO(generics): Distribution[T]
type DurationDistribution struct {
*MetricDescriptor
}
// NewDuration creates a new Duration with the given name.
func NewDuration(name, description string) *DurationDistribution {
return &DurationDistribution{newMetricDescriptor(name, description)}
}
// Descriptor returns the receiver's MetricDescriptor.
func (d *DurationDistribution) Descriptor() *MetricDescriptor {
return d.MetricDescriptor
}
// Record converts its argument into a Value and returns a MetricValue with the
// receiver and the value. It is intended to be used as an argument to
// Builder.Metric.
func (d *DurationDistribution) Record(ctx context.Context, v time.Duration, labels ...Label) {
ev := New(ctx, MetricKind)
if ev != nil {
record(ev, d, Duration(MetricVal, v))
ev.Labels = append(ev.Labels, labels...)
ev.Deliver()
}
}
// An IntDistribution records a distribution of int64s.
type IntDistribution struct {
*MetricDescriptor
}
// NewIntDistribution creates a new IntDistribution with the given name.
func NewIntDistribution(name, description string) *IntDistribution {
return &IntDistribution{newMetricDescriptor(name, description)}
}
// Descriptor returns the receiver's MetricDescriptor.
func (d *IntDistribution) Descriptor() *MetricDescriptor {
return d.MetricDescriptor
}
// Record converts its argument into a Value and returns a MetricValue with the
// receiver and the value. It is intended to be used as an argument to
// Builder.Metric.
func (d *IntDistribution) Record(ctx context.Context, v int64, labels ...Label) {
ev := New(ctx, MetricKind)
if ev != nil {
record(ev, d, Int64(MetricVal, v))
ev.Labels = append(ev.Labels, labels...)
ev.Deliver()
}
}
func record(ev *Event, m Metric, l Label) {
ev.Labels = append(ev.Labels, l, Value(MetricKey, m))
}