Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implement an set of interceptor APIs to allow users configure census …
…with cusome settings.
  • Loading branch information
voidzcy committed Jun 24, 2020
commit c81cbfcfe8c22bed355a54ca6c79c7c7d325b2dd
203 changes: 75 additions & 128 deletions census/src/main/java/io/grpc/census/CensusClientInterceptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,184 +16,131 @@

package io.grpc.census;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Stopwatch;
import com.google.common.base.Supplier;
import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ClientInterceptors;
import io.grpc.InternalCensus;
import io.grpc.MethodDescriptor;
import io.opencensus.stats.Stats;
import io.opencensus.stats.StatsRecorder;
import io.opencensus.tags.Tagger;
import io.opencensus.tags.Tags;
import io.opencensus.tags.propagation.TagContextBinarySerializer;
import io.opencensus.trace.Tracer;
import io.opencensus.trace.Tracing;
import io.opencensus.trace.propagation.BinaryFormat;
import java.util.ArrayList;
import java.util.List;

public final class CensusClientInterceptor {
static final CallOptions.Key<Boolean> DISABLE_CLIENT_DEFAULT_CENSUS_STATS =
CallOptions.Key.createWithDefault("Disable default census stats", true);
static final CallOptions.Key<Boolean> DISABLE_CLIENT_DEFAULT_CENSUS_TRACING =
CallOptions.Key.createWithDefault("Disable default census tracing", true);

private static final Supplier<Stopwatch> STOPWATCH_SUPPLIER = new Supplier<Stopwatch>() {
@Override
public Stopwatch get() {
return Stopwatch.createUnstarted();
/**
* A {@link ClientInterceptor} for configuring client side OpenCensus features with
* custom settings. Note OpenCensus stats and tracing features are turned on by default
* if grpc-census artifact is in the runtime classpath. The gRPC core
* library does not provide public APIs for customized OpenCensus configurations.
* Use this interceptor to do so. Intended for advanced usages.
*
* <p>Applying this interceptor disables the channel's default stats and tracing
* features. The effectively OpenCensus features are determined by configurations in this
* interceptor.
*
* <p>For the current release, applying this interceptor may have the side effect that
* effectively disables retry.
*/
// TODO(chengyuanzhang): add ExperimentalApi annotation.
public final class CensusClientInterceptor implements ClientInterceptor {

private final List<ClientInterceptor> interceptors = new ArrayList<>();

private CensusClientInterceptor(
boolean statsEnabled,
boolean recordStartedRpcs,
boolean recordFinishedRpcs,
boolean recordRealTimeMetrics,
boolean tracingEnabled) {
if (statsEnabled) {
CensusStatsModule censusStats =
new CensusStatsModule(recordStartedRpcs, recordFinishedRpcs, recordRealTimeMetrics);
interceptors.add(censusStats.getClientInterceptor());
}
if (tracingEnabled) {
CensusTracingModule censusTracing = new CensusTracingModule();
interceptors.add(censusTracing.getClientInterceptor());
}
};
}

// Prevent instantiation
private CensusClientInterceptor() {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions, Channel next) {
callOptions = callOptions.withOption(InternalCensus.DISABLE_CLIENT_DEFAULT_CENSUS, true);
if (!interceptors.isEmpty()) {
next =
ClientInterceptors.intercept(next, interceptors.toArray(new ClientInterceptor[0]));
}
return next.newCall(method, callOptions);
}

/**
* Creates a new builder for a {@link CensusClientInterceptor}.
*/
public static Builder newBuilder() {
return new Builder();
}

/**
* A builder for a {@link CensusClientInterceptor}.
*/
public static class Builder {
private static final ClientInterceptor NOOP_INTERCEPTOR = new ClientInterceptor() {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
return next.newCall(method, callOptions);
}
};

private boolean statsEnabled;
private boolean recordStartedRpcs;
private boolean recordFinishedRpcs;
private boolean recordRealTimeMetrics;
private Tagger tagger = Tags.getTagger();
private TagContextBinarySerializer tagCtxSerializer =
Tags.getTagPropagationComponent().getBinarySerializer();
private StatsRecorder statsRecorder = Stats.getStatsRecorder();
private Supplier<Stopwatch> stopwatchSupplier = STOPWATCH_SUPPLIER;
private boolean propagateTags = true;

private boolean tracingEnabled;
private Tracer tracer = Tracing.getTracer();
private BinaryFormat binaryFormat = Tracing.getPropagationComponent().getBinaryFormat();

/**
* Disable or enable stats features. Disabled by default.
*/
public Builder setStatsEnabled(boolean value) {
statsEnabled = value;
return this;
}

/**
* Disable or enable real-time metrics recording. Effective only if {@link #setStatsEnabled}
* is set to true. Disabled by default.
*/
public Builder setRecordStartedRpcs(boolean value) {
recordStartedRpcs = value;
return this;
}

/**
* Disable or enable stats recording for RPC completions. Effective only if {@link
* #setStatsEnabled} is set to true. Disabled by default.
*/
public Builder setRecordFinishedRpcs(boolean value) {
recordFinishedRpcs = value;
return this;
}

/**
* Disable or enable stats recording for RPC upstarts. Effective only if {@link
* #setStatsEnabled} is set to true. Disabled by default.
*/
public Builder setRecordRealTimeMetrics(boolean value) {
recordRealTimeMetrics = value;
return this;
}

/**
* Disable or enable tracing features. Disabled by default.
*/
public Builder setTracingEnabled(boolean value) {
tracingEnabled = value;
return this;
}

@VisibleForTesting
Builder setTagger(Tagger tagger) {
this.tagger = tagger;
return this;
}

@VisibleForTesting
Builder setTagCtxSerializer(TagContextBinarySerializer tagCtxSerializer) {
this.tagCtxSerializer = tagCtxSerializer;
return this;
}

@VisibleForTesting
Builder setStatsRecorder(StatsRecorder statsRecorder) {
this.statsRecorder = statsRecorder;
return this;
}

@VisibleForTesting
Builder setStopwatchSupplier(Supplier<Stopwatch> stopwatchSupplier) {
this.stopwatchSupplier = stopwatchSupplier;
return this;
}

@VisibleForTesting
Builder setPropagateTags(boolean propagateTags) {
this.propagateTags = propagateTags;
return this;
}

@VisibleForTesting
Builder setTracer(Tracer tracer) {
this.tracer = tracer;
return this;
}

@VisibleForTesting
Builder setBinaryFormat(BinaryFormat binaryFormat) {
this.binaryFormat = binaryFormat;
return this;
}

public ClientInterceptor build() {
List<ClientInterceptor> interceptors = new ArrayList<>();
if (statsEnabled) {
CensusStatsModule censusStats =
new CensusStatsModule(
tagger,
tagCtxSerializer,
statsRecorder,
stopwatchSupplier,
propagateTags,
recordStartedRpcs,
recordFinishedRpcs,
recordRealTimeMetrics);
interceptors.add(censusStats.getClientInterceptor());
}
if (tracingEnabled) {
CensusTracingModule censusTracing = new CensusTracingModule(tracer, binaryFormat);
interceptors.add(censusTracing.getClientInterceptor());
}
if (interceptors.isEmpty()) {
interceptors.add(NOOP_INTERCEPTOR);
}
return new CustomConfigCensusClientInterceptor(
interceptors.toArray(new ClientInterceptor[0]));
}

private static final class CustomConfigCensusClientInterceptor implements ClientInterceptor {

private final ClientInterceptor[] interceptors;

CustomConfigCensusClientInterceptor(ClientInterceptor... interceptors) {
this.interceptors = interceptors;
}

@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
for (ClientInterceptor interceptor : interceptors) {
next = ClientInterceptors.intercept(next, interceptors);
}
return next.newCall(
method,
callOptions
.withOption(DISABLE_CLIENT_DEFAULT_CENSUS_STATS, true)
.withOption(DISABLE_CLIENT_DEFAULT_CENSUS_TRACING, true));
}
/**
* Builds the {@link CensusClientInterceptor}.
*/
public CensusClientInterceptor build() {
return new CensusClientInterceptor(
statsEnabled, recordStartedRpcs, recordFinishedRpcs, recordRealTimeMetrics,
tracingEnabled);
}
}
}