Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.

Commit e83c506

Browse files
authored
Add OpenTelemetry tracing (#151)
Signed-off-by: Antoine Toulme <antoine@lunar-ocean.com>
1 parent 609e59a commit e83c506

File tree

6 files changed

+153
-4
lines changed

6 files changed

+153
-4
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,5 +413,14 @@ by starting command have the -d parameter.
413413

414414
Upload full logs to the JIRA not just where the issue occurred if possible
415415

416+
### Tracing
417+
418+
The SDK is set up to trace all gRPC communications:
419+
* All outgoing messages bear trace metadata, allowing correlation with peers.
420+
* Each request/response is computed as a span.
421+
* If you use OpenTelemetry in your program, the gRPC span will correlate using the thread local context to the parent context.
422+
423+
The SDK accepts all environment variables as described in the [OpenTelemetry specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md).
424+
416425

417426
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.

dependencies-suppressions.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
3+
<suppress>
4+
<notes><![CDATA[
5+
file name: opentelemetry-grpc-1.6-1.5.1-alpha.jar
6+
]]></notes>
7+
<packageUrl regex="true">^pkg:maven/io\.opentelemetry\.instrumentation/opentelemetry\-grpc\-1\.6@.*$</packageUrl>
8+
<cve>CVE-2020-7768</cve>
9+
</suppress>
10+
</suppressions>

pom.xml

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@
6868
</plugins>
6969
</reporting>
7070

71+
<dependencyManagement>
72+
<dependencies>
73+
<dependency>
74+
<groupId>io.opentelemetry</groupId>
75+
<artifactId>opentelemetry-bom</artifactId>
76+
<version>1.5.0</version>
77+
<type>pom</type>
78+
<scope>import</scope>
79+
</dependency>
80+
</dependencies>
81+
</dependencyManagement>
82+
7183
<dependencies>
7284
<dependency>
7385
<groupId>org.mockito</groupId>
@@ -220,6 +232,36 @@
220232
<version>1.3.2</version>
221233
</dependency>
222234

235+
<dependency>
236+
<groupId>io.opentelemetry</groupId>
237+
<artifactId>opentelemetry-api</artifactId>
238+
</dependency>
239+
<dependency>
240+
<groupId>io.opentelemetry</groupId>
241+
<artifactId>opentelemetry-sdk</artifactId>
242+
</dependency>
243+
<dependency>
244+
<groupId>io.opentelemetry</groupId>
245+
<artifactId>opentelemetry-sdk-trace</artifactId>
246+
</dependency>
247+
<dependency>
248+
<groupId>io.opentelemetry</groupId>
249+
<artifactId>opentelemetry-exporter-otlp</artifactId>
250+
</dependency>
251+
<dependency>
252+
<groupId>io.opentelemetry</groupId>
253+
<artifactId>opentelemetry-extension-trace-propagators</artifactId>
254+
</dependency>
255+
<dependency>
256+
<groupId>io.opentelemetry.instrumentation</groupId>
257+
<artifactId>opentelemetry-grpc-1.6</artifactId>
258+
<version>1.5.1-alpha</version>
259+
</dependency>
260+
<dependency>
261+
<groupId>io.opentelemetry</groupId>
262+
<artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
263+
<version>1.5.0-alpha</version>
264+
</dependency>
223265
</dependencies>
224266

225267

@@ -576,8 +618,27 @@
576618
</archive>
577619
</configuration>
578620
</plugin>
579-
580-
621+
<plugin>
622+
<groupId>org.owasp</groupId>
623+
<artifactId>dependency-check-maven</artifactId>
624+
<version>6.2.2</version>
625+
<configuration>
626+
<skipProvidedScope>true</skipProvidedScope>
627+
<skipTestScope>true</skipTestScope>
628+
<skipSystemScope>true</skipSystemScope>
629+
<failBuildOnCVSS>7</failBuildOnCVSS>
630+
<suppressionFiles>
631+
<suppressionFile>dependencies-suppressions.xml</suppressionFile>
632+
</suppressionFiles>
633+
</configuration>
634+
<executions>
635+
<execution>
636+
<goals>
637+
<goal>check</goal>
638+
</goals>
639+
</execution>
640+
</executions>
641+
</plugin>
581642
</plugins>
582643
</build>
583644
<distributionManagement>

src/main/java/org/hyperledger/fabric/sdk/Endpoint.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,16 @@
3636
import javax.net.ssl.SSLException;
3737

3838
import com.google.common.collect.ImmutableMap;
39+
import io.grpc.ClientInterceptor;
3940
import io.grpc.ManagedChannelBuilder;
4041
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
4142
import io.grpc.netty.shaded.io.grpc.netty.NegotiationType;
4243
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
4344
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
4445
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder;
4546
import io.grpc.netty.shaded.io.netty.handler.ssl.SslProvider;
47+
import io.opentelemetry.api.OpenTelemetry;
48+
import io.opentelemetry.instrumentation.grpc.v1_6.GrpcTracing;
4649
import org.apache.commons.codec.binary.Hex;
4750
import org.apache.commons.logging.Log;
4851
import org.apache.commons.logging.LogFactory;
@@ -67,6 +70,8 @@ class Endpoint {
6770

6871
private static final String SSLPROVIDER = Config.getConfig().getDefaultSSLProvider();
6972
private static final String SSLNEGOTIATION = Config.getConfig().getDefaultSSLNegotiationType();
73+
private static final OpenTelemetry openTelemetry = Config.getConfig().getOpenTelemetry();
74+
private static final GrpcTracing grpcTracing = GrpcTracing.create(openTelemetry);
7075

7176
private final String addr;
7277
private final int port;
@@ -236,13 +241,14 @@ class Endpoint {
236241
}
237242

238243
try {
244+
ClientInterceptor clientInterceptor = grpcTracing.newClientInterceptor();
239245
if (protocol.equalsIgnoreCase("grpc")) {
240-
this.channelBuilder = NettyChannelBuilder.forAddress(addr, port).negotiationType(NegotiationType.PLAINTEXT);
246+
this.channelBuilder = NettyChannelBuilder.forAddress(addr, port).negotiationType(NegotiationType.PLAINTEXT).intercept(clientInterceptor);
241247
addNettyBuilderProps(channelBuilder, properties);
242248
} else if (protocol.equalsIgnoreCase("grpcs")) {
243249
if (pemBytes == null) {
244250
// use root certificate
245-
this.channelBuilder = NettyChannelBuilder.forAddress(addr, port);
251+
this.channelBuilder = NettyChannelBuilder.forAddress(addr, port).intercept(clientInterceptor);
246252
addNettyBuilderProps(channelBuilder, properties);
247253
} else {
248254
try {

src/main/java/org/hyperledger/fabric/sdk/helper/Config.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@
2323
import java.util.concurrent.TimeUnit;
2424
import java.util.concurrent.atomic.AtomicLong;
2525

26+
import io.opentelemetry.api.OpenTelemetry;
27+
import io.opentelemetry.sdk.OpenTelemetrySdk;
28+
import io.opentelemetry.sdk.OpenTelemetrySdkBuilder;
29+
import io.opentelemetry.sdk.autoconfigure.OpenTelemetrySdkAutoConfiguration;
30+
import io.opentelemetry.sdk.trace.SdkTracerProvider;
2631
import org.apache.commons.logging.Log;
2732
import org.apache.commons.logging.LogFactory;
2833
import org.apache.log4j.Level;
@@ -111,6 +116,7 @@ public class Config {
111116
private static Config config;
112117
private static final Properties sdkProperties = new Properties();
113118
private static final AtomicLong count = new AtomicLong(0);
119+
private final OpenTelemetrySdk openTelemetry;
114120

115121
//Provides a unique id for logging to identify a specific instance.
116122
public String getNextID() {
@@ -241,6 +247,7 @@ private Config() {
241247

242248
}
243249

250+
openTelemetry = OpenTelemetrySdkAutoConfiguration.initialize(false);
244251
}
245252

246253
}
@@ -348,6 +355,10 @@ public String getDefaultSSLNegotiationType() {
348355

349356
}
350357

358+
public OpenTelemetry getOpenTelemetry() {
359+
return openTelemetry;
360+
}
361+
351362
private Map<Integer, String> curveMapping = null;
352363

353364
/**

src/test/java/org/hyperledger/fabric/sdkintegration/End2endLifecycleIT.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
import java.io.IOException;
1111
import java.nio.file.Path;
1212
import java.nio.file.Paths;
13+
import java.util.ArrayList;
1314
import java.util.Arrays;
1415
import java.util.Collection;
1516
import java.util.Collections;
1617
import java.util.EnumSet;
1718
import java.util.HashMap;
1819
import java.util.HashSet;
1920
import java.util.LinkedList;
21+
import java.util.List;
2022
import java.util.Map;
2123
import java.util.Optional;
2224
import java.util.Properties;
@@ -28,7 +30,16 @@
2830
import java.util.concurrent.TimeoutException;
2931
import java.util.function.Predicate;
3032

33+
import com.google.common.io.Closer;
3134
import com.google.protobuf.InvalidProtocolBufferException;
35+
import io.grpc.Server;
36+
import io.grpc.Status;
37+
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
38+
import io.grpc.stub.StreamObserver;
39+
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
40+
import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse;
41+
import io.opentelemetry.proto.collector.trace.v1.TraceServiceGrpc;
42+
import io.opentelemetry.proto.trace.v1.ResourceSpans;
3243
import org.hyperledger.fabric.sdk.BlockEvent.TransactionEvent;
3344
import org.hyperledger.fabric.sdk.ChaincodeCollectionConfiguration;
3445
import org.hyperledger.fabric.sdk.ChaincodeResponse;
@@ -116,6 +127,38 @@ public class End2endLifecycleIT {
116127
TX_EXPECTED.put("writeset1", "Missing writeset for channel bar block 1");
117128
}
118129

130+
private static final class FakeCollector extends TraceServiceGrpc.TraceServiceImplBase {
131+
private final List<ResourceSpans> receivedSpans = new ArrayList<>();
132+
private Status returnedStatus = Status.OK;
133+
134+
@Override
135+
public void export(
136+
final ExportTraceServiceRequest request,
137+
final StreamObserver<ExportTraceServiceResponse> responseObserver) {
138+
receivedSpans.addAll(request.getResourceSpansList());
139+
responseObserver.onNext(ExportTraceServiceResponse.newBuilder().build());
140+
if (!returnedStatus.isOk()) {
141+
if (returnedStatus.getCode() == Status.Code.DEADLINE_EXCEEDED) {
142+
// Do not call onCompleted to simulate a deadline exceeded.
143+
return;
144+
}
145+
responseObserver.onError(returnedStatus.asRuntimeException());
146+
return;
147+
}
148+
responseObserver.onCompleted();
149+
}
150+
151+
List<ResourceSpans> getReceivedSpans() {
152+
return receivedSpans;
153+
}
154+
155+
void setReturnedStatus(final Status returnedStatus) {
156+
this.returnedStatus = returnedStatus;
157+
}
158+
}
159+
160+
private final Closer closer = Closer.create();
161+
private final FakeCollector fakeTracesCollector = new FakeCollector();
119162
private final TestConfigHelper configHelper = new TestConfigHelper();
120163
String testName = "End2endLifecycleIT";
121164

@@ -144,8 +187,15 @@ static void out(String format, Object... args) {
144187
@Before
145188
public void checkConfig() throws Exception {
146189
out("\n\n\nRUNNING: %s.\n", testName);
190+
Server server =
191+
NettyServerBuilder.forPort(4317)
192+
.addService(fakeTracesCollector)
193+
.build()
194+
.start();
195+
closer.register(server::shutdownNow);
147196
// configHelper.clearConfig();
148197
// assertEquals(256, Config.getConfig().getSecurityLevel());
198+
System.setProperty("OTEL_TRACES_SAMPLER", "always_on");
149199
resetConfig();
150200
configHelper.customizeConfig();
151201

@@ -336,6 +386,8 @@ public void runFabricTest() throws Exception {
336386
assertNull(org1Client.getChannel(CHANNEL_NAME));
337387
out("\n");
338388

389+
assertFalse(fakeTracesCollector.receivedSpans.isEmpty());
390+
339391
out("That's all folks!");
340392
}
341393

0 commit comments

Comments
 (0)