-
Notifications
You must be signed in to change notification settings - Fork 714
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds Cassandra client and server integration
This contains tracing instrumentation for [Cassandra](https://github.com/apache/cassandra/blob/trunk/src/java/org/apache/cassandra/tracing/Tracing.java) and the [DataStax Java Driver](https://github.com/datastax/java-driver). `brave.cassandra.Tracing` extracts trace state from the custom payload of incoming requests. How long each request takes, each suboperation, and relevant tags like the session ID are reported to Zipkin. `brave.datastax.TracingSession` tracks the client-side of cassandra and adds trace context to the custom payload of outgoing requests. If server integration is in place, cassandra will contribute data to these RPC spans.
- Loading branch information
Adrian Cole
committed
May 13, 2017
1 parent
629a7da
commit e6e3cc5
Showing
20 changed files
with
1,978 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# brave-instrumentation-cassandra-driver | ||
This contains tracing instrumentation for the [DataStax Java Driver](https://github.com/datastax/java-driver). | ||
|
||
`brave.cassandra.driver.TracingSession` tracks the client-side of cassandra | ||
and adds trace context to the custom payload of outgoing requests. If | ||
[server integration](../cassandra) is in place, cassandra will contribute | ||
data to these RPC spans. | ||
|
||
To set this up, wrap your session like below | ||
```java | ||
session = TracingSession.create(tracing, realSession); | ||
``` | ||
|
||
|
||
## Tagging policy | ||
By default, the following are added to cassandra client spans: | ||
* Span.name as the simple type-name of the statement: ex "bound-statement" | ||
* Tags/binary annotations: | ||
* "cassandra.keyspace" | ||
* "cassandra.query" CQL of prepared statements | ||
* "error" when there is an error of any kind | ||
* Remote IP and port information | ||
|
||
To change the span and tag naming policy, you can do something like this: | ||
|
||
```java | ||
cassandraDriverTracing = cassandraDriverTracing.toBuilder() | ||
.parser(new CassandraParser() { | ||
@Override public String spanName(Statement statement) { | ||
return "query"; | ||
} | ||
|
||
@Override public void requestTags(Statement statement, Tagger tagger) { | ||
super.requestTags(statement, tagger); | ||
tagger.tag("cassandra.fetch_size", Integer.toString(statement.getFetchSize())); | ||
} | ||
}) | ||
.build(); | ||
|
||
tracesSession = TracingSession.create(cassandraDriverTracing.clientOf("remote-cluster"), session); | ||
``` | ||
|
||
## Sampling Policy | ||
The default sampling policy is to use the default (trace ID) sampler. | ||
|
||
For example, if there's no trace already in progress, the sampler | ||
indicated by `Tracing.Builder.sampler` decides whether or not to start a | ||
new trace for the cassandra client request. | ||
|
||
You can change the sampling policy by specifying it in the `CassandraDriverTracing` | ||
component. Here's an example which only starts new traces for bound statements. | ||
|
||
```java | ||
cassandraDriverTracing = cassandraDriverTracing.toBuilder() | ||
.sampler(new CassandraDriverSampler() { | ||
@Override public Boolean trySample(Statement statement) { | ||
return statement instanceof BoundStatement; | ||
} | ||
}) | ||
.build(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?xml version="1.0"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<parent> | ||
<groupId>io.zipkin.brave</groupId> | ||
<artifactId>brave-instrumentation-parent</artifactId> | ||
<version>4.3.1-SNAPSHOT</version> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<artifactId>brave-instrumentation-cassandra-driver</artifactId> | ||
<name>Brave Instrumentation: DataStax Java Driver for Apache Cassandra</name> | ||
|
||
<properties> | ||
<main.basedir>${project.basedir}/../..</main.basedir> | ||
</properties> | ||
|
||
<dependencies> | ||
<!-- for value types... don't worry. this dependency is compile only! --> | ||
<dependency> | ||
<groupId>com.google.auto.value</groupId> | ||
<artifactId>auto-value</artifactId> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.datastax.cassandra</groupId> | ||
<artifactId>cassandra-driver-core</artifactId> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>${project.groupId}</groupId> | ||
<artifactId>brave-instrumentation-cassandra-tests</artifactId> | ||
<version>${project.version}</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
</project> |
53 changes: 53 additions & 0 deletions
53
...entation/cassandra-driver/src/main/java/brave/cassandra/driver/CassandraDriverParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package brave.cassandra.driver; | ||
|
||
import brave.Tagger; | ||
import com.datastax.driver.core.BoundStatement; | ||
import com.datastax.driver.core.ResultSet; | ||
import com.datastax.driver.core.Statement; | ||
import com.google.common.base.CaseFormat; | ||
import zipkin.Constants; | ||
|
||
/** | ||
* Provides reasonable defaults for the data contained in cassandra client spans. Subclass to | ||
* customize, for example, to add tags based on response headers. | ||
*/ | ||
public class CassandraDriverParser { | ||
|
||
/** Returns the span name of the statement. Defaults to the lower-camel case type name. */ | ||
public String spanName(Statement statement) { | ||
return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, statement.getClass().getSimpleName()); | ||
} | ||
|
||
/** | ||
* Adds any tags based on the statement that will be sent to the server. | ||
* | ||
* <p>By default, this adds the {@link CassandraTraceKeys#CASSANDRA_KEYSPACE} and the {@link | ||
* CassandraTraceKeys#CASSANDRA_QUERY} for bound statements. | ||
*/ | ||
public void requestTags(Statement statement, Tagger tagger) { | ||
String keyspace = statement.getKeyspace(); | ||
if (keyspace != null) { | ||
tagger.tag(CassandraTraceKeys.CASSANDRA_KEYSPACE, statement.getKeyspace()); | ||
} | ||
if (statement instanceof BoundStatement) { | ||
tagger.tag(CassandraTraceKeys.CASSANDRA_QUERY, | ||
((BoundStatement) statement).preparedStatement().getQueryString()); | ||
} | ||
} | ||
|
||
/** Adds any tags based on the response received from the server. No default. */ | ||
public void responseTags(ResultSet resultSet, Tagger tagger) { | ||
} | ||
|
||
/** | ||
* Adds an {@link Constants#ERROR error tag} for a failed request. Defaults to the throwable's | ||
* message, or the simple name of the throwable's type. | ||
* | ||
* @see Constants#ERROR | ||
*/ | ||
// This says error tags for consistency eventhough we only add one | ||
public void errorTags(Throwable throwable, Tagger tagger) { | ||
String message = throwable.getMessage(); | ||
tagger.tag(Constants.ERROR, message != null ? message : throwable.getClass().getSimpleName()); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
...ntation/cassandra-driver/src/main/java/brave/cassandra/driver/CassandraDriverSampler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package brave.cassandra.driver; | ||
|
||
import brave.internal.Nullable; | ||
import com.datastax.driver.core.Statement; | ||
|
||
/** | ||
* Decides whether to start a new trace based on the cassandra statement. | ||
* | ||
* <p>Ex. Here's a sampler that only starts traces for bound statements | ||
* <pre>{@code | ||
* cassandraDriverTracingBuilder.serverSampler(new CassandraDriverSampler() { | ||
* @Override public <Req> Boolean trySample(Statement statement) { | ||
* return statement instanceof BoundStatement; | ||
* } | ||
* }); | ||
* }</pre> | ||
*/ | ||
// abstract class as it lets us make helpers in the future | ||
public abstract class CassandraDriverSampler { | ||
/** Ignores the request and uses the {@link brave.sampler.Sampler trace ID instead}. */ | ||
public static final CassandraDriverSampler TRACE_ID = new CassandraDriverSampler() { | ||
@Override public Boolean trySample(Statement statement) { | ||
return null; | ||
} | ||
|
||
@Override public String toString() { | ||
return "DeferDecision"; | ||
} | ||
}; | ||
/** Returns false to never start new traces for cassandra client requests. */ | ||
public static final CassandraDriverSampler NEVER_SAMPLE = new CassandraDriverSampler() { | ||
@Override public Boolean trySample(Statement statement) { | ||
return false; | ||
} | ||
|
||
@Override public String toString() { | ||
return "NeverSample"; | ||
} | ||
}; | ||
|
||
/** | ||
* Returns an overriding sampling decision for a new trace. Return null ignore the statement and | ||
* use the {@link brave.sampler.Sampler trace ID sampler}. | ||
*/ | ||
@Nullable public abstract Boolean trySample(Statement statement); | ||
} |
80 changes: 80 additions & 0 deletions
80
...ntation/cassandra-driver/src/main/java/brave/cassandra/driver/CassandraDriverTracing.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package brave.cassandra.driver; | ||
|
||
import brave.Tracing; | ||
import brave.internal.Nullable; | ||
import com.google.auto.value.AutoValue; | ||
import zipkin.Endpoint; | ||
|
||
@AutoValue | ||
public abstract class CassandraDriverTracing { | ||
public static CassandraDriverTracing create(Tracing tracing) { | ||
return newBuilder(tracing).build(); | ||
} | ||
|
||
public static Builder newBuilder(Tracing tracing) { | ||
return new AutoValue_CassandraDriverTracing.Builder() | ||
.tracing(tracing) | ||
.parser(new CassandraDriverParser()) | ||
.sampler(CassandraDriverSampler.TRACE_ID); | ||
} | ||
|
||
public abstract Tracing tracing(); | ||
|
||
public abstract CassandraDriverParser parser(); | ||
|
||
/** | ||
* Used by cassandra clients to indicate the name of the destination service. Defaults to the | ||
* cluster name. | ||
* | ||
* <p>As this is endpoint-specific, it is typical to create a scoped instance of {@linkplain | ||
* CassandraDriverTracing} to assign this value. | ||
* | ||
* For example: | ||
* <pre>{@code | ||
* production = TracingSession.create(httpTracing.remoteServiceName("production")); | ||
* }</pre> | ||
* | ||
* @see zipkin.Constants#SERVER_ADDR | ||
* @see brave.Span#remoteEndpoint(Endpoint) | ||
*/ | ||
@Nullable public abstract String remoteServiceName(); | ||
|
||
/** | ||
* Scopes this component for a client of the indicated server. | ||
* | ||
* @see #remoteServiceName() | ||
*/ | ||
public CassandraDriverTracing clientOf(String remoteServiceName) { | ||
return toBuilder().remoteServiceName(remoteServiceName).build(); | ||
} | ||
|
||
/** | ||
* Returns an overriding sampling decision for a new trace. Defaults to ignore the request and use | ||
* the {@link CassandraDriverSampler#TRACE_ID trace ID instead}. | ||
*/ | ||
public abstract CassandraDriverSampler sampler(); | ||
|
||
public abstract Builder toBuilder(); | ||
|
||
@AutoValue.Builder | ||
public static abstract class Builder { | ||
/** @see CassandraDriverTracing#tracing() */ | ||
public abstract Builder tracing(Tracing tracing); | ||
|
||
/** @see CassandraDriverTracing#parser() */ | ||
public abstract Builder parser(CassandraDriverParser parser); | ||
|
||
/** @see CassandraDriverTracing#sampler() */ | ||
public abstract Builder sampler(CassandraDriverSampler sampler); | ||
|
||
public abstract CassandraDriverTracing build(); | ||
|
||
abstract Builder remoteServiceName(@Nullable String remoteServiceName); | ||
|
||
Builder() { | ||
} | ||
} | ||
|
||
CassandraDriverTracing() { | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
...rumentation/cassandra-driver/src/main/java/brave/cassandra/driver/CassandraTraceKeys.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package brave.cassandra.driver; | ||
|
||
public final class CassandraTraceKeys { | ||
public static final String CASSANDRA_KEYSPACE = "cassandra.keyspace"; | ||
|
||
/** | ||
* The CQL query in a statement. Ex. "select * from customers where id = ?" | ||
* | ||
* <p>Used to understand the complexity of a request | ||
*/ | ||
public static final String CASSANDRA_QUERY = "cassandra.query"; | ||
|
||
private CassandraTraceKeys() { | ||
} | ||
} |
Oops, something went wrong.