mirror of https://github.com/grpc/grpc-java.git
gcp-observability: Populate global interceptors from observability (#9309)
* Populate global interceptors from observability and added stackdriver exporters
This commit is contained in:
parent
49f555192d
commit
ef89bd3ac9
|
|
@ -73,24 +73,19 @@ final class GlobalInterceptors {
|
|||
isGlobalInterceptorsTracersSet = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of global {@link ClientInterceptor}. If not set, this returns am empty list.
|
||||
*/
|
||||
/** Returns the list of global {@link ClientInterceptor}. If not set, this returns null. */
|
||||
static synchronized List<ClientInterceptor> getClientInterceptors() {
|
||||
isGlobalInterceptorsTracersGet = true;
|
||||
return clientInterceptors;
|
||||
}
|
||||
|
||||
/** Returns list of global {@link ServerInterceptor}. If not set, this returns an empty list. */
|
||||
/** Returns list of global {@link ServerInterceptor}. If not set, this returns null. */
|
||||
static synchronized List<ServerInterceptor> getServerInterceptors() {
|
||||
isGlobalInterceptorsTracersGet = true;
|
||||
return serverInterceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of global {@link ServerStreamTracer.Factory}. If not set, this returns an empty
|
||||
* list.
|
||||
*/
|
||||
/** Returns list of global {@link ServerStreamTracer.Factory}. If not set, this returns null. */
|
||||
static synchronized List<ServerStreamTracer.Factory> getServerStreamTracerFactories() {
|
||||
isGlobalInterceptorsTracersGet = true;
|
||||
return serverStreamTracerFactories;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ dependencies {
|
|||
project(':grpc-alts'),
|
||||
project(':grpc-census'),
|
||||
("com.google.cloud:google-cloud-logging:${cloudLoggingVersion}"),
|
||||
libraries.opencensus.contrib.grpc.metrics,
|
||||
libraries.opencensus.exporter.stats.stackdriver,
|
||||
libraries.opencensus.exporter.trace.stackdriver,
|
||||
libraries.animalsniffer.annotations, // Prefer our version
|
||||
|
|
@ -41,7 +42,8 @@ dependencies {
|
|||
|
||||
runtimeOnly libraries.opencensus.impl
|
||||
|
||||
testImplementation project(':grpc-testing'),
|
||||
testImplementation project(':grpc-context').sourceSets.test.output,
|
||||
project(':grpc-testing'),
|
||||
project(':grpc-testing-proto'),
|
||||
project(':grpc-netty-shaded')
|
||||
testImplementation (libraries.guava.testlib) {
|
||||
|
|
|
|||
|
|
@ -19,8 +19,14 @@ package io.grpc.gcp.observability;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.grpc.ClientInterceptor;
|
||||
import io.grpc.ExperimentalApi;
|
||||
import io.grpc.InternalGlobalInterceptors;
|
||||
import io.grpc.ManagedChannelProvider.ProviderNotFoundException;
|
||||
import io.grpc.ServerInterceptor;
|
||||
import io.grpc.ServerStreamTracer;
|
||||
import io.grpc.census.InternalCensusStatsAccessor;
|
||||
import io.grpc.census.InternalCensusTracingAccessor;
|
||||
import io.grpc.gcp.observability.interceptors.ConfigFilterHelper;
|
||||
import io.grpc.gcp.observability.interceptors.InternalLoggingChannelInterceptor;
|
||||
import io.grpc.gcp.observability.interceptors.InternalLoggingServerInterceptor;
|
||||
|
|
@ -28,13 +34,30 @@ import io.grpc.gcp.observability.interceptors.LogHelper;
|
|||
import io.grpc.gcp.observability.logging.GcpLogSink;
|
||||
import io.grpc.gcp.observability.logging.Sink;
|
||||
import io.grpc.internal.TimeProvider;
|
||||
import io.opencensus.contrib.grpc.metrics.RpcViews;
|
||||
import io.opencensus.exporter.stats.stackdriver.StackdriverStatsConfiguration;
|
||||
import io.opencensus.exporter.stats.stackdriver.StackdriverStatsExporter;
|
||||
import io.opencensus.exporter.trace.stackdriver.StackdriverTraceConfiguration;
|
||||
import io.opencensus.exporter.trace.stackdriver.StackdriverTraceExporter;
|
||||
import io.opencensus.trace.Tracing;
|
||||
import io.opencensus.trace.config.TraceConfig;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/** The main class for gRPC Google Cloud Platform Observability features. */
|
||||
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/8869")
|
||||
public final class GcpObservability implements AutoCloseable {
|
||||
private static final Logger logger = Logger.getLogger(GcpObservability.class.getName());
|
||||
private static GcpObservability instance = null;
|
||||
private final Sink sink;
|
||||
private final ObservabilityConfig config;
|
||||
private final ArrayList<ClientInterceptor> clientInterceptors = new ArrayList<>();
|
||||
private final ArrayList<ServerInterceptor> serverInterceptors = new ArrayList<>();
|
||||
private final ArrayList<ServerStreamTracer.Factory> tracerFactories = new ArrayList<>();
|
||||
private boolean metricsEnabled;
|
||||
private boolean tracesEnabled;
|
||||
|
||||
/**
|
||||
* Initialize grpc-observability.
|
||||
|
|
@ -48,20 +71,33 @@ public final class GcpObservability implements AutoCloseable {
|
|||
Sink sink = new GcpLogSink(observabilityConfig.getDestinationProjectId(),
|
||||
globalLoggingTags.getLocationTags(), globalLoggingTags.getCustomTags(),
|
||||
observabilityConfig.getFlushMessageCount());
|
||||
// TODO(dnvindhya): Cleanup code for LoggingChannelProvider and LoggingServerProvider
|
||||
// once ChannelBuilder and ServerBuilder are used
|
||||
LogHelper helper = new LogHelper(sink, TimeProvider.SYSTEM_TIME_PROVIDER);
|
||||
ConfigFilterHelper configFilterHelper = ConfigFilterHelper.factory(observabilityConfig);
|
||||
instance = grpcInit(sink,
|
||||
instance = grpcInit(sink, observabilityConfig,
|
||||
new InternalLoggingChannelInterceptor.FactoryImpl(helper, configFilterHelper),
|
||||
new InternalLoggingServerInterceptor.FactoryImpl(helper, configFilterHelper));
|
||||
instance.registerStackDriverExporter(observabilityConfig.getDestinationProjectId());
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@VisibleForTesting static GcpObservability grpcInit(Sink sink,
|
||||
@VisibleForTesting
|
||||
static GcpObservability grpcInit(
|
||||
Sink sink,
|
||||
ObservabilityConfig config,
|
||||
InternalLoggingChannelInterceptor.Factory channelInterceptorFactory,
|
||||
InternalLoggingServerInterceptor.Factory serverInterceptorFactory) {
|
||||
InternalLoggingServerInterceptor.Factory serverInterceptorFactory)
|
||||
throws IOException {
|
||||
if (instance == null) {
|
||||
instance = new GcpObservability(sink, channelInterceptorFactory, serverInterceptorFactory);
|
||||
instance =
|
||||
new GcpObservability(sink, config, channelInterceptorFactory, serverInterceptorFactory);
|
||||
LogHelper logHelper = new LogHelper(sink, TimeProvider.SYSTEM_TIME_PROVIDER);
|
||||
ConfigFilterHelper logFilterHelper = ConfigFilterHelper.factory(config);
|
||||
instance.setProducer(
|
||||
new InternalLoggingChannelInterceptor.FactoryImpl(logHelper, logFilterHelper),
|
||||
new InternalLoggingServerInterceptor.FactoryImpl(logHelper, logFilterHelper));
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
|
@ -73,6 +109,7 @@ public final class GcpObservability implements AutoCloseable {
|
|||
if (instance == null) {
|
||||
throw new IllegalStateException("GcpObservability already closed!");
|
||||
}
|
||||
unRegisterStackDriverExporter();
|
||||
LoggingChannelProvider.shutdown();
|
||||
LoggingServerProvider.shutdown();
|
||||
sink.close();
|
||||
|
|
@ -80,10 +117,84 @@ public final class GcpObservability implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
private GcpObservability(Sink sink,
|
||||
private void setProducer(
|
||||
InternalLoggingChannelInterceptor.Factory channelInterceptorFactory,
|
||||
InternalLoggingServerInterceptor.Factory serverInterceptorFactory) {
|
||||
if (config.isEnableCloudLogging()) {
|
||||
clientInterceptors.add(channelInterceptorFactory.create());
|
||||
serverInterceptors.add(serverInterceptorFactory.create());
|
||||
}
|
||||
if (config.isEnableCloudMonitoring()) {
|
||||
clientInterceptors.add(
|
||||
InternalCensusStatsAccessor.getClientInterceptor(true, true, true, true));
|
||||
tracerFactories.add(
|
||||
InternalCensusStatsAccessor.getServerStreamTracerFactory(true, true, true));
|
||||
}
|
||||
if (config.isEnableCloudTracing()) {
|
||||
clientInterceptors.add(InternalCensusTracingAccessor.getClientInterceptor());
|
||||
tracerFactories.add(InternalCensusTracingAccessor.getServerStreamTracerFactory());
|
||||
}
|
||||
|
||||
InternalGlobalInterceptors.setInterceptorsTracers(
|
||||
clientInterceptors, serverInterceptors, tracerFactories);
|
||||
}
|
||||
|
||||
private void registerStackDriverExporter(String projectId) throws IOException {
|
||||
if (config.isEnableCloudMonitoring()) {
|
||||
RpcViews.registerAllGrpcViews();
|
||||
StackdriverStatsConfiguration.Builder statsConfigurationBuilder =
|
||||
StackdriverStatsConfiguration.builder();
|
||||
if (projectId != null) {
|
||||
statsConfigurationBuilder.setProjectId(projectId);
|
||||
}
|
||||
StackdriverStatsExporter.createAndRegister(statsConfigurationBuilder.build());
|
||||
metricsEnabled = true;
|
||||
}
|
||||
|
||||
if (config.isEnableCloudTracing()) {
|
||||
TraceConfig traceConfig = Tracing.getTraceConfig();
|
||||
traceConfig.updateActiveTraceParams(
|
||||
traceConfig.getActiveTraceParams().toBuilder().setSampler(config.getSampler()).build());
|
||||
StackdriverTraceConfiguration.Builder traceConfigurationBuilder =
|
||||
StackdriverTraceConfiguration.builder();
|
||||
if (projectId != null) {
|
||||
traceConfigurationBuilder.setProjectId(projectId);
|
||||
}
|
||||
StackdriverTraceExporter.createAndRegister(traceConfigurationBuilder.build());
|
||||
tracesEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void unRegisterStackDriverExporter() {
|
||||
if (metricsEnabled) {
|
||||
try {
|
||||
StackdriverStatsExporter.unregister();
|
||||
} catch (IllegalStateException e) {
|
||||
logger.log(
|
||||
Level.SEVERE, "Failed to unregister Stackdriver stats exporter, " + e.getMessage());
|
||||
}
|
||||
metricsEnabled = false;
|
||||
}
|
||||
|
||||
if (tracesEnabled) {
|
||||
try {
|
||||
StackdriverTraceExporter.unregister();
|
||||
} catch (IllegalStateException e) {
|
||||
logger.log(
|
||||
Level.SEVERE, "Failed to unregister Stackdriver trace exporter, " + e.getMessage());
|
||||
}
|
||||
tracesEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private GcpObservability(
|
||||
Sink sink,
|
||||
ObservabilityConfig config,
|
||||
InternalLoggingChannelInterceptor.Factory channelInterceptorFactory,
|
||||
InternalLoggingServerInterceptor.Factory serverInterceptorFactory) {
|
||||
this.sink = checkNotNull(sink);
|
||||
this.config = checkNotNull(config);
|
||||
|
||||
LoggingChannelProvider.init(checkNotNull(channelInterceptorFactory));
|
||||
LoggingServerProvider.init(checkNotNull(serverInterceptorFactory));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package io.grpc.gcp.observability;
|
|||
|
||||
import io.grpc.Internal;
|
||||
import io.grpc.observabilitylog.v1.GrpcLogRecord.EventType;
|
||||
import io.opencensus.trace.Sampler;
|
||||
import java.util.List;
|
||||
|
||||
@Internal
|
||||
|
|
@ -43,6 +44,7 @@ public interface ObservabilityConfig {
|
|||
/** Get event types to log. */
|
||||
List<EventType> getEventTypes();
|
||||
|
||||
/** Get sampler for TraceConfig - when Cloud Tracing is enabled. */
|
||||
Sampler getSampler();
|
||||
|
||||
/**
|
||||
|
|
@ -71,34 +73,4 @@ public interface ObservabilityConfig {
|
|||
this.messageBytes = messageBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/** Corresponds to a {@link io.opencensus.trace.Sampler} type. */
|
||||
enum SamplerType {
|
||||
ALWAYS,
|
||||
NEVER,
|
||||
PROBABILISTIC;
|
||||
}
|
||||
|
||||
/** Represents a trace {@link io.opencensus.trace.Sampler} configuration. */
|
||||
class Sampler {
|
||||
private SamplerType type;
|
||||
private double probability;
|
||||
|
||||
Sampler(double probability) {
|
||||
this.probability = probability;
|
||||
this.type = SamplerType.PROBABILISTIC;
|
||||
}
|
||||
|
||||
Sampler(SamplerType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
double getProbability() {
|
||||
return probability;
|
||||
}
|
||||
|
||||
SamplerType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import com.google.common.collect.ImmutableList;
|
|||
import io.grpc.internal.JsonParser;
|
||||
import io.grpc.internal.JsonUtil;
|
||||
import io.grpc.observabilitylog.v1.GrpcLogRecord.EventType;
|
||||
import io.opencensus.trace.Sampler;
|
||||
import io.opencensus.trace.samplers.Samplers;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
|
@ -35,6 +37,8 @@ import java.util.Map;
|
|||
final class ObservabilityConfigImpl implements ObservabilityConfig {
|
||||
private static final String CONFIG_ENV_VAR_NAME = "GRPC_CONFIG_OBSERVABILITY";
|
||||
private static final String CONFIG_FILE_ENV_VAR_NAME = "GRPC_CONFIG_OBSERVABILITY_JSON";
|
||||
// Tolerance for floating-point comparisons.
|
||||
private static final double EPSILON = 1e-6;
|
||||
|
||||
private boolean enableCloudLogging = false;
|
||||
private boolean enableCloudMonitoring = false;
|
||||
|
|
@ -100,19 +104,21 @@ final class ObservabilityConfigImpl implements ObservabilityConfig {
|
|||
}
|
||||
this.eventTypes = eventTypesBuilder.build();
|
||||
}
|
||||
String sampler = JsonUtil.getString(config, "global_trace_sampler");
|
||||
Double samplingRate = JsonUtil.getNumberAsDouble(config, "global_trace_sampling_rate");
|
||||
checkArgument(
|
||||
sampler == null || samplingRate == null,
|
||||
"only one of 'global_trace_sampler' or 'global_trace_sampling_rate' can be specified");
|
||||
if (sampler != null) {
|
||||
this.sampler = new Sampler(SamplerType.valueOf(sampler.toUpperCase()));
|
||||
}
|
||||
if (samplingRate != null) {
|
||||
if (samplingRate == null) {
|
||||
this.sampler = Samplers.probabilitySampler(0.0);
|
||||
} else {
|
||||
checkArgument(
|
||||
samplingRate >= 0.0 && samplingRate <= 1.0,
|
||||
"'global_trace_sampling_rate' needs to be between 0.0 and 1.0");
|
||||
this.sampler = new Sampler(samplingRate);
|
||||
"'global_trace_sampling_rate' needs to be between [0.0, 1.0]");
|
||||
// Using alwaysSample() instead of probabilitySampler() because according to
|
||||
// {@link io.opencensus.trace.samplers.ProbabilitySampler#shouldSample}
|
||||
// there is a (very) small chance of *not* sampling if probability = 1.00.
|
||||
if (1 - samplingRate < EPSILON) {
|
||||
this.sampler = Samplers.alwaysSample();
|
||||
} else {
|
||||
this.sampler = Samplers.probabilitySampler(samplingRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,48 +18,185 @@ package io.grpc.gcp.observability;
|
|||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.AdditionalAnswers.delegatesTo;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import io.grpc.CallOptions;
|
||||
import io.grpc.Channel;
|
||||
import io.grpc.ClientCall;
|
||||
import io.grpc.ClientInterceptor;
|
||||
import io.grpc.InternalGlobalInterceptors;
|
||||
import io.grpc.ManagedChannelProvider;
|
||||
import io.grpc.Metadata;
|
||||
import io.grpc.MethodDescriptor;
|
||||
import io.grpc.ServerCall;
|
||||
import io.grpc.ServerCallHandler;
|
||||
import io.grpc.ServerInterceptor;
|
||||
import io.grpc.ServerProvider;
|
||||
import io.grpc.StaticTestingClassLoader;
|
||||
import io.grpc.gcp.observability.interceptors.InternalLoggingChannelInterceptor;
|
||||
import io.grpc.gcp.observability.interceptors.InternalLoggingServerInterceptor;
|
||||
import io.grpc.gcp.observability.logging.Sink;
|
||||
import io.opencensus.trace.samplers.Samplers;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class GcpObservabilityTest {
|
||||
|
||||
@Test
|
||||
public void initFinish() {
|
||||
ManagedChannelProvider prevChannelProvider = ManagedChannelProvider.provider();
|
||||
ServerProvider prevServerProvider = ServerProvider.provider();
|
||||
Sink sink = mock(Sink.class);
|
||||
InternalLoggingChannelInterceptor.Factory channelInterceptorFactory = mock(
|
||||
InternalLoggingChannelInterceptor.Factory.class);
|
||||
InternalLoggingServerInterceptor.Factory serverInterceptorFactory = mock(
|
||||
InternalLoggingServerInterceptor.Factory.class);
|
||||
GcpObservability observability1;
|
||||
try (GcpObservability observability = GcpObservability.grpcInit(sink, channelInterceptorFactory,
|
||||
serverInterceptorFactory)) {
|
||||
assertThat(ManagedChannelProvider.provider()).isInstanceOf(LoggingChannelProvider.class);
|
||||
assertThat(ServerProvider.provider()).isInstanceOf(ServerProvider.class);
|
||||
observability1 = GcpObservability.grpcInit(sink, channelInterceptorFactory,
|
||||
serverInterceptorFactory);
|
||||
assertThat(observability1).isSameInstanceAs(observability);
|
||||
|
||||
private final StaticTestingClassLoader classLoader =
|
||||
new StaticTestingClassLoader(
|
||||
getClass().getClassLoader(),
|
||||
Pattern.compile(
|
||||
"io\\.grpc\\.InternalGlobalInterceptors|io\\.grpc\\.GlobalInterceptors|"
|
||||
+ "io\\.grpc\\.gcp\\.observability\\.[^.]+|"
|
||||
+ "io\\.grpc\\.gcp\\.observability\\.interceptors\\.[^.]+|"
|
||||
+ "io\\.grpc\\.gcp\\.observability\\.GcpObservabilityTest\\$.*"));
|
||||
|
||||
@Test
|
||||
public void initFinish() throws Exception {
|
||||
Class<?> runnable =
|
||||
classLoader.loadClass(StaticTestingClassInitFinish.class.getName());
|
||||
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableObservability() throws Exception {
|
||||
Class<?> runnable =
|
||||
classLoader.loadClass(StaticTestingClassEnableObservability.class.getName());
|
||||
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableObservability() throws Exception {
|
||||
Class<?> runnable =
|
||||
classLoader.loadClass(StaticTestingClassDisableObservability.class.getName());
|
||||
((Runnable) runnable.getDeclaredConstructor().newInstance()).run();
|
||||
}
|
||||
|
||||
// UsedReflectively
|
||||
public static final class StaticTestingClassInitFinish implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// TODO(dnvindhya) : Remove usage of Providers on cleaning up Logging*Provider
|
||||
ManagedChannelProvider prevChannelProvider = ManagedChannelProvider.provider();
|
||||
ServerProvider prevServerProvider = ServerProvider.provider();
|
||||
Sink sink = mock(Sink.class);
|
||||
ObservabilityConfig config = mock(ObservabilityConfig.class);
|
||||
InternalLoggingChannelInterceptor.Factory channelInterceptorFactory =
|
||||
mock(InternalLoggingChannelInterceptor.Factory.class);
|
||||
InternalLoggingServerInterceptor.Factory serverInterceptorFactory =
|
||||
mock(InternalLoggingServerInterceptor.Factory.class);
|
||||
GcpObservability observability1;
|
||||
try {
|
||||
GcpObservability observability =
|
||||
GcpObservability.grpcInit(
|
||||
sink, config, channelInterceptorFactory, serverInterceptorFactory);
|
||||
assertThat(ManagedChannelProvider.provider()).isInstanceOf(LoggingChannelProvider.class);
|
||||
assertThat(ServerProvider.provider()).isInstanceOf(ServerProvider.class);
|
||||
observability1 =
|
||||
GcpObservability.grpcInit(
|
||||
sink, config, channelInterceptorFactory, serverInterceptorFactory);
|
||||
assertThat(observability1).isSameInstanceAs(observability);
|
||||
observability.close();
|
||||
verify(sink).close();
|
||||
assertThat(ManagedChannelProvider.provider()).isSameInstanceAs(prevChannelProvider);
|
||||
assertThat(ServerProvider.provider()).isSameInstanceAs(prevServerProvider);
|
||||
try {
|
||||
observability1.close();
|
||||
fail("should have failed for calling close() second time");
|
||||
} catch (IllegalStateException e) {
|
||||
assertThat(e).hasMessageThat().contains("GcpObservability already closed!");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
fail("Encountered exception: " + e);
|
||||
}
|
||||
}
|
||||
verify(sink).close();
|
||||
assertThat(ManagedChannelProvider.provider()).isSameInstanceAs(prevChannelProvider);
|
||||
assertThat(ServerProvider.provider()).isSameInstanceAs(prevServerProvider);
|
||||
try {
|
||||
observability1.close();
|
||||
fail("should have failed for calling close() second time");
|
||||
} catch (IllegalStateException e) {
|
||||
assertThat(e).hasMessageThat().contains("GcpObservability already closed!");
|
||||
}
|
||||
|
||||
public static final class StaticTestingClassEnableObservability implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Sink sink = mock(Sink.class);
|
||||
ObservabilityConfig config = mock(ObservabilityConfig.class);
|
||||
when(config.isEnableCloudLogging()).thenReturn(true);
|
||||
when(config.isEnableCloudMonitoring()).thenReturn(true);
|
||||
when(config.isEnableCloudTracing()).thenReturn(true);
|
||||
when(config.getSampler()).thenReturn(Samplers.neverSample());
|
||||
|
||||
ClientInterceptor clientInterceptor =
|
||||
mock(ClientInterceptor.class, delegatesTo(new NoopClientInterceptor()));
|
||||
InternalLoggingChannelInterceptor.Factory channelInterceptorFactory =
|
||||
mock(InternalLoggingChannelInterceptor.Factory.class);
|
||||
when(channelInterceptorFactory.create()).thenReturn(clientInterceptor);
|
||||
|
||||
ServerInterceptor serverInterceptor =
|
||||
mock(ServerInterceptor.class, delegatesTo(new NoopServerInterceptor()));
|
||||
InternalLoggingServerInterceptor.Factory serverInterceptorFactory =
|
||||
mock(InternalLoggingServerInterceptor.Factory.class);
|
||||
when(serverInterceptorFactory.create()).thenReturn(serverInterceptor);
|
||||
|
||||
try (GcpObservability unused =
|
||||
GcpObservability.grpcInit(
|
||||
sink, config, channelInterceptorFactory, serverInterceptorFactory)) {
|
||||
assertThat(InternalGlobalInterceptors.getClientInterceptors()).hasSize(3);
|
||||
assertThat(InternalGlobalInterceptors.getServerInterceptors()).hasSize(1);
|
||||
assertThat(InternalGlobalInterceptors.getServerStreamTracerFactories()).hasSize(2);
|
||||
} catch (Exception e) {
|
||||
fail("Encountered exception: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class StaticTestingClassDisableObservability implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Sink sink = mock(Sink.class);
|
||||
ObservabilityConfig config = mock(ObservabilityConfig.class);
|
||||
when(config.isEnableCloudLogging()).thenReturn(false);
|
||||
when(config.isEnableCloudMonitoring()).thenReturn(false);
|
||||
when(config.isEnableCloudTracing()).thenReturn(false);
|
||||
when(config.getSampler()).thenReturn(Samplers.neverSample());
|
||||
|
||||
InternalLoggingChannelInterceptor.Factory channelInterceptorFactory =
|
||||
mock(InternalLoggingChannelInterceptor.Factory.class);
|
||||
InternalLoggingServerInterceptor.Factory serverInterceptorFactory =
|
||||
mock(InternalLoggingServerInterceptor.Factory.class);;
|
||||
|
||||
try (GcpObservability unused =
|
||||
GcpObservability.grpcInit(
|
||||
sink, config, channelInterceptorFactory, serverInterceptorFactory)) {
|
||||
assertThat(InternalGlobalInterceptors.getClientInterceptors()).isEmpty();
|
||||
assertThat(InternalGlobalInterceptors.getServerInterceptors()).isEmpty();
|
||||
assertThat(InternalGlobalInterceptors.getServerStreamTracerFactories()).isEmpty();
|
||||
} catch (Exception e) {
|
||||
fail("Encountered exception: " + e);
|
||||
}
|
||||
verify(sink).close();
|
||||
}
|
||||
}
|
||||
|
||||
private static class NoopClientInterceptor implements ClientInterceptor {
|
||||
@Override
|
||||
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
|
||||
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
|
||||
return next.newCall(method, callOptions);
|
||||
}
|
||||
}
|
||||
|
||||
private static class NoopServerInterceptor implements ServerInterceptor {
|
||||
@Override
|
||||
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
|
||||
ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
|
||||
return next.startCall(call, headers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ import com.google.common.base.Charsets;
|
|||
import com.google.common.collect.ImmutableList;
|
||||
import io.grpc.gcp.observability.ObservabilityConfig.LogFilter;
|
||||
import io.grpc.observabilitylog.v1.GrpcLogRecord.EventType;
|
||||
|
||||
import io.opencensus.trace.Sampler;
|
||||
import io.opencensus.trace.samplers.Samplers;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
|
@ -77,35 +78,33 @@ public class ObservabilityConfigImplTest {
|
|||
+ "}";
|
||||
|
||||
private static final String ENABLE_CLOUD_MONITORING_AND_TRACING = "{\n"
|
||||
+ " \"enable_cloud_monitoring\": true,\n"
|
||||
+ " \"enable_cloud_tracing\": true\n"
|
||||
+ "}";
|
||||
+ " \"enable_cloud_monitoring\": true,\n"
|
||||
+ " \"enable_cloud_tracing\": true\n"
|
||||
+ "}";
|
||||
|
||||
private static final String GLOBAL_TRACING_ALWAYS_SAMPLER = "{\n"
|
||||
+ " \"enable_cloud_tracing\": true,\n"
|
||||
+ " \"global_trace_sampler\": \"always\"\n"
|
||||
+ "}";
|
||||
+ " \"enable_cloud_tracing\": true,\n"
|
||||
+ " \"global_trace_sampling_rate\": 1.00\n"
|
||||
+ "}";
|
||||
|
||||
private static final String GLOBAL_TRACING_NEVER_SAMPLER = "{\n"
|
||||
+ " \"enable_cloud_tracing\": true,\n"
|
||||
+ " \"global_trace_sampler\": \"never\"\n"
|
||||
+ "}";
|
||||
+ " \"enable_cloud_tracing\": true,\n"
|
||||
+ " \"global_trace_sampling_rate\": 0.00\n"
|
||||
+ "}";
|
||||
|
||||
private static final String GLOBAL_TRACING_PROBABILISTIC_SAMPLER = "{\n"
|
||||
+ " \"enable_cloud_tracing\": true,\n"
|
||||
+ " \"global_trace_sampling_rate\": 0.75\n"
|
||||
+ "}";
|
||||
+ " \"enable_cloud_tracing\": true,\n"
|
||||
+ " \"global_trace_sampling_rate\": 0.75\n"
|
||||
+ "}";
|
||||
|
||||
private static final String GLOBAL_TRACING_BOTH_SAMPLER_ERROR = "{\n"
|
||||
+ " \"enable_cloud_tracing\": true,\n"
|
||||
+ " \"global_trace_sampler\": \"never\",\n"
|
||||
+ " \"global_trace_sampling_rate\": 0.75\n"
|
||||
+ "}";
|
||||
private static final String GLOBAL_TRACING_DEFAULT_SAMPLER = "{\n"
|
||||
+ " \"enable_cloud_tracing\": true\n"
|
||||
+ "}";
|
||||
|
||||
private static final String GLOBAL_TRACING_BADPROBABILISTIC_SAMPLER = "{\n"
|
||||
+ " \"enable_cloud_tracing\": true,\n"
|
||||
+ " \"global_trace_sampling_rate\": -0.75\n"
|
||||
+ "}";
|
||||
+ " \"enable_cloud_tracing\": true,\n"
|
||||
+ " \"global_trace_sampling_rate\": -0.75\n"
|
||||
+ "}";
|
||||
|
||||
|
||||
ObservabilityConfigImpl observabilityConfig = new ObservabilityConfigImpl();
|
||||
|
|
@ -198,41 +197,36 @@ public class ObservabilityConfigImplTest {
|
|||
public void alwaysSampler() throws IOException {
|
||||
observabilityConfig.parse(GLOBAL_TRACING_ALWAYS_SAMPLER);
|
||||
assertTrue(observabilityConfig.isEnableCloudTracing());
|
||||
ObservabilityConfig.Sampler sampler = observabilityConfig.getSampler();
|
||||
Sampler sampler = observabilityConfig.getSampler();
|
||||
assertThat(sampler).isNotNull();
|
||||
assertThat(sampler.getType()).isEqualTo(ObservabilityConfig.SamplerType.ALWAYS);
|
||||
assertThat(sampler).isEqualTo(Samplers.alwaysSample());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void neverSampler() throws IOException {
|
||||
observabilityConfig.parse(GLOBAL_TRACING_NEVER_SAMPLER);
|
||||
assertTrue(observabilityConfig.isEnableCloudTracing());
|
||||
ObservabilityConfig.Sampler sampler = observabilityConfig.getSampler();
|
||||
Sampler sampler = observabilityConfig.getSampler();
|
||||
assertThat(sampler).isNotNull();
|
||||
assertThat(sampler.getType()).isEqualTo(ObservabilityConfig.SamplerType.NEVER);
|
||||
assertThat(sampler).isEqualTo(Samplers.probabilitySampler(0.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void probabilisticSampler() throws IOException {
|
||||
observabilityConfig.parse(GLOBAL_TRACING_PROBABILISTIC_SAMPLER);
|
||||
assertTrue(observabilityConfig.isEnableCloudTracing());
|
||||
ObservabilityConfig.Sampler sampler = observabilityConfig.getSampler();
|
||||
Sampler sampler = observabilityConfig.getSampler();
|
||||
assertThat(sampler).isNotNull();
|
||||
assertThat(sampler.getType()).isEqualTo(ObservabilityConfig.SamplerType.PROBABILISTIC);
|
||||
assertThat(sampler.getProbability()).isEqualTo(0.75);
|
||||
assertThat(sampler).isEqualTo(Samplers.probabilitySampler(0.75));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bothSamplerAndSamplingRate_error() throws IOException {
|
||||
try {
|
||||
observabilityConfig.parse(GLOBAL_TRACING_BOTH_SAMPLER_ERROR);
|
||||
fail("exception expected!");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
assertThat(iae.getMessage())
|
||||
.isEqualTo(
|
||||
"only one of 'global_trace_sampler' or 'global_trace_sampling_rate' can be"
|
||||
+ " specified");
|
||||
}
|
||||
public void defaultSampler() throws IOException {
|
||||
observabilityConfig.parse(GLOBAL_TRACING_DEFAULT_SAMPLER);
|
||||
assertTrue(observabilityConfig.isEnableCloudTracing());
|
||||
Sampler sampler = observabilityConfig.getSampler();
|
||||
assertThat(sampler).isNotNull();
|
||||
assertThat(sampler).isEqualTo(Samplers.probabilitySampler(0.00));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -242,7 +236,7 @@ public class ObservabilityConfigImplTest {
|
|||
fail("exception expected!");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
assertThat(iae.getMessage()).isEqualTo(
|
||||
"'global_trace_sampling_rate' needs to be between 0.0 and 1.0");
|
||||
"'global_trace_sampling_rate' needs to be between [0.0, 1.0]");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,4 +257,4 @@ public class ObservabilityConfigImplTest {
|
|||
assertThat(logFilters.get(1).headerBytes).isNull();
|
||||
assertThat(logFilters.get(1).messageBytes).isNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue