Skip to content

Commit

Permalink
Add TServer logging of query IDs and Tests
Browse files Browse the repository at this point in the history
Added the query option tserver.logging.active to enable
logging of query IDs to the TServer logs. Created the
class QueryLogIterator to handle this. Logs the
start and end of each method called.

Fixes NationalSecurityAgency#2305
  • Loading branch information
SethSmucker committed Jun 20, 2024
1 parent 0f34220 commit e5e1883
Show file tree
Hide file tree
Showing 11 changed files with 532 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,5 @@ public class QueryParameters {
* Used to specify model or DB fields that must be treated as strict (cannot be skipped if normalization fails)
*/
public static final String STRICT_FIELDS = "strict.fields";

}
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,11 @@ public class ShardQueryConfiguration extends GenericQueryConfiguration implement
*/
private boolean sortQueryByCounts = false;

/**
* Controls whether query IDs are logged on the tserver level via {@link datawave.query.iterator.QueryLogIterator}.
*/
private boolean tserverLoggingActive = true;

/**
* Default constructor
*/
Expand Down Expand Up @@ -720,6 +725,7 @@ public ShardQueryConfiguration(ShardQueryConfiguration other) {
this.setUseTermCounts(other.getUseTermCounts());
this.setSortQueryBeforeGlobalIndex(other.isSortQueryBeforeGlobalIndex());
this.setSortQueryByCounts(other.isSortQueryByCounts());
this.setTserverLoggingActive(other.isTserverLoggingActive());
}

/**
Expand Down Expand Up @@ -2740,14 +2746,25 @@ public void setSortQueryByCounts(boolean sortQueryByCounts) {
this.sortQueryByCounts = sortQueryByCounts;
}

public boolean isTserverLoggingActive() {
return this.tserverLoggingActive;
}

public void setTserverLoggingActive(boolean tserverLoggingActive) {
this.tserverLoggingActive = tserverLoggingActive;
}

@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (o == null || getClass() != o.getClass())
}
if (o == null || getClass() != o.getClass()) {
return false;
if (!super.equals(o))
}
if (!super.equals(o)) {
return false;
}
// @formatter:off
ShardQueryConfiguration that = (ShardQueryConfiguration) o;
return isTldQuery() == that.isTldQuery() &&
Expand Down Expand Up @@ -2947,7 +2964,8 @@ public boolean equals(Object o) {
getUseFieldCounts() == that.getUseFieldCounts() &&
getUseTermCounts() == that.getUseTermCounts() &&
isSortQueryBeforeGlobalIndex() == that.isSortQueryBeforeGlobalIndex() &&
isSortQueryByCounts() == that.isSortQueryByCounts();
isSortQueryByCounts() == that.isSortQueryByCounts() &&
isTserverLoggingActive() == that.isTserverLoggingActive();
// @formatter:on
}

Expand Down Expand Up @@ -3152,7 +3170,8 @@ public int hashCode() {
getUseFieldCounts(),
getUseTermCounts(),
isSortQueryBeforeGlobalIndex(),
isSortQueryByCounts());
isSortQueryByCounts(),
isTserverLoggingActive());
// @formatter:on
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package datawave.query.iterator;

import static datawave.query.iterator.QueryOptions.QUERY_ID;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.iterators.IteratorEnvironment;
import org.apache.accumulo.core.iterators.OptionDescriber;
import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
import org.apache.log4j.Logger;

/**
* An iterator used to log the start and end of each method run by the {@link SortedKeyValueIterator} above it in the iterator stack. Logs the QueryID
* associated with each method. Logs are written on the TServer where the iterator is running
*/
public class QueryLogIterator implements SortedKeyValueIterator<Key,Value>, OptionDescriber {

private static final Logger log = Logger.getLogger(QueryLogIterator.class);
private static final String CLASS_NAME = QueryLogIterator.class.getSimpleName();

private String queryID;
private SortedKeyValueIterator<Key,Value> source;
private IteratorEnvironment env;

/**
* Default constructor
*/
public QueryLogIterator() {
// no-arg constructor
}

/**
* Class copy constructor
*/
public QueryLogIterator(QueryLogIterator other, IteratorEnvironment env) {
this.source = other.source.deepCopy(env);
this.env = other.env;
this.queryID = other.queryID;
}

/**
* Wraps the init() method of the iterator above it, logging the start and end of the method along with its query id.
*/
@Override
public void init(SortedKeyValueIterator<Key,Value> source, Map<String,String> options, IteratorEnvironment env) throws IOException {

try {
logStartOf("init()");
this.queryID = options.get(QUERY_ID);
this.source = source;
this.env = env;
} finally {
logEndOf("init()");
}
}

/**
* Logs the query id and {@link SortedKeyValueIterator} method name before the method is run.
*/
private void logStartOf(String methodName) {
if (log.isInfoEnabled()) {
log.info(CLASS_NAME + " " + methodName + " Started QueryID: " + this.queryID);
}
}

/**
* Logs the query id and {@link SortedKeyValueIterator} method name after the method is run.
*/
private void logEndOf(String methodName) {
if (log.isInfoEnabled()) {
log.info(CLASS_NAME + " " + methodName + " Ended QueryID: " + this.queryID);
}
}

/**
* Wraps the hasTop() method of the iterator above it, logging the start and end of the method along with its query id.
*/
@Override
public boolean hasTop() {
boolean result;

try {
logStartOf("hasTop()");
result = source.hasTop();
} finally {
logEndOf("hasTop()");
}
return result;
}

/**
* Wraps the next() method of the iterator above it, logging the start and end of the method along with its query id.
*/
@Override
public void next() throws IOException {
try {
logStartOf("next()");
source.next();
} finally {
logEndOf("next()");
}
}

/**
* Wraps the getTopKey() method of the iterator above it, logging the start and end of the method along with its query id.
*/
@Override
public Key getTopKey() {
Key k;
try {
logStartOf("getTopKey()");
k = source.getTopKey();
} finally {
logEndOf("getTopKey()");
}
return k;
}

/**
* Wraps the getTopValue() method of the iterator above it, logging the start and end of the method along with its query id.
*/
@Override
public Value getTopValue() {
Value v;
try {
logStartOf("getTopValue()");
v = source.getTopValue();
} finally {
logEndOf("getTopValue()");
}
return v;
}

/**
* Wraps the deepCopy() method of the iterator above it, logging the start and end of the method along with its query id.
*/
@Override
public SortedKeyValueIterator<Key,Value> deepCopy(IteratorEnvironment iteratorEnvironment) {

QueryLogIterator copy;

try {
logStartOf("deepCopy()");
copy = new QueryLogIterator(this, this.env);
} finally {
logEndOf("deepCopy()");
}
return copy;
}

/**
* Wraps the seek() method of the iterator above it, logging the start and end of the method along with its query id.
*/
@Override
public void seek(Range range, Collection<ByteSequence> collection, boolean b) throws IOException {

try {
logStartOf("seek()");
this.source.seek(range, collection, b);
} finally {
logEndOf("seek()");
}
}

/**
* Returns a {@link org.apache.accumulo.core.iterators.OptionDescriber.IteratorOptions} object containing a description of the iterator and an option for
* the QueryID.
*/
@Override
public IteratorOptions describeOptions() {
Map<String,String> options = new HashMap<>();
options.put(QUERY_ID, "The QueryID to be logged as methods are invoked");

return new IteratorOptions(getClass().getSimpleName(), "An iterator used to log the QueryID", options, null);
}

/**
* Returns true if the options provided contains the QueryID.
*/
@Override
public boolean validateOptions(Map<String,String> options) {
return options.containsKey(QUERY_ID);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
Expand All @@ -39,12 +38,7 @@
import org.apache.log4j.Logger;
import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
Expand Down
Loading

0 comments on commit e5e1883

Please sign in to comment.