-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gcp-observability: Populate global interceptors from observability #9309
gcp-observability: Populate global interceptors from observability #9309
Conversation
observabilityConfig.getDestinationProjectId(), | ||
globalLoggingTags.getLocationTags(), | ||
globalLoggingTags.getCustomTags(), | ||
observabilityConfig.getFlushMessageCount()); | ||
LogHelper helper = new LogHelper(sink, TimeProvider.SYSTEM_TIME_PROVIDER); | ||
ConfigFilterHelper configFilterHelper = ConfigFilterHelper.factory(observabilityConfig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are passing observabilityConfig
to the non-static grpcInit
we can construct configFilterHelper
in there? Unless I am missing something?
May be the same thing for many other objects being constructed here and passed to the non-static grpcInit
such as sink
helper
etc?
The reason I am saying is because the non-static grpcInit
is unit tested/unit-testable so the more code it has the better it is. But we need to look into it carefully
|
||
/** | ||
* Initialize grpc-observability. | ||
* | ||
* @throws ProviderNotFoundException if no underlying channel/server provider is available. | ||
*/ | ||
public static synchronized GcpObservability grpcInit() throws IOException { | ||
public static synchronized GcpObservability grpcInit() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which other exception type made this necessary from IOException to Exception? Can we just add the additional types (if practical) instead of moving up to Exception?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stackdriver<Stats/Trace>Exporter
throws IllegalStateException
. So I will add IllegalStateException to the list of exceptions instead of generic Exception
.
try { | ||
StackdriverStatsExporter.createAndRegister(statsConfigurationBuilder.build()); | ||
} catch (IOException e) { | ||
throw new IOException("Failed to register Stackdriver stats exporter, " + e.getMessage()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unusual: catching an IOException
and throwing another IOException
with just the message modified. Wouldn't the original message be sufficient - so no need to do this? Same for line 181
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I realized about the IllegalStateException
: so we will get that for duplicate registration attempt. Ideally that should not happen because of the guard around grpcInit
but a user could have registered the exporter on their own. I guess the only way to resolve that is to document that in the UG? Unless there is a use-case for the user to have a separate registration for their own purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed catching and re-throwing exceptions.
gcp-observability/src/main/java/io/grpc/gcp/observability/GcpObservability.java
Show resolved
Hide resolved
Sink sink = new GcpLogSink(observabilityConfig.getDestinationProjectId(), | ||
globalLoggingTags.getLocationTags(), globalLoggingTags.getCustomTags(), | ||
observabilityConfig.getFlushMessageCount()); | ||
Sink sink = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is formatting only change with no real code change - will be good to avoid it to minimize the amount of code showing up as different
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
gcp-observability/src/main/java/io/grpc/gcp/observability/GcpObservability.java
Show resolved
Hide resolved
gcp-observability/src/main/java/io/grpc/gcp/observability/GcpObservability.java
Show resolved
Hide resolved
tracerFactories.add(InternalCensusTracingAccessor.getServerStreamTracerFactory()); | ||
} | ||
|
||
if (!clientInterceptors.isEmpty() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the latest change in the other PR, you should remove this check in the if
. Even if empty you should now set the interceptors or tracers in the GlobalInterceptors.
Hopefully you can unit test this scenario since it's important for correct functioning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added unit test to verify empty lists are returned when grpcInit
is called and none of the observability features are enabled.
RpcViews.registerAllGrpcViews(); | ||
StackdriverStatsConfiguration.Builder statsConfigurationBuilder = | ||
StackdriverStatsConfiguration.builder(); | ||
if (!Strings.isNullOrEmpty(projectId)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can understand null, do we want to include empty to have the same semantics? 2 Qs
- will the ObservabilityConfig ever return empty string for the project ID?
- if it does do we want special or different semantics for empty project ID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ObservabilityConfig
will not return empty, if the value does not exist in config it returns null
instead.
Updated the check.
gcp-observability/src/main/java/io/grpc/gcp/observability/ObservabilityConfigImpl.java
Show resolved
Hide resolved
"'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]"); | ||
if (samplingRate == 1.0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comparison of double numbers is tricky and because of precision (and conversion from String to double) issues this equality check may not go through. Has this been unit tested? https://www.baeldung.com/java-comparing-doubles#comparing_in_plain_Java
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated. PTAL
gcp-observability/src/main/java/io/grpc/gcp/observability/GcpObservability.java
Outdated
Show resolved
Hide resolved
88efda3
to
6e713a0
Compare
} | ||
double epsilon = 1e-6; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not make this a class final constant with some comment (e.g. why 1e-6
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
gcp-observability/src/main/java/io/grpc/gcp/observability/ObservabilityConfig.java
Show resolved
Hide resolved
"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 (enableCloudTracing && samplingRate == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be simpler/better if you just remove the check for enableCloudTracing
and do it as follows (with epsilon defined as a class constant)?:
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, 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 (Math.abs(1 - samplingRate) < EPSILON) {
this.sampler = Samplers.alwaysSample();
} else {
this.sampler = Samplers.probabilitySampler(samplingRate);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
import io.grpc.ClientCall; | ||
import io.grpc.ClientInterceptor; | ||
import io.grpc.InternalGlobalInterceptors; | ||
// import io.grpc.ManagedChannelProvider; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the commented line?
// 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 (Math.abs(1 - samplingRate) < epsilon) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Since samplingRate
is always going to be <= 1.0 (because of the check on line 112) the Math.abs
is strictly unnecessary. But I am okay to leave it there as a generalized double equality comparison logic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed Math.abs
import io.grpc.ServerCall; | ||
import io.grpc.ServerCallHandler; | ||
import io.grpc.ServerInterceptor; | ||
// import io.grpc.ServerProvider; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another commented import line? Any reason to leave them here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was an oversight. Removed both.
gcp-observability/src/test/java/io/grpc/gcp/observability/GcpObservabilityTest.java
Show resolved
Hide resolved
mock(InternalLoggingServerInterceptor.Factory.class); | ||
when(serverInterceptorFactory.create()).thenReturn(serverInterceptor); | ||
|
||
try (GcpObservability observability = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
observability
is unused - I am surprised you don't get a compile or link warning. If that was the case you can rename this var to unused
or use the SuppressWarning
annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few comments and it will be good to get them addressed but otherwise looks good.
…rpc#9309) * Populate global interceptors from observability and added stackdriver exporters
This PR populates Global Interceptors and Stream Tracers based on observability configuration.
Also, adds stackdriver exporter required for exporting metric and trace to Google cloud.
CC @sanjaypujare