Skip to content

Commit 8d69243

Browse files
dashpoleXSAM
authored andcommitted
Implement new runtime metrics (open-telemetry#5780)
Part of open-telemetry#5655 Changes: * Move the configuration options to `options.go` without modification. * Implements the metrics defined here: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/runtime/go-metrics.md. These are still disabled by default while it is under development. * Add unit tests Notes: It doesn't implement `go.schedule.duration`, as the histogram will need some additional work to figure out. Based on prometheus/client_golang#955 (comment), using go's runtime metrics should is more efficient than reading memstats. --------- Co-authored-by: Sam Xie <[email protected]>
1 parent e38b3f5 commit 8d69243

File tree

9 files changed

+580
-74
lines changed

9 files changed

+580
-74
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1616
- The `go.opentelemetry.io/contrib/bridges/otelzap` module.
1717
This module provides an OpenTelemetry logging bridge for `go.uber.org/zap`. (#5191)
1818
- The `go.opentelemetry.io/contrib/config` package supports configuring `with_resource_constant_labels` for the prometheus exporter. (#5890)
19+
- Add new runtime metrics to `go.opentelemetry.io/contrib/instrumentation/runtime`, which are still disabled by default. (#5870)
1920

2021
### Removed
2122

instrumentation/runtime/doc.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,16 @@
1919
// runtime.go.mem.heap_sys (bytes) Bytes of heap memory obtained from the OS
2020
// runtime.go.mem.live_objects - Number of live objects is the number of cumulative Mallocs - Frees
2121
// runtime.uptime (ms) Milliseconds since application was initialized
22+
//
23+
// When the OTEL_GO_X_DEPRECATED_RUNTIME_METRICS environment variable is set to
24+
// false, the metrics produced are:
25+
//
26+
// go.memory.used By Memory used by the Go runtime.
27+
// go.memory.limit By Go runtime memory limit configured by the user, if a limit exists.
28+
// go.memory.allocated By Memory allocated to the heap by the application.
29+
// go.memory.allocations {allocation} Count of allocations to the heap by the application.
30+
// go.memory.gc.goal By Heap size target for the end of the GC cycle.
31+
// go.goroutine.count {goroutine} Count of live goroutines.
32+
// go.processor.limit {thread} The number of OS threads that can execute user-level Go code simultaneously.
33+
// go.config.gogc % Heap size target percentage configured by the user, otherwise 100.
2234
package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime"

instrumentation/runtime/options.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime"
5+
6+
import (
7+
"time"
8+
9+
"go.opentelemetry.io/otel"
10+
"go.opentelemetry.io/otel/metric"
11+
)
12+
13+
// config contains optional settings for reporting runtime metrics.
14+
type config struct {
15+
// MinimumReadMemStatsInterval sets the minimum interval
16+
// between calls to runtime.ReadMemStats(). Negative values
17+
// are ignored.
18+
MinimumReadMemStatsInterval time.Duration
19+
20+
// MeterProvider sets the metric.MeterProvider. If nil, the global
21+
// Provider will be used.
22+
MeterProvider metric.MeterProvider
23+
}
24+
25+
// Option supports configuring optional settings for runtime metrics.
26+
type Option interface {
27+
apply(*config)
28+
}
29+
30+
// DefaultMinimumReadMemStatsInterval is the default minimum interval
31+
// between calls to runtime.ReadMemStats(). Use the
32+
// WithMinimumReadMemStatsInterval() option to modify this setting in
33+
// Start().
34+
const DefaultMinimumReadMemStatsInterval time.Duration = 15 * time.Second
35+
36+
// WithMinimumReadMemStatsInterval sets a minimum interval between calls to
37+
// runtime.ReadMemStats(), which is a relatively expensive call to make
38+
// frequently. This setting is ignored when `d` is negative.
39+
func WithMinimumReadMemStatsInterval(d time.Duration) Option {
40+
return minimumReadMemStatsIntervalOption(d)
41+
}
42+
43+
type minimumReadMemStatsIntervalOption time.Duration
44+
45+
func (o minimumReadMemStatsIntervalOption) apply(c *config) {
46+
if o >= 0 {
47+
c.MinimumReadMemStatsInterval = time.Duration(o)
48+
}
49+
}
50+
51+
// WithMeterProvider sets the Metric implementation to use for
52+
// reporting. If this option is not used, the global metric.MeterProvider
53+
// will be used. `provider` must be non-nil.
54+
func WithMeterProvider(provider metric.MeterProvider) Option {
55+
return metricProviderOption{provider}
56+
}
57+
58+
type metricProviderOption struct{ metric.MeterProvider }
59+
60+
func (o metricProviderOption) apply(c *config) {
61+
if o.MeterProvider != nil {
62+
c.MeterProvider = o.MeterProvider
63+
}
64+
}
65+
66+
// newConfig computes a config from the supplied Options.
67+
func newConfig(opts ...Option) config {
68+
c := config{
69+
MeterProvider: otel.GetMeterProvider(),
70+
MinimumReadMemStatsInterval: DefaultMinimumReadMemStatsInterval,
71+
}
72+
for _, opt := range opts {
73+
opt.apply(&c)
74+
}
75+
return c
76+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime"
5+
6+
import (
7+
"testing"
8+
"time"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestNewConfig(t *testing.T) {
14+
for _, tt := range []struct {
15+
name string
16+
opts []Option
17+
expect config
18+
}{
19+
{
20+
name: "default",
21+
expect: config{MinimumReadMemStatsInterval: 15 * time.Second},
22+
},
23+
{
24+
name: "negative MinimumReadMemStatsInterval ignored",
25+
opts: []Option{WithMinimumReadMemStatsInterval(-1 * time.Second)},
26+
expect: config{MinimumReadMemStatsInterval: 15 * time.Second},
27+
},
28+
{
29+
name: "set MinimumReadMemStatsInterval",
30+
opts: []Option{WithMinimumReadMemStatsInterval(10 * time.Second)},
31+
expect: config{MinimumReadMemStatsInterval: 10 * time.Second},
32+
},
33+
} {
34+
t.Run(tt.name, func(t *testing.T) {
35+
got := newConfig(tt.opts...)
36+
assert.True(t, configEqual(got, tt.expect))
37+
})
38+
}
39+
}
40+
41+
func configEqual(a, b config) bool {
42+
// ignore MeterProvider
43+
return a.MinimumReadMemStatsInterval == b.MinimumReadMemStatsInterval
44+
}

0 commit comments

Comments
 (0)