Skip to content

Commit

Permalink
First attempt to add GRPC instrumentation (#1139)
Browse files Browse the repository at this point in the history
* Adding preliminary GRPC instrumentation to Sleuth

fixes #305
  • Loading branch information
tkvangorder authored and marcingrzejszczak committed Dec 4, 2018
1 parent a1832f6 commit 415a7a6
Show file tree
Hide file tree
Showing 16 changed files with 2,148 additions and 0 deletions.
38 changes: 38 additions & 0 deletions docs/src/main/asciidoc/spring-cloud-sleuth.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,44 @@ You can disable it by setting `spring.sleuth.feign.processor.enabled` to `false`
If you set it to `false`, Spring Cloud Sleuth does not instrument any of your custom Feign components.
However, all the default instrumentation is still there.

=== gRPC

Spring Cloud Sleuth provides instrumentation for https://grpc.io/[gRPC] through `TraceGrpcAutoConfiguration`. You can disable it entirely by setting `spring.sleuth.grpc.enabled` to `false`.

==== Dependencies
IMPORTANT: The gRPC integration relies on two external libraries to instrument clients and servers and both of those libraries must be on the class path to enable the instrumentation.

Maven:
```
<dependency>
<groupId>io.github.lognet</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-grpc</artifactId>
</dependency>
```
Gradle:
```
compile("io.github.lognet:grpc-spring-boot-starter")
compile("io.zipkin.brave:brave-instrumentation-grpc")
```

==== Server Instrumentation

Spring Cloud Sleuth leverages grpc-spring-boot-starter to register Brave's gRPC server interceptor with all services annotated with `@GRpcService`.

==== Client Instrumentation

gRPC clients leverage a `ManagedChannelBuilder` to construct a `ManagedChannel` used to communicate to the gRPC server. The native `ManagedChannelBuilder` provides static methods as entry points for construction of `ManagedChannel` instances, however, this mechanism is outside the influence of the Spring application context.

IMPORTANT: Spring Cloud Sleuth provides a `SpringAwareManagedChannelBuilder` that can be customized through the Spring application context and injected by gRPC clients. *This builder must be used when creating `ManagedChannel` instances.*


Sleuth creates a `TracingManagedChannelBuilderCustomizer` which inject Brave's client interceptor into the `SpringAwareManagedChannelBuilder`.


=== Asynchronous Communication

==== `@Async` Annotated methods
Expand Down
18 changes: 18 additions & 0 deletions spring-cloud-sleuth-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,17 @@
<artifactId>spring-jms</artifactId>
<optional>true</optional>
</dependency>
<!-- GRPC Optional Dependencies -->
<dependency>
<groupId>io.github.lognet</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-grpc</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
Expand Down Expand Up @@ -311,6 +322,13 @@
<artifactId>activemq-ra</artifactId>
<scope>test</scope>
</dependency>
<!-- This forces the guava version to 20 within the test scope, which is required by GRPC -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.sleuth.instrument.grpc;

import io.grpc.ManagedChannelBuilder;

/**
* Callback interface that can be implemented by beans wishing to further customize the
* {@link io.grpc.ManagedChannelBuilder} via the {@link SpringAwareManagedChannelBuilder}.
*
* @author tyler.vangorder
*/
public interface GrpcManagedChannelBuilderCustomizer {

void customize(ManagedChannelBuilder<?> managedChannelBuilder);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.sleuth.instrument.grpc;

import java.util.List;
import java.util.Optional;

import io.grpc.ManagedChannelBuilder;
import io.grpc.inprocess.InProcessChannelBuilder;

/**
* This is a Spring-aware managed channel builder that wraps the static entry points of
* gRPC's ManagedChannelBuilder to allow the configuration of the builder to be influenced
* by the Spring Context. All GrpcManagedChannelBuilderCustomizer instances included in
* the application context will have the opportunity to customize the builder.
*
* NOTE: There is nothing "Sleuth-specific" about this, however, there is currently not a
* good spring abstraction for client-side gRPC. Ideally, this could be moved up into
* grpc-spring-boot-starter or a new project could be created
* "spring-grpc"/"spring-cloud-grpc"?

This comment has been minimized.

Copy link
@ST-DDT

ST-DDT Feb 8, 2019

Contributor

There is the yidongnan/grpc-spring-boot-starter project, which also supports the client-side of grpc. We have also considered joining the spring label, but don't know how to do so.

In that library there is already an GrpcChannelConfigurer for the same use case.

We have support for sleuth build in natively, but we could move the few lines of code here as well.

See also: #1209

*
* @author tyler.vangorder
*/
public class SpringAwareManagedChannelBuilder {

private List<GrpcManagedChannelBuilderCustomizer> customizers;

public SpringAwareManagedChannelBuilder(
Optional<List<GrpcManagedChannelBuilderCustomizer>> customizers) {
this.customizers = customizers.orElse(null);
}

public ManagedChannelBuilder<?> forAddress(String name, int port) {

ManagedChannelBuilder<?> builder = ManagedChannelBuilder.forAddress(name, port);

if (this.customizers != null) {
this.customizers.stream()
.forEach(customizer -> customizer.customize(builder));
}
return builder;
}

public ManagedChannelBuilder<?> forTarget(String target) {
ManagedChannelBuilder<?> builder = ManagedChannelBuilder.forTarget(target);
if (this.customizers != null) {
this.customizers.stream()
.forEach(customizer -> customizer.customize(builder));
}
return builder;
}

public ManagedChannelBuilder<?> inProcessChannelBuilder(String serverName) {
ManagedChannelBuilder<?> builder = InProcessChannelBuilder.forName(serverName);
if (this.customizers != null) {
this.customizers.stream()
.forEach(customizer -> customizer.customize(builder));
}
return builder;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.sleuth.instrument.grpc;

import java.util.List;
import java.util.Optional;

import brave.Tracing;
import brave.grpc.GrpcTracing;
import io.grpc.ServerInterceptor;
import org.lognet.springboot.grpc.GRpcGlobalInterceptor;

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;

/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} enables span information propagation when using GRPC.
*
* This configuration is only enabled when both grpc-spring-boot-starter and
* brave-instrumentation-grpc are on the classpath.
*
* @author tyler.vangorder
*/
@ConditionalOnClass({ GrpcTracing.class, GRpcGlobalInterceptor.class })
@ConditionalOnProperty(value = "spring.sleuth.grpc.enabled", matchIfMissing = true)
@ConditionalOnBean(Tracing.class)
public class TraceGrpcAutoConfiguration {

@Bean
public GrpcTracing grpcTracing(Tracing tracing) {
return GrpcTracing.create(tracing);
}

// Register a global interceptor for both the server
@Bean
@GRpcGlobalInterceptor
ServerInterceptor grpcServerBraveInterceptor(GrpcTracing grpcTracing) {
return grpcTracing.newServerInterceptor();
}

// This is wrapper around gRPC's managed channel builder that is spring-aware
@Bean
@ConditionalOnMissingBean(SpringAwareManagedChannelBuilder.class)
public SpringAwareManagedChannelBuilder managedChannelBuilder(
Optional<List<GrpcManagedChannelBuilderCustomizer>> customizers) {
return new SpringAwareManagedChannelBuilder(customizers);
}

@Bean
GrpcManagedChannelBuilderCustomizer tracingManagedChannelBuilderCustomizer(
GrpcTracing grpcTracing) {
return new TracingManagedChannelBuilderCustomizer(grpcTracing);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.sleuth.instrument.grpc;

import brave.grpc.GrpcTracing;
import io.grpc.ManagedChannelBuilder;

/**
* @author tyler.vangorder
*/
public class TracingManagedChannelBuilderCustomizer
implements GrpcManagedChannelBuilderCustomizer {

GrpcTracing grpcTracing;

public TracingManagedChannelBuilderCustomizer(GrpcTracing grpcTracing) {
this.grpcTracing = grpcTracing;
}

/**
* Add brave's client interceptor to the builder.
*/
@Override
public void customize(ManagedChannelBuilder<?> managedChannelBuilder) {
managedChannelBuilder.intercept(this.grpcTracing.newClientInterceptor());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,11 @@
"type": "java.lang.Boolean",
"description": "Enable span information propagation when using Zuul.",
"defaultValue": true
},
{
"name": "spring.sleuth.grpc.enabled",
"type": "java.lang.Boolean",
"description": "Enable span information propagation when using GRPC.",
"defaultValue": true
}
]}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ org.springframework.cloud.sleuth.instrument.rxjava.RxJavaAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.reactor.TraceReactorAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.web.TraceWebFluxAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.zuul.TraceZuulAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.grpc.TraceGrpcAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.messaging.TraceMessagingAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.messaging.TraceSpringIntegrationAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.messaging.websocket.TraceWebSocketAutoConfiguration,\
Expand Down
Loading

0 comments on commit 415a7a6

Please sign in to comment.