package com.github.kristofa.brave.grpc;
import com.github.kristofa.brave.Brave;
import com.github.kristofa.brave.ClientRequestAdapter;
import com.github.kristofa.brave.ClientRequestInterceptor;
import com.github.kristofa.brave.ClientResponseAdapter;
import com.github.kristofa.brave.ClientResponseInterceptor;
import com.github.kristofa.brave.ClientSpanThreadBinder;
import com.github.kristofa.brave.IdConversion;
import com.github.kristofa.brave.KeyValueAnnotation;
import com.github.kristofa.brave.SpanId;
import com.github.kristofa.brave.internal.Nullable;
import com.github.kristofa.brave.internal.Util;
import com.twitter.zipkin.gen.Endpoint;
import com.twitter.zipkin.gen.Span;
import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ForwardingClientCall.SimpleForwardingClientCall;
import io.grpc.ForwardingClientCallListener.SimpleForwardingClientCallListener;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.Status;
import io.grpc.Status.Code;
import java.util.Collection;
import java.util.Collections;
import static com.github.kristofa.brave.grpc.GrpcKeys.GRPC_STATUS_CODE;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* @deprecated Replaced by {@code GrpcTracing} from brave-instrumentation-grpc
*/
@Deprecated
public final class BraveGrpcClientInterceptor implements ClientInterceptor {
/** Creates a tracing interceptor with defaults. Use {@link #builder(Brave)} to customize. */
public static BraveGrpcClientInterceptor create(Brave brave) {
return new Builder(brave).build();
}
public static Builder builder(Brave brave) {
return new Builder(brave);
}
public static final class Builder {
final Brave brave;
Builder(Brave brave) { // intentionally hidden
this.brave = Util.checkNotNull(brave, "brave");
}
public BraveGrpcClientInterceptor build() {
return new BraveGrpcClientInterceptor(this);
}
}
private final ClientRequestInterceptor clientRequestInterceptor;
private final ClientResponseInterceptor clientResponseInterceptor;
private final ClientSpanThreadBinder clientSpanThreadBinder;
BraveGrpcClientInterceptor(Builder b) { // intentionally hidden
this.clientRequestInterceptor = b.brave.clientRequestInterceptor();
this.clientResponseInterceptor = b.brave.clientResponseInterceptor();
this.clientSpanThreadBinder = b.brave.clientSpanThreadBinder();
}
/**
* @deprecated please use {@link #create(Brave)} or {@link #builder(Brave)}
*/
@Deprecated
public BraveGrpcClientInterceptor(Brave brave) {
this.clientRequestInterceptor = checkNotNull(brave.clientRequestInterceptor());
this.clientResponseInterceptor = checkNotNull(brave.clientResponseInterceptor());
this.clientSpanThreadBinder = checkNotNull(brave.clientSpanThreadBinder());
}
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(final MethodDescriptor<ReqT, RespT> method,
final CallOptions callOptions, final Channel next) {
return new SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
clientRequestInterceptor.handle(new GrpcClientRequestAdapter<>(method, headers));
final Span currentClientSpan = clientSpanThreadBinder.getCurrentClientSpan();
super.start(new SimpleForwardingClientCallListener<RespT>(responseListener) {
@Override
public void onClose(Status status, Metadata trailers) {
try {
clientSpanThreadBinder.setCurrentSpan(currentClientSpan);
clientResponseInterceptor.handle(new GrpcClientResponseAdapter(status));
super.onClose(status, trailers);
} finally {
clientSpanThreadBinder.setCurrentSpan(null);
}
}
}, headers);
}
};
}
static final class GrpcClientRequestAdapter<ReqT, RespT> implements ClientRequestAdapter {
private final MethodDescriptor<ReqT, RespT> method;
private final Metadata headers;
public GrpcClientRequestAdapter(MethodDescriptor<ReqT, RespT> method, Metadata headers) {
this.method = checkNotNull(method);
this.headers = checkNotNull(headers);
}
@Override
public String getSpanName() {
return method.getFullMethodName().toLowerCase();
}
@Override
public void addSpanIdToRequest(@Nullable SpanId spanId) {
if (spanId == null) {
headers.put(BravePropagationKeys.Sampled, "0");
} else {
headers.put(BravePropagationKeys.Sampled, "1");
headers.put(BravePropagationKeys.TraceId, spanId.traceIdString());
headers.put(BravePropagationKeys.SpanId, IdConversion.convertToString(spanId.spanId));
if (spanId.nullableParentId() != null) {
headers.put(BravePropagationKeys.ParentSpanId, IdConversion.convertToString(spanId.parentId));
}
}
}
@Override
public Collection<KeyValueAnnotation> requestAnnotations() {
return Collections.emptyList();
}
@Override
public Endpoint serverAddress() {
return null;
}
}
static final class GrpcClientResponseAdapter implements ClientResponseAdapter {
private final Status status;
public GrpcClientResponseAdapter(Status status) {
this.status = checkNotNull(status);
}
@Override
public Collection<KeyValueAnnotation> responseAnnotations() {
Code statusCode = status.getCode();
return statusCode == Code.OK
? Collections.<KeyValueAnnotation>emptyList()
: Collections.singletonList(KeyValueAnnotation.create(GRPC_STATUS_CODE, statusCode.name()));
}
}
}