Detailed information about the server-side internals for a given query.
- disabled by default, must enable per statement with Statement.setTracing() or StatementBuilder.setTracing().
- retrieve with ResultSet.getExecutionInfo().getTracingId() and getQueryTrace().
advanced.request.trace
in the configuration: fine-grained control over how the driver fetches the trace data.
To help troubleshooting performance, Cassandra offers the ability to trace a query, in other words capture detailed information about the the internal operations performed by all nodes in the cluster in order to build the response.
The driver provides a way to enable tracing on a particular statement, and an API to examine the results.
Set the tracing flag on the Statement
instance. There are various ways depending on how you build
it (see statements for more details):
// Setter-based:
Statement statement =
SimpleStatement.newInstance("SELECT * FROM users WHERE id = 1234").setTracing(true);
// Builder-based:
Statement statement =
SimpleStatement.builder("SELECT * FROM users WHERE id = 1234").setTracing().build();
Tracing is supposed to be run on a small percentage of requests only. Do not enable it on every request, you would risk overwhelming your cluster.
Once you've executed a statement with tracing enabled, tracing data is available through the ExecutionInfo:
ResultSet rs = session.execute(statement);
ExecutionInfo executionInfo = rs.getExecutionInfo();
Cassandra assigns a unique identifier to each query trace. It is returned with the query results, and therefore available immediately:
UUID tracingId = executionInfo.getTracingId();
This is the primary key in the system_traces.sessions
and system_traces.events
tables where
Cassandra stores tracing data (you don't need to query those tables manually, see the next section).
If you call getTracingId()
for a statement that didn't have tracing enabled, the resulting id will
be null
.
To get to the details of the trace, retrieve the QueryTrace instance:
QueryTrace trace = executionInfo.getQueryTrace();
// Or asynchronous equivalent:
CompletionStage<QueryTrace> traceFuture = executionInfo.getQueryTraceAsync();
This triggers background queries to fetch the information from the system_traces.sessions
and
system_traces.events
tables. Because Cassandra writes that information asynchronously, it might
not be immediately available, therefore the driver will retry a few times if necessary. You can
control this behavior through the configuration:
# These options can be changed at runtime, the new values will be used for requests issued after
# the change. They can be overridden in a profile.
datastax-java-driver.advanced.request.trace {
# How many times the driver will attempt to fetch the query if it is not ready yet.
attempts = 5
# The interval between each attempt.
interval = 3 milliseconds
# The consistency level to use for trace queries.
# Note that the default replication strategy for the system_traces keyspace is SimpleStrategy
# with RF=2, therefore LOCAL_ONE might not work if the local DC has no replicas for a given
# trace id.
consistency = ONE
}
Once you have the QueryTrace
object, access its properties for relevant information, for example:
System.out.printf(
"'%s' to %s took %dμs%n",
trace.getRequestType(), trace.getCoordinator(), trace.getDurationMicros());
for (TraceEvent event : trace.getEvents()) {
System.out.printf(
" %d - %s - %s%n",
event.getSourceElapsedMicros(), event.getSource(), event.getActivity());
}
If you call getQueryTrace()
for a statement that didn't have tracing enabled, an exception is
thrown.