## Query tracing

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. 

### Enabling tracing

Set the tracing flag on the `Statement` instance. There are various ways depending on how you build
it (see [statements](../statements/) for more details):

```java
// 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").withTracing().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.

### Retrieving tracing data

Once you've executed a statement with tracing enabled, tracing data is available through the
[ExecutionInfo]:

```java
ResultSet rs = session.execute(statement);
ExecutionInfo executionInfo = rs.getExecutionInfo();
```

#### Tracing id

Cassandra assigns a unique identifier to each query trace. It is returned with the query results,
and therefore available immediately: 

```java
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`. 

#### Tracing information

To get to the details of the trace, retrieve the [QueryTrace] instance:

```java
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:

```java
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.

[ExecutionInfo]: http://docs.datastax.com/en/drivers/java/4.0/com/datastax/oss/driver/api/core/cql/ExecutionInfo.html
[QueryTrace]:    http://docs.datastax.com/en/drivers/java/4.0/com/datastax/oss/driver/api/core/cql/QueryTrace.html
