Implement spec changes for grpc server span error status (#9641)
This commit is contained in:
parent
6980b693dc
commit
13585c6d95
|
@ -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> {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue