event: metric tweaks

- Document metric symbols.

- Use pointer to MetricDescriptor instead of value.

- Fix call depth when constructing namespace.

Change-Id: I5ee4011c7a857bdbb6d83b7eb1ed948021b5529e
Reviewed-on: https://go-review.googlesource.com/c/exp/+/326672
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
diff --git a/event/metric.go b/event/metric.go
index 9ca35c8..52b27ed 100644
--- a/event/metric.go
+++ b/event/metric.go
@@ -9,71 +9,85 @@
 	"time"
 )
 
+// A Metric represents a kind of recorded measurement.
 type Metric interface {
-	Descriptor() MetricDescriptor
+	Descriptor() *MetricDescriptor
 }
 
+// A MetricDescriptor describes a metric.
 type MetricDescriptor struct {
 	namespace   string
 	name        string
 	Description string
-	// For unit, 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.
+	// 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.
 }
 
-// TODO: how to force a non-empty namespace?
+// 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 string) *MetricDescriptor {
+	return newMetricDescriptor(name)
+}
 
-func NewMetricDescriptor(name string) MetricDescriptor {
+func newMetricDescriptor(name string) *MetricDescriptor {
 	if name == "" {
 		panic("name cannot be empty")
 	}
-	m := MetricDescriptor{name: name}
-	// TODO: make this work right whether called from in this package or externally.
-	// Set namespace to the caller's import path.
-	// Depth:
-	//   0  runtime.Callers
-	//   1  importPath
-	//   2  this function
-	//   3  caller of this function (one of the NewXXX methods in this package)
-	//   4  caller's caller
-	m.namespace = importPath(4, nil)
-	return m
+	return &MetricDescriptor{
+		name: name,
+		// Set namespace to the caller's import path.
+		// Depth:
+		//   0  runtime.Callers
+		//   1  importPath
+		//   2  this function
+		//   3  caller of this function (one of the NewXXX methods in this package)
+		//   4  caller's caller
+		namespace: importPath(4, nil),
+	}
+}
+
+// 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) WithNamespace(ns string) *MetricDescriptor {
-	if ns == "" {
-		panic("namespace cannot be empty")
-	}
-	m.namespace = ns
-	return m
-}
+func (m *MetricDescriptor) Name() string      { return m.name }
+func (m *MetricDescriptor) Namespace() string { return m.namespace }
 
-func (m MetricDescriptor) Name() string      { return m.name }
-func (m MetricDescriptor) Namespace() string { return m.namespace }
-
-// A counter is a metric that counts something cumulatively.
-type Counter struct {
-	MetricDescriptor
-}
-
-func NewCounter(name string) *Counter {
-	return &Counter{NewMetricDescriptor(name)}
-}
-
-func (c *Counter) Descriptor() MetricDescriptor {
-	return c.MetricDescriptor
-}
-
+// A MetricValue is a pair of a Metric and a Value.
 type MetricValue struct {
 	m Metric
 	v Value
 }
 
+// A Counter is a metric that counts something cumulatively.
+type Counter struct {
+	*MetricDescriptor
+}
+
+// NewCounter creates a counter with the given name.
+func NewCounter(name string) *Counter {
+	return &Counter{newMetricDescriptor(name)}
+}
+
+// Descriptor returns the receiver's MetricDescriptor.
+func (c *Counter) Descriptor() *MetricDescriptor {
+	return c.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 (c *Counter) Record(v uint64) MetricValue {
 	return MetricValue{c, Uint64Of(v)}
 }
@@ -81,17 +95,22 @@
 // A FloatGauge records a single floating-point value that may go up or down.
 // TODO(generics): Gauge[T]
 type FloatGauge struct {
-	MetricDescriptor
+	*MetricDescriptor
 }
 
+// NewFloatGauge creates a new FloatGauge with the given name.
 func NewFloatGauge(name string) *FloatGauge {
-	return &FloatGauge{NewMetricDescriptor(name)}
+	return &FloatGauge{newMetricDescriptor(name)}
 }
 
-func (g *FloatGauge) Descriptor() MetricDescriptor {
+// 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(v float64) MetricValue {
 	return MetricValue{g, Float64Of(v)}
 }
@@ -99,17 +118,22 @@
 // A Duration records a distribution of durations.
 // TODO(generics): Distribution[T]
 type Duration struct {
-	MetricDescriptor
+	*MetricDescriptor
 }
 
+// NewDuration creates a new Duration with the given name.
 func NewDuration(name string) *Duration {
-	return &Duration{NewMetricDescriptor(name)}
+	return &Duration{newMetricDescriptor(name)}
 }
 
-func (d *Duration) Descriptor() MetricDescriptor {
+// Descriptor returns the receiver's MetricDescriptor.
+func (d *Duration) 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 *Duration) Record(v time.Duration) MetricValue {
 	return MetricValue{d, DurationOf(v)}
 }