Implement spec changes for grpc server span error status (#9641)

This commit is contained in:
Lauri Tulmin 2023-10-10 16:37:02 +03:00 committed by GitHub
parent 6980b693dc
commit 13585c6d95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 14 deletions

View File

@ -5,15 +5,29 @@
package io.opentelemetry.instrumentation.grpc.v1_6; package io.opentelemetry.instrumentation.grpc.v1_6;
import com.google.errorprone.annotations.Immutable;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.StatusException; import io.grpc.StatusException;
import io.grpc.StatusRuntimeException; import io.grpc.StatusRuntimeException;
import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import javax.annotation.Nullable; import javax.annotation.Nullable;
final class GrpcSpanStatusExtractor implements SpanStatusExtractor<GrpcRequest, Status> { enum GrpcSpanStatusExtractor implements SpanStatusExtractor<GrpcRequest, Status> {
CLIENT(GrpcSpanStatusExtractor::isClientError),
SERVER(GrpcSpanStatusExtractor::isServerError);
private final ErrorStatusPredicate isError;
GrpcSpanStatusExtractor(ErrorStatusPredicate isError) {
this.isError = isError;
}
@Override @Override
public void extract( public void extract(
SpanStatusBuilder spanStatusBuilder, SpanStatusBuilder spanStatusBuilder,
@ -28,11 +42,35 @@ final class GrpcSpanStatusExtractor implements SpanStatusExtractor<GrpcRequest,
} }
} }
if (status != null) { if (status != null) {
if (!status.isOk()) { if (isError.test(status)) {
spanStatusBuilder.setStatus(StatusCode.ERROR); spanStatusBuilder.setStatus(StatusCode.ERROR);
} }
} else { } else {
SpanStatusExtractor.getDefault().extract(spanStatusBuilder, request, status, error); SpanStatusExtractor.getDefault().extract(spanStatusBuilder, request, status, error);
} }
} }
private static final Set<Status.Code> serverErrorStatuses = new HashSet<>();
static {
serverErrorStatuses.addAll(
Arrays.asList(
Status.Code.UNKNOWN,
Status.Code.DEADLINE_EXCEEDED,
Status.Code.UNIMPLEMENTED,
Status.Code.INTERNAL,
Status.Code.UNAVAILABLE,
Status.Code.DATA_LOSS));
}
private static boolean isServerError(Status status) {
return serverErrorStatuses.contains(status.getCode());
}
private static boolean isClientError(Status status) {
return !status.isOk();
}
@Immutable
private interface ErrorStatusPredicate extends Predicate<Status> {}
} }

View File

@ -25,7 +25,6 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Stream;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** A builder of {@link GrpcTelemetry}. */ /** A builder of {@link GrpcTelemetry}. */
@ -167,13 +166,6 @@ public final class GrpcTelemetryBuilder {
InstrumenterBuilder<GrpcRequest, Status> serverInstrumenterBuilder = InstrumenterBuilder<GrpcRequest, Status> serverInstrumenterBuilder =
Instrumenter.builder(openTelemetry, INSTRUMENTATION_NAME, serverSpanNameExtractor); Instrumenter.builder(openTelemetry, INSTRUMENTATION_NAME, serverSpanNameExtractor);
Stream.of(clientInstrumenterBuilder, serverInstrumenterBuilder)
.forEach(
instrumenter ->
instrumenter
.setSpanStatusExtractor(new GrpcSpanStatusExtractor())
.addAttributesExtractors(additionalExtractors));
GrpcClientNetworkAttributesGetter netClientAttributesGetter = GrpcClientNetworkAttributesGetter netClientAttributesGetter =
new GrpcClientNetworkAttributesGetter(); new GrpcClientNetworkAttributesGetter();
GrpcNetworkServerAttributesGetter netServerAttributesGetter = GrpcNetworkServerAttributesGetter netServerAttributesGetter =
@ -181,6 +173,8 @@ public final class GrpcTelemetryBuilder {
GrpcRpcAttributesGetter rpcAttributesGetter = GrpcRpcAttributesGetter.INSTANCE; GrpcRpcAttributesGetter rpcAttributesGetter = GrpcRpcAttributesGetter.INSTANCE;
clientInstrumenterBuilder clientInstrumenterBuilder
.setSpanStatusExtractor(GrpcSpanStatusExtractor.CLIENT)
.addAttributesExtractors(additionalExtractors)
.addAttributesExtractor(RpcClientAttributesExtractor.create(rpcAttributesGetter)) .addAttributesExtractor(RpcClientAttributesExtractor.create(rpcAttributesGetter))
.addAttributesExtractor(ServerAttributesExtractor.create(netClientAttributesGetter)) .addAttributesExtractor(ServerAttributesExtractor.create(netClientAttributesGetter))
.addAttributesExtractors(additionalClientExtractors) .addAttributesExtractors(additionalClientExtractors)
@ -189,6 +183,8 @@ public final class GrpcTelemetryBuilder {
GrpcRpcAttributesGetter.INSTANCE, capturedClientRequestMetadata)) GrpcRpcAttributesGetter.INSTANCE, capturedClientRequestMetadata))
.addOperationMetrics(RpcClientMetrics.get()); .addOperationMetrics(RpcClientMetrics.get());
serverInstrumenterBuilder serverInstrumenterBuilder
.setSpanStatusExtractor(GrpcSpanStatusExtractor.SERVER)
.addAttributesExtractors(additionalExtractors)
.addAttributesExtractor(RpcServerAttributesExtractor.create(rpcAttributesGetter)) .addAttributesExtractor(RpcServerAttributesExtractor.create(rpcAttributesGetter))
.addAttributesExtractor( .addAttributesExtractor(
ServerAttributesExtractor.createForServerSide(netServerAttributesGetter)) ServerAttributesExtractor.createForServerSide(netServerAttributesGetter))

View File

@ -604,6 +604,7 @@ public abstract class AbstractGrpcTest {
assertThat(t.getStatus().getDescription()).isEqualTo(status.getDescription()); assertThat(t.getStatus().getDescription()).isEqualTo(status.getDescription());
}); });
boolean isServerError = status.getCode() != Status.Code.NOT_FOUND;
testing() testing()
.waitAndAssertTraces( .waitAndAssertTraces(
trace -> trace ->
@ -635,7 +636,7 @@ public abstract class AbstractGrpcTest {
span.hasName("example.Greeter/SayHello") span.hasName("example.Greeter/SayHello")
.hasKind(SpanKind.SERVER) .hasKind(SpanKind.SERVER)
.hasParent(trace.getSpan(0)) .hasParent(trace.getSpan(0))
.hasStatus(StatusData.error()) .hasStatus(isServerError ? StatusData.error() : StatusData.unset())
.hasAttributesSatisfyingExactly( .hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.RPC_SYSTEM, "grpc"), equalTo(SemanticAttributes.RPC_SYSTEM, "grpc"),
equalTo(SemanticAttributes.RPC_SERVICE, "example.Greeter"), equalTo(SemanticAttributes.RPC_SERVICE, "example.Greeter"),
@ -863,11 +864,19 @@ public abstract class AbstractGrpcTest {
public Stream<? extends Arguments> provideArguments(ExtensionContext context) { public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of( return Stream.of(
arguments(Status.UNKNOWN.withCause(new RuntimeException("some error"))), arguments(Status.UNKNOWN.withCause(new RuntimeException("some error"))),
arguments(Status.PERMISSION_DENIED.withCause(new RuntimeException("some error"))), arguments(Status.DEADLINE_EXCEEDED.withCause(new RuntimeException("some error"))),
arguments(Status.UNIMPLEMENTED.withCause(new RuntimeException("some error"))), arguments(Status.UNIMPLEMENTED.withCause(new RuntimeException("some error"))),
arguments(Status.INTERNAL.withCause(new RuntimeException("some error"))),
arguments(Status.UNAVAILABLE.withCause(new RuntimeException("some error"))),
arguments(Status.DATA_LOSS.withCause(new RuntimeException("some error"))),
arguments(Status.NOT_FOUND.withCause(new RuntimeException("some error"))),
arguments(Status.UNKNOWN.withDescription("some description")), arguments(Status.UNKNOWN.withDescription("some description")),
arguments(Status.PERMISSION_DENIED.withDescription("some description")), arguments(Status.DEADLINE_EXCEEDED.withDescription("some description")),
arguments(Status.UNIMPLEMENTED.withDescription("some description"))); arguments(Status.UNIMPLEMENTED.withDescription("some description")),
arguments(Status.INTERNAL.withDescription("some description")),
arguments(Status.UNAVAILABLE.withDescription("some description")),
arguments(Status.DATA_LOSS.withDescription("some description")),
arguments(Status.NOT_FOUND.withDescription("some description")));
} }
} }