1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-02-07 13:31:42 +02:00

sdk/metric: Record measurements when context is done (#4671)

This commit is contained in:
Robert Pająk 2023-12-15 19:14:16 +01:00 committed by GitHub
parent 057f897096
commit 8e756513a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 12 deletions

View File

@ -20,6 +20,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Changed
- Record synchronous measurements when the passed context is canceled instead of dropping in `go.opentelemetry.io/otel/sdk/metric`.
If you do not want to make a measurement when the context is cancelled, you need to handle it yourself (e.g `if ctx.Err() != nil`). (#4671)
- Improve `go.opentelemetry.io/otel/trace.TraceState`'s performance. (#4722)
- Improve `go.opentelemetry.io/otel/propagation.TraceContext`'s performance. (#4721)
- Improve `go.opentelemetry.io/otel/baggage` performance. (#4743)

View File

@ -591,6 +591,26 @@ this.
[^3]: https://github.com/open-telemetry/opentelemetry-go/issues/3548
### Ignoring context cancellation
OpenTelemetry API implementations need to ignore the cancellation of the context that are
passed when recording a value (e.g. starting a span, recording a measurement, emitting a log).
Recording methods should not return an error describing the cancellation state of the context
when they complete, nor should they abort any work.
This rule may not apply if the OpenTelemetry specification defines a timeout mechanism for
the method. In that case the context cancellation can be used for the timeout with the
restriction that this behavior is documented for the method. Otherwise, timeouts
are expected to be handled by the user calling the API, not the implementation.
Stoppage of the telemetry pipeline is handled by calling the appropriate `Shutdown` method
of a provider. It is assumed the context passed from a user is not used for this purpose.
Outside of the direct recording of telemetry from the API (e.g. exporting telemetry,
force flushing telemetry, shutting down a signal provider) the context cancellation
should be honored. This means all work done on behalf of the user provided context
should be canceled.
## Approvers and Maintainers
### Approvers

View File

@ -205,9 +205,6 @@ func (i *int64Inst) Record(ctx context.Context, val int64, opts ...metric.Record
}
func (i *int64Inst) aggregate(ctx context.Context, val int64, s attribute.Set) { // nolint:revive // okay to shadow pkg with method.
if err := ctx.Err(); err != nil {
return
}
for _, in := range i.measures {
in(ctx, val, s)
}
@ -238,9 +235,6 @@ func (i *float64Inst) Record(ctx context.Context, val float64, opts ...metric.Re
}
func (i *float64Inst) aggregate(ctx context.Context, val float64, s attribute.Set) {
if err := ctx.Err(); err != nil {
return
}
for _, in := range i.measures {
in(ctx, val, s)
}

View File

@ -168,6 +168,10 @@ func TestCallbackUnregisterConcurrency(t *testing.T) {
// Instruments should produce correct ResourceMetrics.
func TestMeterCreatesInstruments(t *testing.T) {
// The synchronous measurement methods must ignore the context cancelation.
ctx, cancel := context.WithCancel(context.Background())
cancel()
attrs := attribute.NewSet(attribute.String("name", "alice"))
opt := metric.WithAttributeSet(attrs)
testCases := []struct {
@ -340,7 +344,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
ctr, err := m.Int64Counter("sint")
assert.NoError(t, err)
ctr.Add(context.Background(), 3)
ctr.Add(ctx, 3)
},
want: metricdata.Metrics{
Name: "sint",
@ -359,7 +363,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
ctr, err := m.Int64UpDownCounter("sint")
assert.NoError(t, err)
ctr.Add(context.Background(), 11)
ctr.Add(ctx, 11)
},
want: metricdata.Metrics{
Name: "sint",
@ -378,7 +382,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
gauge, err := m.Int64Histogram("histogram")
assert.NoError(t, err)
gauge.Record(context.Background(), 7)
gauge.Record(ctx, 7)
},
want: metricdata.Metrics{
Name: "histogram",
@ -404,7 +408,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
ctr, err := m.Float64Counter("sfloat")
assert.NoError(t, err)
ctr.Add(context.Background(), 3)
ctr.Add(ctx, 3)
},
want: metricdata.Metrics{
Name: "sfloat",
@ -423,7 +427,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
ctr, err := m.Float64UpDownCounter("sfloat")
assert.NoError(t, err)
ctr.Add(context.Background(), 11)
ctr.Add(ctx, 11)
},
want: metricdata.Metrics{
Name: "sfloat",
@ -442,7 +446,7 @@ func TestMeterCreatesInstruments(t *testing.T) {
gauge, err := m.Float64Histogram("histogram")
assert.NoError(t, err)
gauge.Record(context.Background(), 7)
gauge.Record(ctx, 7)
},
want: metricdata.Metrics{
Name: "histogram",

View File

@ -1133,6 +1133,18 @@ func TestNilSpanEnd(t *testing.T) {
span.End()
}
func TestSpanWithCanceledContext(t *testing.T) {
te := NewTestExporter()
tp := NewTracerProvider(WithSyncer(te))
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, span := tp.Tracer(t.Name()).Start(ctx, "span")
span.End()
assert.Equal(t, 1, te.Len(), "span recording must ignore context cancelation")
}
func TestNonRecordingSpanDoesNotTrackRuntimeTracerTask(t *testing.T) {
tp := NewTracerProvider(WithSampler(NeverSample()))
tr := tp.Tracer("TestNonRecordingSpanDoesNotTrackRuntimeTracerTask")