Skip to content

Commit 2159c26

Browse files
committed
runtime/metrics: add package interface
This change creates the runtime/metrics package and adds the initial interface as laid out in the design document. For #37112. Change-Id: I202dcee08ab008dd63bf96f7a4162f5b5f813637 Reviewed-on: https://go-review.googlesource.com/c/go/+/247040 Run-TryBot: Michael Knyszek <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Michael Knyszek <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent c02134a commit 2159c26

File tree

6 files changed

+232
-0
lines changed

6 files changed

+232
-0
lines changed

src/go/build/deps_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ var depsRules = `
138138
MATH
139139
< math/rand;
140140
141+
MATH
142+
< runtime/metrics;
143+
141144
MATH, unicode/utf8
142145
< strconv;
143146

src/runtime/metrics/description.go

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package metrics
6+
7+
// Description describes a runtime metric.
8+
type Description struct {
9+
// Name is the full name of the metric which includes the unit.
10+
//
11+
// The format of the metric may be described by the following regular expression.
12+
//
13+
// ^(?P<name>/[^:]+):(?P<unit>[^:*\/]+(?:[*\/][^:*\/]+)*)$
14+
//
15+
// The format splits the name into two components, separated by a colon: a path which always
16+
// starts with a /, and a machine-parseable unit. The name may contain any valid Unicode
17+
// codepoint in between / characters, but by convention will try to stick to lowercase
18+
// characters and hyphens. An example of such a path might be "/memory/heap/free".
19+
//
20+
// The unit is by convention a series of lowercase English unit names (singular or plural)
21+
// without prefixes delimited by '*' or '/'. The unit names may contain any valid Unicode
22+
// codepoint that is not a delimiter.
23+
// Examples of units might be "seconds", "bytes", "bytes/second", "cpu-seconds",
24+
// "byte*cpu-seconds", and "bytes/second/second".
25+
//
26+
// A complete name might look like "/memory/heap/free:bytes".
27+
Name string
28+
29+
// Kind is the kind of value for this metric.
30+
//
31+
// The purpose of this field is to allow users to filter out metrics whose values are
32+
// types which their application may not understand.
33+
Kind ValueKind
34+
35+
// Cumulative is whether or not the metric is cumulative. If a cumulative metric is just
36+
// a single number, then it increases monotonically. If the metric is a distribution,
37+
// then each bucket count increases monotonically.
38+
//
39+
// This flag thus indicates whether or not it's useful to compute a rate from this value.
40+
Cumulative bool
41+
42+
// StopTheWorld is whether or not the metric requires a stop-the-world
43+
// event in order to collect it.
44+
StopTheWorld bool
45+
}
46+
47+
var allDesc = []Description{}
48+
49+
// All returns a slice of containing metric descriptions for all supported metrics.
50+
func All() []Description {
51+
return allDesc
52+
}

src/runtime/metrics/doc.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
/*
6+
Package metrics provides a stable interface to access implementation-defined
7+
metrics exported by the Go runtime. This package is similar to existing functions
8+
like runtime.ReadMemStats and debug.ReadGCStats, but significantly more general.
9+
10+
The set of metrics defined by this package may evolve as the runtime itself
11+
evolves, and also enables variation across Go implementations, whose relevant
12+
metric sets may not intersect.
13+
14+
Interface
15+
16+
Metrics are designated by a string key, rather than, for example, a field name in
17+
a struct. The full list of supported metrics is always available in the slice of
18+
Descriptions returned by All. Each Description also includes useful information
19+
about the metric, such as how to display it (e.g. gauge vs. counter) and how difficult
20+
or disruptive it is to obtain it (e.g. do you need to stop the world?).
21+
22+
Thus, users of this API are encouraged to sample supported metrics defined by the
23+
slice returned by All to remain compatible across Go versions. Of course, situations
24+
arise where reading specific metrics is critical. For these cases, users are
25+
encouranged to use build tags, and although metrics may be deprecated and removed,
26+
users should consider this to be an exceptional and rare event, coinciding with a
27+
very large change in a particular Go implementation.
28+
29+
Each metric key also has a "kind" that describes the format of the metric's value.
30+
In the interest of not breaking users of this package, the "kind" for a given metric
31+
is guaranteed not to change. If it must change, then a new metric will be introduced
32+
with a new key and a new "kind."
33+
34+
Metric key format
35+
36+
As mentioned earlier, metric keys are strings. Their format is simple and well-defined,
37+
designed to be both human and machine readable. It is split into two components,
38+
separated by a colon: a rooted path and a unit. The choice to include the unit in
39+
the key is motivated by compatibility: if a metric's unit changes, its semantics likely
40+
did also, and a new key should be introduced.
41+
42+
For more details on the precise definition of the metric key's path and unit formats, see
43+
the documentation of the Name field of the Description struct.
44+
45+
Supported metrics
46+
47+
TODO(mknyszek): List them here as they're added.
48+
*/
49+
package metrics

src/runtime/metrics/histogram.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package metrics
6+
7+
// Float64Histogram represents a distribution of float64 values.
8+
type Float64Histogram struct {
9+
// Counts contains the weights for each histogram bucket. The length of
10+
// Counts is equal to the length of Buckets (in the metric description)
11+
// plus one to account for the implicit minimum bucket.
12+
//
13+
// Given N buckets, the following is the mathematical relationship between
14+
// Counts and Buckets.
15+
// count[0] is the weight of the range (-inf, bucket[0])
16+
// count[n] is the weight of the range [bucket[n], bucket[n+1]), for 0 < n < N-1
17+
// count[N-1] is the weight of the range [bucket[N-1], inf)
18+
Counts []uint64
19+
20+
// Buckets contains the boundaries between histogram buckets, in increasing order.
21+
//
22+
// Because this slice contains boundaries, there are len(Buckets)+1 counts:
23+
// a count for all values less than the first boundary, a count covering each
24+
// [slice[i], slice[i+1]) interval, and a count for all values greater than or
25+
// equal to the last boundary.
26+
//
27+
// For a given metric name, the value of Buckets is guaranteed not to change
28+
// between calls until program exit.
29+
Buckets []float64
30+
}

src/runtime/metrics/sample.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package metrics
6+
7+
// Sample captures a single metric sample.
8+
type Sample struct {
9+
// Name is the name of the metric sampled.
10+
//
11+
// It must correspond to a name in one of the metric descriptions
12+
// returned by Descriptions.
13+
Name string
14+
15+
// Value is the value of the metric sample.
16+
Value Value
17+
}
18+
19+
// Read populates each Value field in the given slice of metric samples.
20+
//
21+
// Desired metrics should be present in the slice with the appropriate name.
22+
// The user of this API is encouraged to re-use the same slice between calls.
23+
//
24+
// Metric values with names not appearing in the value returned by Descriptions
25+
// will have the value populated as KindBad to indicate that the name is
26+
// unknown.
27+
func Read(m []Sample) {
28+
panic("unimplemented")
29+
}

src/runtime/metrics/value.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package metrics
6+
7+
import (
8+
"math"
9+
"unsafe"
10+
)
11+
12+
// ValueKind is a tag for a metric Value which indicates its type.
13+
type ValueKind int
14+
15+
const (
16+
// KindBad indicates that the Value has no type and should not be used.
17+
KindBad ValueKind = iota
18+
19+
// KindUint64 indicates that the type of the Value is a uint64.
20+
KindUint64
21+
22+
// KindFloat64 indicates that the type of the Value is a float64.
23+
KindFloat64
24+
25+
// KindFloat64Histogram indicates that the type of the Value is a *Float64Histogram.
26+
KindFloat64Histogram
27+
)
28+
29+
// Value represents a metric value returned by the runtime.
30+
type Value struct {
31+
kind ValueKind
32+
scalar uint64 // contains scalar values for scalar Kinds.
33+
pointer unsafe.Pointer // contains non-scalar values.
34+
}
35+
36+
// Kind returns the a tag representing the kind of value this is.
37+
func (v Value) Kind() ValueKind {
38+
return v.kind
39+
}
40+
41+
// Uint64 returns the internal uint64 value for the metric.
42+
//
43+
// If v.Kind() != KindUint64, this method panics.
44+
func (v Value) Uint64() uint64 {
45+
if v.kind != KindUint64 {
46+
panic("called Uint64 on non-uint64 metric value")
47+
}
48+
return v.scalar
49+
}
50+
51+
// Float64 returns the internal float64 value for the metric.
52+
//
53+
// If v.Kind() != KindFloat64, this method panics.
54+
func (v Value) Float64() float64 {
55+
if v.kind != KindFloat64 {
56+
panic("called Float64 on non-float64 metric value")
57+
}
58+
return math.Float64frombits(v.scalar)
59+
}
60+
61+
// Float64Histogram returns the internal *Float64Histogram value for the metric.
62+
//
63+
// If v.Kind() != KindFloat64Histogram, this method panics.
64+
func (v Value) Float64Histogram() *Float64Histogram {
65+
if v.kind != KindFloat64Histogram {
66+
panic("called Float64 on non-float64 metric value")
67+
}
68+
return (*Float64Histogram)(v.pointer)
69+
}

0 commit comments

Comments
 (0)