diff --git a/stats/opentelemetry/e2e_test.go b/stats/opentelemetry/e2e_test.go index f4c3b4752..9e5a3c66d 100644 --- a/stats/opentelemetry/e2e_test.go +++ b/stats/opentelemetry/e2e_test.go @@ -885,6 +885,14 @@ func (s) TestMetricsAndTracesOptionEnabled(t *testing.T) { Key: "FailFast", Value: attribute.BoolValue(false), }, + { + Key: "previous-rpc-attempts", + Value: attribute.IntValue(0), + }, + { + Key: "transparent-retry", + Value: attribute.BoolValue(false), + }, }, events: []trace.Event{ { @@ -999,6 +1007,14 @@ func (s) TestMetricsAndTracesOptionEnabled(t *testing.T) { Key: "FailFast", Value: attribute.BoolValue(false), }, + { + Key: "previous-rpc-attempts", + Value: attribute.IntValue(0), + }, + { + Key: "transparent-retry", + Value: attribute.BoolValue(false), + }, }, events: nil, }, @@ -1093,6 +1109,14 @@ func (s) TestSpan(t *testing.T) { Key: "FailFast", Value: attribute.BoolValue(false), }, + { + Key: "previous-rpc-attempts", + Value: attribute.IntValue(0), + }, + { + Key: "transparent-retry", + Value: attribute.BoolValue(false), + }, }, events: []trace.Event{ { @@ -1191,6 +1215,14 @@ func (s) TestSpan(t *testing.T) { Key: "FailFast", Value: attribute.BoolValue(false), }, + { + Key: "previous-rpc-attempts", + Value: attribute.IntValue(0), + }, + { + Key: "transparent-retry", + Value: attribute.BoolValue(false), + }, }, events: nil, }, @@ -1287,6 +1319,14 @@ func (s) TestSpan_WithW3CContextPropagator(t *testing.T) { Key: "FailFast", Value: attribute.BoolValue(false), }, + { + Key: "previous-rpc-attempts", + Value: attribute.IntValue(0), + }, + { + Key: "transparent-retry", + Value: attribute.BoolValue(false), + }, }, events: []trace.Event{ { @@ -1385,6 +1425,14 @@ func (s) TestSpan_WithW3CContextPropagator(t *testing.T) { Key: "FailFast", Value: attribute.BoolValue(false), }, + { + Key: "previous-rpc-attempts", + Value: attribute.IntValue(0), + }, + { + Key: "transparent-retry", + Value: attribute.BoolValue(false), + }, }, events: nil, }, @@ -1554,6 +1602,8 @@ func (s) TestTraceSpan_WithRetriesAndNameResolutionDelay(t *testing.T) { attributes: []attribute.KeyValue{ attribute.Bool("Client", false), attribute.Bool("FailFast", false), + attribute.Int("previous-rpc-attempts", 0), + attribute.Bool("transparent-retry", false), }, events: []trace.Event{ { @@ -1593,6 +1643,8 @@ func (s) TestTraceSpan_WithRetriesAndNameResolutionDelay(t *testing.T) { attributes: []attribute.KeyValue{ attribute.Bool("Client", false), attribute.Bool("FailFast", false), + attribute.Int("previous-rpc-attempts", 0), + attribute.Bool("transparent-retry", false), }, events: []trace.Event{ { @@ -1632,6 +1684,8 @@ func (s) TestTraceSpan_WithRetriesAndNameResolutionDelay(t *testing.T) { attributes: []attribute.KeyValue{ attribute.Bool("Client", false), attribute.Bool("FailFast", false), + attribute.Int("previous-rpc-attempts", 0), + attribute.Bool("transparent-retry", false), }, events: []trace.Event{ { @@ -1685,6 +1739,8 @@ func (s) TestTraceSpan_WithRetriesAndNameResolutionDelay(t *testing.T) { attributes: []attribute.KeyValue{ attribute.Bool("Client", false), attribute.Bool("FailFast", false), + attribute.Int("previous-rpc-attempts", 0), + attribute.Bool("transparent-retry", false), }, events: []trace.Event{ { @@ -1766,6 +1822,8 @@ func (s) TestTraceSpan_WithRetriesAndNameResolutionDelay(t *testing.T) { attributes: []attribute.KeyValue{ attribute.Bool("Client", false), attribute.Bool("FailFast", false), + attribute.Int("previous-rpc-attempts", 0), + attribute.Bool("transparent-retry", false), }, events: nil, }, @@ -1797,6 +1855,8 @@ func (s) TestTraceSpan_WithRetriesAndNameResolutionDelay(t *testing.T) { attributes: []attribute.KeyValue{ attribute.Bool("Client", false), attribute.Bool("FailFast", false), + attribute.Int("previous-rpc-attempts", 0), + attribute.Bool("transparent-retry", false), }, events: nil, }, @@ -1828,6 +1888,8 @@ func (s) TestTraceSpan_WithRetriesAndNameResolutionDelay(t *testing.T) { attributes: []attribute.KeyValue{ attribute.Bool("Client", false), attribute.Bool("FailFast", false), + attribute.Int("previous-rpc-attempts", 0), + attribute.Bool("transparent-retry", false), }, events: []trace.Event{ { @@ -1867,6 +1929,8 @@ func (s) TestTraceSpan_WithRetriesAndNameResolutionDelay(t *testing.T) { attributes: []attribute.KeyValue{ attribute.Bool("Client", false), attribute.Bool("FailFast", false), + attribute.Int("previous-rpc-attempts", 0), + attribute.Bool("transparent-retry", false), }, events: []trace.Event{ { @@ -2028,6 +2092,8 @@ func (s) TestStreamingRPC_TraceSequenceNumbers(t *testing.T) { attributes: []attribute.KeyValue{ attribute.Bool("Client", false), attribute.Bool("FailFast", false), + attribute.Int("previous-rpc-attempts", 0), + attribute.Bool("transparent-retry", false), }, }, { diff --git a/stats/opentelemetry/trace.go b/stats/opentelemetry/trace.go index 19d41ece5..a61ad3118 100644 --- a/stats/opentelemetry/trace.go +++ b/stats/opentelemetry/trace.go @@ -42,20 +42,26 @@ func populateSpan(rs stats.RPCStats, ai *attemptInfo) { // Note: Go always added Client and FailFast attributes even though they are not // defined by the OpenCensus gRPC spec. Thus, they are unimportant for // correctness. - attrs := []attribute.KeyValue{ + // previousRPCAttempts tracks the number of previous RPC attempts. + // If ai.previousRPCAttempts is nil (which can occur on the server path), + // prevAttempts defaults to 0 to avoid a nil pointer dereference. + previousRPCAttempts := int64(0) + if ai.previousRPCAttempts != nil { + previousRPCAttempts = int64(ai.previousRPCAttempts.Load()) + } + span.SetAttributes( attribute.Bool("Client", rs.Client), attribute.Bool("FailFast", rs.FailFast), - } - if rs.Client { - attrs = append(attrs, - attribute.Int64("previous-rpc-attempts", int64(ai.previousRPCAttempts.Load())), - attribute.Bool("transparent-retry", rs.IsTransparentRetryAttempt), - ) - } - span.SetAttributes(attrs...) + // TODO: Remove "previous-rpc-attempts" and "transparent-retry" + // attributes from server spans. These attributes are only relevant + // to client spans. + attribute.Int64("previous-rpc-attempts", previousRPCAttempts), + attribute.Bool("transparent-retry", rs.IsTransparentRetryAttempt), + ) // Increment retry count for the next attempt if not a transparent - // retry. - if !rs.IsTransparentRetryAttempt && rs.Client { + // retry. Added nil check to avoid panic on server path where + // previousRPCAttempts is not set. + if !rs.IsTransparentRetryAttempt && ai.previousRPCAttempts != nil { ai.previousRPCAttempts.Add(1) } case *stats.PickerUpdated: