Skip to content

Commit 5819ac6

Browse files
authored
Merge branch 'main' into cirilla/fix_b3_propagator_panic
2 parents 4d747f9 + ae2a4f0 commit 5819ac6

File tree

10 files changed

+463
-272
lines changed

10 files changed

+463
-272
lines changed

CHANGELOG.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1313
- The `go.opentelemetry.io/contrib/config` add support to configure periodic reader interval and timeout. (#5661)
1414
- Add support to configure views when creating MeterProvider using the config package. (#5654)
1515
- Add log support for the autoexport package. (#5733)
16+
- Add support for disabling the old runtime metrics using the `OTEL_GO_X_DEPRECATED_RUNTIME_METRICS=false` environment variable. (#5747)
1617

1718
### Fixed
1819

1920
- The superfluous `response.WriteHeader` call in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` when the response writer is flushed. (#5634)
2021
- Custom attributes targeting metrics recorded by the `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` are not ignored anymore. (#5129)
2122
- Use `c.FullPath()` method to set `http.route` attribute in `go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin`. (#5734)
22-
- Fix out-of-bounds panic caused by invalid spanId with b3 propagator. (#5754)
23+
- The double setup in `go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace/example` that caused duplicate traces. (#5564)
24+
- Out-of-bounds panic in case of invalid span ID in `go.opentelemetry.io/contrib/propagators/b3`. (#5754)
2325

2426
### Deprecated
2527

@@ -39,8 +41,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
3941

4042
### Changed
4143

42-
- Improve performance of `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` with the usage of `WithAttributeSet()` instead of `WithAttribute()`. (#5664)
43-
- Improve performance of `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` with the usage of `WithAttributeSet()` instead of `WithAttribute()`. (#5664)
44+
- Improve performance of `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` with the usage of `WithAttributeSet()` instead of `WithAttribute()`. (#5664)
45+
- Improve performance of `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` with the usage of `WithAttributeSet()` instead of `WithAttribute()`. (#5664)
4446

4547
## [1.27.0/0.52.0/0.21.0/0.7.0/0.2.0] - 2024-05-21
4648

instrumentation/net/http/httptrace/otelhttptrace/example/client/client.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ func main() {
6060
client := http.Client{
6161
Transport: otelhttp.NewTransport(
6262
http.DefaultTransport,
63+
// By setting the otelhttptrace client in this transport, it can be
64+
// injected into the context after the span is started, which makes the
65+
// httptrace spans children of the transport one.
6366
otelhttp.WithClientTrace(func(ctx context.Context) *httptrace.ClientTrace {
6467
return otelhttptrace.NewClientTrace(ctx)
6568
}),
@@ -76,7 +79,6 @@ func main() {
7679
ctx, span := tr.Start(ctx, "say hello", trace.WithAttributes(semconv.PeerService("ExampleService")))
7780
defer span.End()
7881

79-
ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx))
8082
req, _ := http.NewRequestWithContext(ctx, "GET", *url, nil)
8183

8284
fmt.Printf("Sending request...\n")

instrumentation/runtime/go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ module go.opentelemetry.io/contrib/instrumentation/runtime
33
go 1.21
44

55
require (
6+
github.com/stretchr/testify v1.9.0
67
go.opentelemetry.io/otel v1.27.0
78
go.opentelemetry.io/otel/metric v1.27.0
89
)
910

1011
require (
12+
github.com/davecgh/go-spew v1.1.1 // indirect
1113
github.com/go-logr/logr v1.4.2 // indirect
1214
github.com/go-logr/stdr v1.2.2 // indirect
15+
github.com/pmezard/go-difflib v1.0.0 // indirect
1316
go.opentelemetry.io/otel/trace v1.27.0 // indirect
17+
gopkg.in/yaml.v3 v3.0.1 // indirect
1418
)

instrumentation/runtime/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@ go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0
1717
go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak=
1818
go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw=
1919
go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4=
20+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
21+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2022
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
2123
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Package deprecatedruntime implements the deprecated runtime metrics for OpenTelemetry.
5+
//
6+
// The metric events produced are:
7+
//
8+
// runtime.go.cgo.calls - Number of cgo calls made by the current process
9+
// runtime.go.gc.count - Number of completed garbage collection cycles
10+
// runtime.go.gc.pause_ns (ns) Amount of nanoseconds in GC stop-the-world pauses
11+
// runtime.go.gc.pause_total_ns (ns) Cumulative nanoseconds in GC stop-the-world pauses since the program started
12+
// runtime.go.goroutines - Number of goroutines that currently exist
13+
// runtime.go.lookups - Number of pointer lookups performed by the runtime
14+
// runtime.go.mem.heap_alloc (bytes) Bytes of allocated heap objects
15+
// runtime.go.mem.heap_idle (bytes) Bytes in idle (unused) spans
16+
// runtime.go.mem.heap_inuse (bytes) Bytes in in-use spans
17+
// runtime.go.mem.heap_objects - Number of allocated heap objects
18+
// runtime.go.mem.heap_released (bytes) Bytes of idle spans whose physical memory has been returned to the OS
19+
// runtime.go.mem.heap_sys (bytes) Bytes of heap memory obtained from the OS
20+
// runtime.go.mem.live_objects - Number of live objects is the number of cumulative Mallocs - Frees
21+
// runtime.uptime (ms) Milliseconds since application was initialized
22+
package deprecatedruntime // import "go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime"
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package deprecatedruntime // import "go.opentelemetry.io/contrib/instrumentation/runtime/internal/deprecatedruntime"
5+
6+
import (
7+
"context"
8+
goruntime "runtime"
9+
"sync"
10+
"time"
11+
12+
"go.opentelemetry.io/otel/metric"
13+
)
14+
15+
// Runtime reports the work-in-progress conventional runtime metrics specified by OpenTelemetry.
16+
type runtime struct {
17+
minimumReadMemStatsInterval time.Duration
18+
meter metric.Meter
19+
}
20+
21+
// Start initializes reporting of runtime metrics using the supplied config.
22+
func Start(meter metric.Meter, minimumReadMemStatsInterval time.Duration) error {
23+
r := &runtime{
24+
meter: meter,
25+
minimumReadMemStatsInterval: minimumReadMemStatsInterval,
26+
}
27+
return r.register()
28+
}
29+
30+
func (r *runtime) register() error {
31+
startTime := time.Now()
32+
uptime, err := r.meter.Int64ObservableCounter(
33+
"runtime.uptime",
34+
metric.WithUnit("ms"),
35+
metric.WithDescription("Milliseconds since application was initialized"),
36+
)
37+
if err != nil {
38+
return err
39+
}
40+
41+
goroutines, err := r.meter.Int64ObservableUpDownCounter(
42+
"process.runtime.go.goroutines",
43+
metric.WithDescription("Number of goroutines that currently exist"),
44+
)
45+
if err != nil {
46+
return err
47+
}
48+
49+
cgoCalls, err := r.meter.Int64ObservableUpDownCounter(
50+
"process.runtime.go.cgo.calls",
51+
metric.WithDescription("Number of cgo calls made by the current process"),
52+
)
53+
if err != nil {
54+
return err
55+
}
56+
57+
_, err = r.meter.RegisterCallback(
58+
func(ctx context.Context, o metric.Observer) error {
59+
o.ObserveInt64(uptime, time.Since(startTime).Milliseconds())
60+
o.ObserveInt64(goroutines, int64(goruntime.NumGoroutine()))
61+
o.ObserveInt64(cgoCalls, goruntime.NumCgoCall())
62+
return nil
63+
},
64+
uptime,
65+
goroutines,
66+
cgoCalls,
67+
)
68+
if err != nil {
69+
return err
70+
}
71+
72+
return r.registerMemStats()
73+
}
74+
75+
func (r *runtime) registerMemStats() error {
76+
var (
77+
err error
78+
79+
heapAlloc metric.Int64ObservableUpDownCounter
80+
heapIdle metric.Int64ObservableUpDownCounter
81+
heapInuse metric.Int64ObservableUpDownCounter
82+
heapObjects metric.Int64ObservableUpDownCounter
83+
heapReleased metric.Int64ObservableUpDownCounter
84+
heapSys metric.Int64ObservableUpDownCounter
85+
liveObjects metric.Int64ObservableUpDownCounter
86+
87+
// TODO: is ptrLookups useful? I've not seen a value
88+
// other than zero.
89+
ptrLookups metric.Int64ObservableCounter
90+
91+
gcCount metric.Int64ObservableCounter
92+
pauseTotalNs metric.Int64ObservableCounter
93+
gcPauseNs metric.Int64Histogram
94+
95+
lastNumGC uint32
96+
lastMemStats time.Time
97+
memStats goruntime.MemStats
98+
99+
// lock prevents a race between batch observer and instrument registration.
100+
lock sync.Mutex
101+
)
102+
103+
lock.Lock()
104+
defer lock.Unlock()
105+
106+
if heapAlloc, err = r.meter.Int64ObservableUpDownCounter(
107+
"process.runtime.go.mem.heap_alloc",
108+
metric.WithUnit("By"),
109+
metric.WithDescription("Bytes of allocated heap objects"),
110+
); err != nil {
111+
return err
112+
}
113+
114+
if heapIdle, err = r.meter.Int64ObservableUpDownCounter(
115+
"process.runtime.go.mem.heap_idle",
116+
metric.WithUnit("By"),
117+
metric.WithDescription("Bytes in idle (unused) spans"),
118+
); err != nil {
119+
return err
120+
}
121+
122+
if heapInuse, err = r.meter.Int64ObservableUpDownCounter(
123+
"process.runtime.go.mem.heap_inuse",
124+
metric.WithUnit("By"),
125+
metric.WithDescription("Bytes in in-use spans"),
126+
); err != nil {
127+
return err
128+
}
129+
130+
if heapObjects, err = r.meter.Int64ObservableUpDownCounter(
131+
"process.runtime.go.mem.heap_objects",
132+
metric.WithDescription("Number of allocated heap objects"),
133+
); err != nil {
134+
return err
135+
}
136+
137+
// FYI see https://github.com/golang/go/issues/32284 to help
138+
// understand the meaning of this value.
139+
if heapReleased, err = r.meter.Int64ObservableUpDownCounter(
140+
"process.runtime.go.mem.heap_released",
141+
metric.WithUnit("By"),
142+
metric.WithDescription("Bytes of idle spans whose physical memory has been returned to the OS"),
143+
); err != nil {
144+
return err
145+
}
146+
147+
if heapSys, err = r.meter.Int64ObservableUpDownCounter(
148+
"process.runtime.go.mem.heap_sys",
149+
metric.WithUnit("By"),
150+
metric.WithDescription("Bytes of heap memory obtained from the OS"),
151+
); err != nil {
152+
return err
153+
}
154+
155+
if ptrLookups, err = r.meter.Int64ObservableCounter(
156+
"process.runtime.go.mem.lookups",
157+
metric.WithDescription("Number of pointer lookups performed by the runtime"),
158+
); err != nil {
159+
return err
160+
}
161+
162+
if liveObjects, err = r.meter.Int64ObservableUpDownCounter(
163+
"process.runtime.go.mem.live_objects",
164+
metric.WithDescription("Number of live objects is the number of cumulative Mallocs - Frees"),
165+
); err != nil {
166+
return err
167+
}
168+
169+
if gcCount, err = r.meter.Int64ObservableCounter(
170+
"process.runtime.go.gc.count",
171+
metric.WithDescription("Number of completed garbage collection cycles"),
172+
); err != nil {
173+
return err
174+
}
175+
176+
// Note that the following could be derived as a sum of
177+
// individual pauses, but we may lose individual pauses if the
178+
// observation interval is too slow.
179+
if pauseTotalNs, err = r.meter.Int64ObservableCounter(
180+
"process.runtime.go.gc.pause_total_ns",
181+
// TODO: nanoseconds units
182+
metric.WithDescription("Cumulative nanoseconds in GC stop-the-world pauses since the program started"),
183+
); err != nil {
184+
return err
185+
}
186+
187+
if gcPauseNs, err = r.meter.Int64Histogram(
188+
"process.runtime.go.gc.pause_ns",
189+
// TODO: nanoseconds units
190+
metric.WithDescription("Amount of nanoseconds in GC stop-the-world pauses"),
191+
); err != nil {
192+
return err
193+
}
194+
195+
_, err = r.meter.RegisterCallback(
196+
func(ctx context.Context, o metric.Observer) error {
197+
lock.Lock()
198+
defer lock.Unlock()
199+
200+
now := time.Now()
201+
if now.Sub(lastMemStats) >= r.minimumReadMemStatsInterval {
202+
goruntime.ReadMemStats(&memStats)
203+
lastMemStats = now
204+
}
205+
206+
o.ObserveInt64(heapAlloc, int64(memStats.HeapAlloc))
207+
o.ObserveInt64(heapIdle, int64(memStats.HeapIdle))
208+
o.ObserveInt64(heapInuse, int64(memStats.HeapInuse))
209+
o.ObserveInt64(heapObjects, int64(memStats.HeapObjects))
210+
o.ObserveInt64(heapReleased, int64(memStats.HeapReleased))
211+
o.ObserveInt64(heapSys, int64(memStats.HeapSys))
212+
o.ObserveInt64(liveObjects, int64(memStats.Mallocs-memStats.Frees))
213+
o.ObserveInt64(ptrLookups, int64(memStats.Lookups))
214+
o.ObserveInt64(gcCount, int64(memStats.NumGC))
215+
o.ObserveInt64(pauseTotalNs, int64(memStats.PauseTotalNs))
216+
217+
computeGCPauses(ctx, gcPauseNs, memStats.PauseNs[:], lastNumGC, memStats.NumGC)
218+
219+
lastNumGC = memStats.NumGC
220+
221+
return nil
222+
},
223+
heapAlloc,
224+
heapIdle,
225+
heapInuse,
226+
heapObjects,
227+
heapReleased,
228+
heapSys,
229+
liveObjects,
230+
231+
ptrLookups,
232+
233+
gcCount,
234+
pauseTotalNs,
235+
)
236+
if err != nil {
237+
return err
238+
}
239+
return nil
240+
}
241+
242+
func computeGCPauses(
243+
ctx context.Context,
244+
recorder metric.Int64Histogram,
245+
circular []uint64,
246+
lastNumGC, currentNumGC uint32,
247+
) {
248+
delta := int(int64(currentNumGC) - int64(lastNumGC))
249+
250+
if delta == 0 {
251+
return
252+
}
253+
254+
if delta >= len(circular) {
255+
// There were > 256 collections, some may have been lost.
256+
recordGCPauses(ctx, recorder, circular)
257+
return
258+
}
259+
260+
length := uint32(len(circular))
261+
262+
i := lastNumGC % length
263+
j := currentNumGC % length
264+
265+
if j < i { // wrap around the circular buffer
266+
recordGCPauses(ctx, recorder, circular[i:])
267+
recordGCPauses(ctx, recorder, circular[:j])
268+
return
269+
}
270+
271+
recordGCPauses(ctx, recorder, circular[i:j])
272+
}
273+
274+
func recordGCPauses(
275+
ctx context.Context,
276+
recorder metric.Int64Histogram,
277+
pauses []uint64,
278+
) {
279+
for _, pause := range pauses {
280+
recorder.Record(ctx, int64(pause))
281+
}
282+
}

0 commit comments

Comments
 (0)