Skip to content

Commit

Permalink
Merge pull request #954 from Graylog2/947-parse-errors
Browse files Browse the repository at this point in the history
Fix error handling for search errors
  • Loading branch information
joschi committed Feb 9, 2015
2 parents 277f12a + e853e81 commit 7c3ec85
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 107 deletions.
Expand Up @@ -48,6 +48,10 @@ public int getHttpCode() {
return response != null ? response.getStatusCode() : -1;
}

public byte[] getResponseBody() throws IOException {
return response != null ? response.getResponseBodyAsBytes() : new byte[0];
}

@Override
public String getMessage() {
final StringBuilder sb = new StringBuilder();
Expand Down
Expand Up @@ -130,12 +130,11 @@ private <T> T doSearch(Class<T> clazz, MediaType mediaType, int pageSize, Set<St
if (selectedFields != null && !selectedFields.isEmpty()) {
builder.queryParam("fields", Joiner.on(',').skipNulls().join(selectedFields));
}
final T result = builder
return builder
.accept(mediaType)
.timeout(KEITH, TimeUnit.SECONDS)
.expect(200, 400)
.execute();
return result;
}

public SearchResult search() throws IOException, APIException {
Expand All @@ -145,7 +144,7 @@ public SearchResult search() throws IOException, APIException {
throw new APIException(null, null, new RuntimeException("Empty search response, this is likely a bug in exception handling."));
}

SearchResult result = new SearchResult(
return new SearchResult(
query,
response.builtQuery,
timeRange,
Expand All @@ -154,13 +153,10 @@ public SearchResult search() throws IOException, APIException {
response.messages,
response.fields,
response.usedIndices,
response.error != null ? response.error : response.genericError,
response.getFromDataTime(),
response.getToDataTime(),
fieldMapper
);

return result;
}

public String searchAsCsv(Set<String> selectedFields) throws IOException, APIException {
Expand Down
@@ -0,0 +1,33 @@
package org.graylog2.restclient.models.api.responses;

import com.fasterxml.jackson.annotation.JsonProperty;

import javax.annotation.Nullable;

public class QueryParseError {
@JsonProperty("query")
public String query;

@JsonProperty("message")
@Nullable
public String message;

@JsonProperty("begin_column")
@Nullable
public Integer beginColumn;

@JsonProperty("begin_line")
@Nullable
public Integer beginLine;

@JsonProperty("end_column")
@Nullable
public Integer endColumn;

@JsonProperty("end_line")
@Nullable
public Integer endLine;

@JsonProperty("exception_name")
public String exceptionName;
}
Expand Up @@ -16,14 +16,14 @@
*/
package org.graylog2.restclient.models.api.responses;

import org.graylog2.restclient.models.api.responses.system.indices.IndexRangeSummary;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.graylog2.restclient.models.api.responses.system.indices.IndexRangeSummary;
import org.joda.time.DateTime;

import javax.annotation.Nullable;
import java.util.List;

public class SearchResultResponse {

public int time;
public String query;
public long total_results;
Expand All @@ -36,43 +36,14 @@ public class SearchResultResponse {
@JsonProperty("built_query")
public String builtQuery;

public ParseError error;

@JsonProperty("generic_error")
public GenericError genericError;

public String from;

public String to;

public DateTime getFromDataTime() {
return from != null ? DateTime.parse(from) : null;
}

public DateTime getToDataTime() {
return to != null ? DateTime.parse(to) : null;
}

public abstract static class QueryError {}

public static class ParseError extends QueryError {
@JsonProperty("begin_column")
public int beginColumn;

@JsonProperty("begin_line")
public int beginLine;

@JsonProperty("end_column")
public int endColumn;

@JsonProperty("end_line")
public int endLine;
}

public static class GenericError extends QueryError {
@JsonProperty("exception_name")
public String exceptionName;

public String message;
}

}
Expand Up @@ -51,7 +51,6 @@ public class SearchResult {
private final long totalResultCount;
private final int tookMs;
private final List<MessageResult> results;
private final SearchResultResponse.QueryError error;
private final List<Field> fields;
private final List<IndexRangeSummary> usedIndices;
private List<Field> allFields;
Expand All @@ -66,7 +65,6 @@ public SearchResult(String originalQuery,
List<MessageSummaryResponse> summaryResponses,
List<String> fields,
List<IndexRangeSummary> usedIndices,
SearchResultResponse.QueryError error,
DateTime fromDateTime,
DateTime toDateTime,
FieldMapper fieldMapper) {
Expand All @@ -75,7 +73,6 @@ public SearchResult(String originalQuery,
this.timeRange = timeRange;
this.totalResultCount = totalResultCount;
this.tookMs = tookMs;
this.error = error;
this.fields = buildFields(fields);
this.usedIndices = usedIndices;
this.fromDateTime = fromDateTime;
Expand Down Expand Up @@ -143,10 +140,6 @@ public String getBuiltQuery() {
return builtQuery;
}

public SearchResultResponse.QueryError getError() {
return error;
}

public DateTime getFromDateTime() {
return fromDateTime;
}
Expand Down
Expand Up @@ -31,16 +31,15 @@
import org.graylog2.indexer.searches.Searches;
import org.graylog2.indexer.searches.Sorting;
import org.graylog2.indexer.searches.timeranges.AbsoluteRange;
import org.graylog2.shared.rest.resources.RestResource;
import org.graylog2.rest.resources.search.responses.FieldStatsResult;
import org.graylog2.rest.resources.search.responses.GenericError;
import org.graylog2.rest.resources.search.responses.HistogramResult;
import org.graylog2.rest.resources.search.responses.QueryParseError;
import org.graylog2.rest.resources.search.responses.SearchResponse;
import org.graylog2.rest.resources.search.responses.TermsResult;
import org.graylog2.rest.resources.search.responses.TermsStatsResult;
import org.graylog2.rest.resources.search.responses.TimeRange;
import org.graylog2.security.RestPermissions;
import org.graylog2.shared.rest.resources.RestResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -178,9 +177,12 @@ protected Sorting buildSorting(String sort) {

protected BadRequestException createRequestExceptionForParseFailure(String query, SearchPhaseExecutionException e) {
LOG.warn("Unable to execute search: {}", e.getMessage());
QueryParseError errorMessage = QueryParseError.create(query, e.getMessage(), e.getClass().getCanonicalName());

// we won't actually iterate over all of the shard failures, only the first one,
// since we assume that parse errors happen on all of the shards.
for (ShardSearchFailure failure : e.shardFailures()) {
//noinspection ThrowableResultOfMethodCallIgnored
Throwable unwrapped = ExceptionsHelper.unwrapCause(failure.failure());
if (!(unwrapped instanceof SearchParseException)) {
LOG.warn("Unhandled ShardSearchFailure", e);
Expand All @@ -189,10 +191,9 @@ protected BadRequestException createRequestExceptionForParseFailure(String query
Throwable rootCause = ((SearchParseException) unwrapped).getRootCause();
if (rootCause instanceof ParseException) {
Token currentToken = ((ParseException) rootCause).currentToken;
final QueryParseError queryParseError;
if (currentToken == null) {
LOG.warn("No position/token available for ParseException.");
queryParseError = QueryParseError.create(query);
LOG.warn("No position/token available for ParseException.", rootCause);
errorMessage = QueryParseError.create(query, rootCause.getMessage(), rootCause.getClass().getCanonicalName());
} else {
// scan for first usable token with position information
int beginColumn = 0;
Expand All @@ -204,25 +205,28 @@ protected BadRequestException createRequestExceptionForParseFailure(String query
beginLine = currentToken.beginLine;
endColumn = currentToken.endColumn;
endLine = currentToken.endLine;

currentToken = currentToken.next;
}

queryParseError = QueryParseError.create(query, beginColumn, beginLine, endColumn, endLine);
errorMessage = QueryParseError.create(
query,
beginColumn,
beginLine,
endColumn,
endLine,
rootCause.getMessage(),
rootCause.getClass().getCanonicalName());
}

return new BadRequestException(Response.status(Response.Status.BAD_REQUEST).entity(queryParseError).build());
} else if (rootCause instanceof NumberFormatException) {
final GenericError genericError = GenericError.create(query, rootCause.getClass().getCanonicalName(), rootCause.getMessage());
return new BadRequestException(Response.status(Response.Status.BAD_REQUEST).entity(genericError).build());
} else {
LOG.info("Root cause of SearchParseException has unexpected, generic type!" + rootCause.getClass());
final GenericError genericError = GenericError.create(query, rootCause.getClass().getCanonicalName(), rootCause.getMessage());
return new BadRequestException(Response.status(Response.Status.BAD_REQUEST).entity(genericError).build());
LOG.debug("Root cause of SearchParseException has unexpected, generic type: " + rootCause.getClass(), rootCause);
errorMessage = QueryParseError.create(query, rootCause.getMessage(), rootCause.getClass().getCanonicalName());
}
}

return new BadRequestException();
return new BadRequestException(Response
.status(Response.Status.BAD_REQUEST)
.entity(errorMessage)
.build());
}

public void checkSearchPermission(String filter, String searchPermission) {
Expand Down

This file was deleted.

Expand Up @@ -20,29 +20,48 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;

import javax.annotation.Nullable;

@JsonAutoDetect
@AutoValue
public abstract class QueryParseError {
@JsonProperty
public abstract String query();

@JsonProperty
public abstract int beginColumn();
@Nullable
public abstract Integer beginColumn();

@JsonProperty
@Nullable
public abstract Integer beginLine();

@JsonProperty
@Nullable
public abstract Integer endColumn();

@JsonProperty
public abstract int beginLine();
@Nullable
public abstract Integer endLine();

@JsonProperty
public abstract int endColumn();
@Nullable
public abstract String message();

@JsonProperty
public abstract int endLine();
public abstract String exceptionName();

public static QueryParseError create(String query, int beginColumn, int beginLine, int endColumn, int endLine) {
return new AutoValue_QueryParseError(query, beginColumn, beginLine, endColumn, endLine);
public static QueryParseError create(String query,
@Nullable Integer beginColumn,
@Nullable Integer beginLine,
@Nullable Integer endColumn,
@Nullable Integer endLine,
@Nullable String message,
String exceptionName) {
return new AutoValue_QueryParseError(query, beginColumn, beginLine, endColumn, endLine, message, exceptionName);
}

public static QueryParseError create(String query) {
return new AutoValue_QueryParseError(query, 0, 0, 0, 0);
public static QueryParseError create(String query, @Nullable String message, String exceptionName) {
return create(query, null, null, null, null, message, exceptionName);
}
}

0 comments on commit 7c3ec85

Please sign in to comment.