Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c388401

Browse files
committedSep 5, 2022
Tracing: added OpenTelemetry tracing example
Added OpenTelemetry and Zipkin connection configuration classes, along with docker-compose file, example run script and related changes in README.
1 parent ba3075a commit c388401

File tree

6 files changed

+363
-1
lines changed

6 files changed

+363
-1
lines changed
 

‎driver-examples/README.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ Apache Cassandra.
55

66
## Usage
77

8-
Unless otherwise stated, all examples assume that you have a single-node Cassandra 3.0 cluster
8+
Unless otherwise stated, all examples assume that you have a single-node Cassandra 3.0 cluster
99
listening on localhost:9042.
1010

11+
Before running examples, make sure you installed repo artifacts (in root driver directory):
12+
```
13+
mvn install -q -Dmaven.test.skip=true
14+
```
15+
16+
To conveniently run the example showing OpenTelemetry integration (ZipkinConfiguration),
17+
you can use the provided ```docker-compose.yaml``` file (which runs both Scylla cluster and Zipkin instance):
18+
```
19+
docker-compose up
20+
./runOpenTelemetryExample.sh
21+
```

‎driver-examples/docker-compose.yaml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
version: '3.4'
2+
3+
services:
4+
zipkin:
5+
image: openzipkin/zipkin
6+
ports:
7+
- "9411:9411"
8+
scylla_node:
9+
image: scylladb/scylla
10+
ports:
11+
- "9042:9042"
12+
command: "--smp 1 --skip-wait-for-gossip-to-settle 0"

‎driver-examples/pom.xml

+34
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@
4848
<optional>true</optional>
4949
</dependency>
5050

51+
<dependency>
52+
<groupId>com.scylladb</groupId>
53+
<artifactId>scylla-driver-opentelemetry</artifactId>
54+
</dependency>
55+
5156
<!--Jackson-->
5257

5358
<dependency>
@@ -134,6 +139,26 @@
134139
<artifactId>logback-classic</artifactId>
135140
</dependency>
136141

142+
<!-- OpenTelemetry -->
143+
144+
<dependency>
145+
<groupId>io.opentelemetry</groupId>
146+
<artifactId>opentelemetry-sdk</artifactId>
147+
<version>1.9.1</version>
148+
</dependency>
149+
150+
<dependency>
151+
<groupId>io.opentelemetry</groupId>
152+
<artifactId>opentelemetry-semconv</artifactId>
153+
<version>1.9.0-alpha</version>
154+
</dependency>
155+
156+
<dependency>
157+
<groupId>io.opentelemetry</groupId>
158+
<artifactId>opentelemetry-exporter-zipkin</artifactId>
159+
<version>1.9.1</version>
160+
</dependency>
161+
137162
</dependencies>
138163

139164
<build>
@@ -184,6 +209,15 @@
184209
</configuration>
185210
</plugin>
186211

212+
<plugin>
213+
<groupId>org.apache.maven.plugins</groupId>
214+
<artifactId>maven-compiler-plugin</artifactId>
215+
<configuration>
216+
<source>8</source>
217+
<target>8</target>
218+
</configuration>
219+
</plugin>
220+
187221
</plugins>
188222

189223
</build>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mvn -q exec:java -Dexec.mainClass="com.datastax.driver.examples.opentelemetry.ZipkinUsage"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (C) 2021 ScyllaDB
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.datastax.driver.examples.opentelemetry;
18+
19+
import io.opentelemetry.api.OpenTelemetry;
20+
import io.opentelemetry.api.common.Attributes;
21+
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
22+
import io.opentelemetry.sdk.OpenTelemetrySdk;
23+
import io.opentelemetry.sdk.resources.Resource;
24+
import io.opentelemetry.sdk.trace.SdkTracerProvider;
25+
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
26+
import io.opentelemetry.sdk.trace.export.SpanExporter;
27+
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
28+
29+
/** Example showing how to configure OpenTelemetry for tracing with Scylla Java Driver. */
30+
class OpenTelemetryConfiguration {
31+
private static final String SERVICE_NAME = "Scylla Java driver";
32+
33+
public static OpenTelemetry initialize(SpanExporter spanExporter) {
34+
Resource serviceNameResource =
35+
Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, SERVICE_NAME));
36+
37+
// Set to process the spans by the spanExporter.
38+
final SdkTracerProvider tracerProvider =
39+
SdkTracerProvider.builder()
40+
.addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
41+
.setResource(Resource.getDefault().merge(serviceNameResource))
42+
.build();
43+
OpenTelemetrySdk openTelemetry =
44+
OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).buildAndRegisterGlobal();
45+
46+
// Add a shutdown hook to shut down the SDK.
47+
Runtime.getRuntime()
48+
.addShutdownHook(
49+
new Thread(
50+
new Runnable() {
51+
@Override
52+
public void run() {
53+
tracerProvider.close();
54+
}
55+
}));
56+
57+
// Return the configured instance so it can be used for instrumentation.
58+
return openTelemetry;
59+
}
60+
61+
public static OpenTelemetry initializeForZipkin(String ip, int port) {
62+
String endpointPath = "/api/v2/spans";
63+
String httpUrl = String.format("http://%s:%s", ip, port);
64+
65+
SpanExporter exporter =
66+
ZipkinSpanExporter.builder().setEndpoint(httpUrl + endpointPath).build();
67+
68+
return initialize(exporter);
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
/*
2+
* Copyright DataStax, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/*
18+
* Copyright (C) 2021 ScyllaDB
19+
*
20+
* Modified by ScyllaDB
21+
*/
22+
package com.datastax.driver.examples.opentelemetry;
23+
24+
import com.datastax.driver.core.BoundStatement;
25+
import com.datastax.driver.core.Cluster;
26+
import com.datastax.driver.core.PreparedStatement;
27+
import com.datastax.driver.core.ResultSetFuture;
28+
import com.datastax.driver.core.Session;
29+
import com.datastax.driver.core.tracing.TracingInfoFactory;
30+
import com.datastax.driver.opentelemetry.OpenTelemetryTracingInfoFactory;
31+
import io.opentelemetry.api.OpenTelemetry;
32+
import io.opentelemetry.api.trace.Span;
33+
import io.opentelemetry.api.trace.Tracer;
34+
import io.opentelemetry.context.Scope;
35+
36+
/**
37+
* Creates a keyspace and tables, and loads some data into them. Sends OpenTelemetry tracing data to
38+
* Zipkin tracing backend
39+
*
40+
* <p>Preconditions: - a Scylla cluster is running and accessible through the contacts points
41+
* identified by CONTACT_POINTS and PORT and Zipkin backend is running and accessible through the
42+
* contacts points identified by ZIPKIN_CONTACT_POINT and ZIPKIN_PORT.
43+
*
44+
* <p>Side effects: - creates a new keyspace "simplex" in the cluster. If a keyspace with this name
45+
* already exists, it will be reused; - creates two tables "simplex.songs" and "simplex.playlists".
46+
* If they exist already, they will be reused; - inserts a row in each table.
47+
*/
48+
public class ZipkinUsage {
49+
private static final String CONTACT_POINT = "127.0.0.1";
50+
private static final int PORT = 9042;
51+
52+
private static final String ZIPKIN_CONTACT_POINT = "127.0.0.1";
53+
private static final int ZIPKIN_PORT = 9411;
54+
55+
private Cluster cluster;
56+
private Session session;
57+
58+
private Tracer tracer;
59+
60+
public static void main(String[] args) {
61+
// Workaround for setting ContextStorage to ThreadLocalContextStorage.
62+
System.setProperty("io.opentelemetry.context.contextStorageProvider", "default");
63+
64+
ZipkinUsage client = new ZipkinUsage();
65+
66+
try {
67+
client.connect();
68+
client.createSchema();
69+
client.loadData();
70+
client.querySchema();
71+
System.out.println(
72+
"All requests have been completed. Now you can visit Zipkin at "
73+
+ "http://"
74+
+ ZIPKIN_CONTACT_POINT
75+
+ ":"
76+
+ ZIPKIN_PORT
77+
+ " and examine the produced trace.");
78+
} finally {
79+
client.close();
80+
}
81+
}
82+
83+
/** Initiates a connection to the cluster. */
84+
public void connect() {
85+
cluster = Cluster.builder().addContactPoints(CONTACT_POINT).withPort(PORT).build();
86+
87+
System.out.printf("Connected to cluster: %s%n", cluster.getMetadata().getClusterName());
88+
89+
OpenTelemetry openTelemetry =
90+
OpenTelemetryConfiguration.initializeForZipkin(ZIPKIN_CONTACT_POINT, ZIPKIN_PORT);
91+
tracer = openTelemetry.getTracerProvider().get("this");
92+
TracingInfoFactory tracingInfoFactory = new OpenTelemetryTracingInfoFactory(tracer);
93+
cluster.setTracingInfoFactory(tracingInfoFactory);
94+
95+
session = cluster.connect();
96+
}
97+
98+
/** Creates the schema (keyspace) and tables for this example. */
99+
public void createSchema() {
100+
session.execute("DROP KEYSPACE IF EXISTS simplex;");
101+
Span parentSpan = tracer.spanBuilder("create schema").startSpan();
102+
try (Scope parentScope = parentSpan.makeCurrent()) {
103+
{
104+
Span span = tracer.spanBuilder("create simplex").startSpan();
105+
try (Scope scope = span.makeCurrent()) {
106+
session.execute(
107+
"CREATE KEYSPACE IF NOT EXISTS simplex WITH replication "
108+
+ "= {'class':'SimpleStrategy', 'replication_factor':1};");
109+
110+
} finally {
111+
span.end();
112+
}
113+
}
114+
{
115+
Span span = tracer.spanBuilder("create simplex.songs").startSpan();
116+
try (Scope scope = span.makeCurrent()) {
117+
ResultSetFuture f =
118+
session.executeAsync(
119+
"CREATE TABLE IF NOT EXISTS simplex.songs ("
120+
+ "id uuid,"
121+
+ "title text,"
122+
+ "album text,"
123+
+ "artist text,"
124+
+ "tags set<text>,"
125+
+ "data blob,"
126+
+ "PRIMARY KEY ((title, artist), album)"
127+
+ ");");
128+
f.getUninterruptibly();
129+
} finally {
130+
span.end();
131+
}
132+
}
133+
{
134+
Span span = tracer.spanBuilder("create simplex.playlists").startSpan();
135+
try (Scope scope = span.makeCurrent()) {
136+
session.execute(
137+
"CREATE TABLE IF NOT EXISTS simplex.playlists ("
138+
+ "id uuid,"
139+
+ "title text,"
140+
+ "album text, "
141+
+ "artist text,"
142+
+ "song_id uuid,"
143+
+ "PRIMARY KEY (id, title, album, artist)"
144+
+ ");");
145+
146+
} finally {
147+
span.end();
148+
}
149+
}
150+
} finally {
151+
parentSpan.end();
152+
}
153+
}
154+
155+
/** Inserts data into the tables. */
156+
public void loadData() {
157+
Span parentSpan = tracer.spanBuilder("load data").startSpan();
158+
try (Scope parentScope = parentSpan.makeCurrent()) {
159+
160+
Span prepareSpan = tracer.spanBuilder("prepare").startSpan();
161+
PreparedStatement ps;
162+
try (Scope prepareScope = prepareSpan.makeCurrent()) {
163+
ps =
164+
session.prepare(
165+
"INSERT INTO simplex.songs (id, title, album, artist, tags) "
166+
+ "VALUES ("
167+
+ "756716f7-2e54-4715-9f00-91dcbea6cf50,"
168+
+ "?,"
169+
+ "?,"
170+
+ "?,"
171+
+ "{'jazz', '2013'})"
172+
+ ";");
173+
} finally {
174+
prepareSpan.end();
175+
}
176+
177+
Span bindSpan = tracer.spanBuilder("bind").startSpan();
178+
BoundStatement bound;
179+
try (Scope bindScope = bindSpan.makeCurrent()) {
180+
bound = ps.bind("La Petite Tonkinoise", "Bye Bye Blackbird", "Joséphine Baker");
181+
} finally {
182+
bindSpan.end();
183+
}
184+
185+
Span span = tracer.spanBuilder("insert simplex.songs").startSpan();
186+
try (Scope scope = span.makeCurrent()) {
187+
session.execute(bound);
188+
} finally {
189+
span.end();
190+
}
191+
192+
} finally {
193+
parentSpan.end();
194+
}
195+
}
196+
197+
public void querySchema() {
198+
Span parentSpan = tracer.spanBuilder("query schema").startSpan();
199+
try (Scope parentScope = parentSpan.makeCurrent()) {
200+
201+
Span prepareSpan = tracer.spanBuilder("prepare").startSpan();
202+
PreparedStatement ps;
203+
try (Scope prepareScope = prepareSpan.makeCurrent()) {
204+
ps = session.prepare("SELECT * FROM simplex.songs WHERE artist = ? AND title = ?;");
205+
} finally {
206+
prepareSpan.end();
207+
}
208+
209+
Span bindSpan = tracer.spanBuilder("bind").startSpan();
210+
BoundStatement bound;
211+
try (Scope bindScope = bindSpan.makeCurrent()) {
212+
bound = ps.bind("Joséphine Baker", "La Petite Tonkinoise");
213+
} finally {
214+
bindSpan.end();
215+
}
216+
217+
Span span = tracer.spanBuilder("query simplex.songs").startSpan();
218+
try (Scope scope = span.makeCurrent()) {
219+
session.execute(bound);
220+
} finally {
221+
span.end();
222+
}
223+
224+
} finally {
225+
parentSpan.end();
226+
}
227+
}
228+
229+
/** Closes the session and the cluster. */
230+
public void close() {
231+
if (session != null) session.close();
232+
if (cluster != null) cluster.close();
233+
}
234+
}

0 commit comments

Comments
 (0)
Please sign in to comment.