Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   *      Copyright (C) 2012 DataStax Inc.
   *
   *   Licensed under the Apache License, Version 2.0 (the "License");
   *   you may not use this file except in compliance with the License.
   *   You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
  *   Unless required by applicable law or agreed to in writing, software
  *   distributed under the License is distributed on an "AS IS" BASIS,
  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *   See the License for the specific language governing permissions and
  *   limitations under the License.
  */
 package com.datastax.driver.core;
 
 import java.util.*;
 
 
The Cassandra trace for a query.

A trace is generated by Cassandra when query tracing is enabled for the query. The trace itself is stored in Cassandra in the sessions and events table in the system_traces keyspace and can be retrieve manually using the trace identifier (the one returned by getTraceId()).

This class provides facilities to fetch the traces from Cassandra. Please note that the writing of the trace is done asynchronously in Cassandra. So accessing the trace too soon after the query may result in the trace being incomplete.

 
 public class QueryTrace {
     private static final String SELECT_SESSIONS_FORMAT = "SELECT * FROM system_traces.sessions WHERE session_id = %s";
     private static final String SELECT_EVENTS_FORMAT = "SELECT * FROM system_traces.events WHERE session_id = %s";
 
     private static final int MAX_TRIES = 5;
     private static final long BASE_SLEEP_BETWEEN_TRIES_IN_MS = 3;
 
     private final UUID traceId;
 
     private volatile String requestType;
     // We use the duration to figure out if the trace is complete, because
     // that's the last event that is written (and it is written asynchronously
     // so it's possible that a fetch gets all the trace except the duration).
     private volatile int duration = .;
     private volatile InetAddress coordinator;
     private volatile Map<StringStringparameters;
     private volatile long startedAt;
     private volatile List<Eventevents;
 
     private final SessionManager session;
     private final Lock fetchLock = new ReentrantLock();
 
     QueryTrace(UUID traceIdSessionManager session) {
         this. = traceId;
         this. = session;
     }

    
Returns the identifier of this trace.

Note that contrary to the other methods in this class, this does not entail fetching query trace details from Cassandra.

Returns:
the identifier of this trace.
 
     public UUID getTraceId() {
         return ;
     }

    
Returns the type of request.

Returns:
the type of request or null if the request type is not yet available.
Throws:
com.datastax.driver.core.exceptions.TraceRetrievalException if the trace details cannot be retrieve from Cassandra successfully.
 
     public String getRequestType() {
         maybeFetchTrace();
         return ;
     }

    
Returns the server-side duration of the query in microseconds.

Returns:
the (server side) duration of the query in microseconds. This method will return Integer.MIN_VALUE if the duration is not yet available.
Throws:
com.datastax.driver.core.exceptions.TraceRetrievalException if the trace details cannot be retrieve from Cassandra successfully.
    public int getDurationMicros() {
        maybeFetchTrace();
        return ;
    }

    
Returns the coordinator host of the query.

Returns:
the coordinator host of the query or null if the coordinator is not yet available.
Throws:
com.datastax.driver.core.exceptions.TraceRetrievalException if the trace details cannot be retrieve from Cassandra successfully.
    public InetAddress getCoordinator() {
        maybeFetchTrace();
        return ;
    }

    
Returns the parameters attached to this trace.

Returns:
the parameters attached to this trace. or null if the coordinator is not yet available.
Throws:
com.datastax.driver.core.exceptions.TraceRetrievalException if the trace details cannot be retrieve from Cassandra successfully.
    public Map<StringStringgetParameters() {
        maybeFetchTrace();
        return ;
    }

    
Returns the server-side timestamp of the start of this query.

Returns:
the server side timestamp of the start of this query or 0 if the start timestamp is not available.
Throws:
com.datastax.driver.core.exceptions.TraceRetrievalException if the trace details cannot be retrieve from Cassandra successfully.
    public long getStartedAt() {
        maybeFetchTrace();
        return ;
    }

    
Returns the events contained in this trace.

Query tracing is asynchronous in Cassandra. Hence, it is possible for the list returned to be missing some events for some of the replica involved in the query if the query trace is requested just after the return of the query it is a trace of (the only guarantee being that the list will contain the events pertaining to the coordinator of the query).

Returns:
the events contained in this trace.
Throws:
com.datastax.driver.core.exceptions.TraceRetrievalException if the trace details cannot be retrieve from Cassandra successfully.
    public List<EventgetEvents() {
        maybeFetchTrace();
        return ;
    }
    @Override
    public String toString() {
        maybeFetchTrace();
        return String.format("%s [%s] - %dµs");
    }
    private void maybeFetchTrace() {
        if ( != .)
            return;
        .lock();
        try {
            doFetchTrace();
        } finally {
            .unlock();
        }
    }
    private void doFetchTrace() {
        int tries = 0;
        try {
            // We cannot guarantee the trace is complete. But we can't at least wait until we have all the information
            // the coordinator log in the trace. Since the duration is the last thing the coordinator log, that's
            // what we check to know if the trace is "complete" (again, it may not contain the log of replicas).
            while ( == . && tries <= ) {
                ++tries;
                Row sessRow = sessionsFuture.get().one();
                if (sessRow != null && !sessRow.isNull("duration")) {
                     = sessRow.getString("request");
                     = sessRow.getInet("coordinator");
                    if (!sessRow.isNull("parameters"))
                         = Collections.unmodifiableMap(sessRow.getMap("parameters"String.classString.class));
                     = sessRow.getDate("started_at").getTime();
                     = new ArrayList<Event>();
                    for (Row evRow : eventsFuture.get()) {
                        .add(new Event(evRow.getString("activity"),
                                    evRow.getUUID("event_id").timestamp(),
                                    evRow.getInet("source"),
                                    evRow.getInt("source_elapsed"),
                                    evRow.getString("thread")));
                    }
                     = Collections.unmodifiableList();
                    // Set the duration last as it's our test to know if the trace is complete
                     = sessRow.getInt("duration");
                } else {
                    // The trace is not ready. Give it a few milliseconds before trying again.
                    // Notes: granted, sleeping uninterruptibly is bad, but  having all method propagate
                    // InterruptedException bothers me.
                    Uninterruptibles.sleepUninterruptibly(tries * .);
                }
            }
        } catch (Exception e) {
            throw new TraceRetrievalException("Unexpected exception while fetching query trace"e);
        }
        if (tries > )
            throw new TraceRetrievalException(String.format("Unable to retrieve complete query trace after %d tries"));
    }

    
A trace event.

A query trace is composed of a list of trace events.

    public static class Event {
        private final String name;
        private final long timestamp;
        private final InetAddress source;
        private final int sourceElapsed;
        private final String threadName;
        private Event(String namelong timestampInetAddress sourceint sourceElapsedString threadName) {
            this. = name;
            // Convert the UUID timestamp to an epoch timestamp; I stole this seemingly random value from cqlsh, hopefully it's correct.
            this. = (timestamp - 0x01b21dd213814000L) / 10000;
            this. = source;
            this. = sourceElapsed;
            this. = threadName;
        }

        
The event description, that is which activity this event correspond to.

Returns:
the event description.
        public String getDescription() {
            return ;
        }

        
Returns the server side timestamp of the event.

Returns:
the server side timestamp of the event.
        public long getTimestamp() {
            return ;
        }

        
Returns the address of the host having generated this event.

Returns:
the address of the host having generated this event.
        public InetAddress getSource() {
            return ;
        }

        
Returns the number of microseconds elapsed on the source when this event occurred since when the source started handling the query.

Returns:
the elapsed time on the source host when that event happened in microseconds.
        public int getSourceElapsedMicros() {
            return ;
        }

        
Returns the name of the thread on which this event occurred.

Returns:
the name of the thread on which this event occurred.
        public String getThreadName() {
            return ;
        }
        @Override
        public String toString() {
            return String.format("%s on %s[%s] at %s"new Date());
        }
    }
New to GrepCode? Check out our FAQ X