Merge pull request #12260 from s1monw/issues/12239
Include stacktrace in rendered exceptions
This commit is contained in:
commit
9c6ed8c238
|
@ -43,7 +43,10 @@ import java.util.*;
|
||||||
*/
|
*/
|
||||||
public class ElasticsearchException extends RuntimeException implements ToXContent {
|
public class ElasticsearchException extends RuntimeException implements ToXContent {
|
||||||
|
|
||||||
public static final String REST_EXCEPTION_SKIP_CAUSE = "rest.exception.skip_cause";
|
public static final String REST_EXCEPTION_SKIP_CAUSE = "rest.exception.cause.skip";
|
||||||
|
public static final String REST_EXCEPTION_SKIP_STACK_TRACE = "rest.exception.stacktrace.skip";
|
||||||
|
private static final boolean REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT = false;
|
||||||
|
private static final boolean REST_EXCEPTION_SKIP_CAUSE_DEFAULT = false;
|
||||||
private static final String INDEX_HEADER_KEY = "es.index";
|
private static final String INDEX_HEADER_KEY = "es.index";
|
||||||
private static final String SHARD_HEADER_KEY = "es.shard";
|
private static final String SHARD_HEADER_KEY = "es.shard";
|
||||||
private static final String RESOURCE_HEADER_TYPE_KEY = "es.resource.type";
|
private static final String RESOURCE_HEADER_TYPE_KEY = "es.resource.type";
|
||||||
|
@ -270,6 +273,9 @@ public class ElasticsearchException extends RuntimeException implements ToXConte
|
||||||
}
|
}
|
||||||
innerToXContent(builder, params);
|
innerToXContent(builder, params);
|
||||||
renderHeader(builder, params);
|
renderHeader(builder, params);
|
||||||
|
if (params.paramAsBoolean(REST_EXCEPTION_SKIP_STACK_TRACE, REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT) == false) {
|
||||||
|
builder.field("stack_trace", ExceptionsHelper.stackTrace(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
@ -286,7 +292,7 @@ public class ElasticsearchException extends RuntimeException implements ToXConte
|
||||||
*/
|
*/
|
||||||
protected final void causeToXContent(XContentBuilder builder, Params params) throws IOException {
|
protected final void causeToXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
final Throwable cause = getCause();
|
final Throwable cause = getCause();
|
||||||
if (cause != null && params.paramAsBoolean(REST_EXCEPTION_SKIP_CAUSE, false) == false) {
|
if (cause != null && params.paramAsBoolean(REST_EXCEPTION_SKIP_CAUSE, REST_EXCEPTION_SKIP_CAUSE_DEFAULT) == false) {
|
||||||
builder.field("caused_by");
|
builder.field("caused_by");
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
toXContent(builder, params, cause);
|
toXContent(builder, params, cause);
|
||||||
|
@ -342,6 +348,9 @@ public class ElasticsearchException extends RuntimeException implements ToXConte
|
||||||
toXContent(builder, params, ex.getCause());
|
toXContent(builder, params, ex.getCause());
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
|
if (params.paramAsBoolean(REST_EXCEPTION_SKIP_STACK_TRACE, REST_EXCEPTION_SKIP_STACK_TRACE_DEFAULT) == false) {
|
||||||
|
builder.field("stack_trace", ExceptionsHelper.stackTrace(ex));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,10 +52,12 @@ import java.io.EOFException;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.NoSuchFileException;
|
import java.nio.file.NoSuchFileException;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
public class ESExceptionTests extends ESTestCase {
|
public class ESExceptionTests extends ESTestCase {
|
||||||
|
private static final ToXContent.Params PARAMS = new ToXContent.MapParams(Collections.singletonMap(ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "true"));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStatus() {
|
public void testStatus() {
|
||||||
|
@ -144,7 +146,7 @@ public class ESExceptionTests extends ESTestCase {
|
||||||
SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1});
|
SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1});
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
ex.toXContent(builder, PARAMS);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
String expected = "{\"type\":\"search_phase_execution_exception\",\"reason\":\"all shards failed\",\"phase\":\"search\",\"grouped\":true,\"failed_shards\":[{\"shard\":1,\"index\":\"foo\",\"node\":\"node_1\",\"reason\":{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\"}}]}";
|
String expected = "{\"type\":\"search_phase_execution_exception\",\"reason\":\"all shards failed\",\"phase\":\"search\",\"grouped\":true,\"failed_shards\":[{\"shard\":1,\"index\":\"foo\",\"node\":\"node_1\",\"reason\":{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\"}}]}";
|
||||||
assertEquals(expected, builder.string());
|
assertEquals(expected, builder.string());
|
||||||
|
@ -159,7 +161,7 @@ public class ESExceptionTests extends ESTestCase {
|
||||||
SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1, failure2});
|
SearchPhaseExecutionException ex = new SearchPhaseExecutionException("search", "all shards failed", new ShardSearchFailure[]{failure, failure1, failure2});
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
ex.toXContent(builder, PARAMS);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
String expected = "{\"type\":\"search_phase_execution_exception\",\"reason\":\"all shards failed\",\"phase\":\"search\",\"grouped\":true,\"failed_shards\":[{\"shard\":1,\"index\":\"foo\",\"node\":\"node_1\",\"reason\":{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\"}},{\"shard\":1,\"index\":\"foo1\",\"node\":\"node_1\",\"reason\":{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo1\"}}]}";
|
String expected = "{\"type\":\"search_phase_execution_exception\",\"reason\":\"all shards failed\",\"phase\":\"search\",\"grouped\":true,\"failed_shards\":[{\"shard\":1,\"index\":\"foo\",\"node\":\"node_1\",\"reason\":{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\"}},{\"shard\":1,\"index\":\"foo1\",\"node\":\"node_1\",\"reason\":{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo1\"}}]}";
|
||||||
assertEquals(expected, builder.string());
|
assertEquals(expected, builder.string());
|
||||||
|
@ -184,7 +186,7 @@ public class ESExceptionTests extends ESTestCase {
|
||||||
ElasticsearchException ex = new SearchParseException(new TestSearchContext(), "foo", new XContentLocation(1,0));
|
ElasticsearchException ex = new SearchParseException(new TestSearchContext(), "foo", new XContentLocation(1,0));
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
ex.toXContent(builder, PARAMS);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
String expected = "{\"type\":\"search_parse_exception\",\"reason\":\"foo\",\"line\":1,\"col\":0}";
|
String expected = "{\"type\":\"search_parse_exception\",\"reason\":\"foo\",\"line\":1,\"col\":0}";
|
||||||
|
@ -194,7 +196,7 @@ public class ESExceptionTests extends ESTestCase {
|
||||||
ElasticsearchException ex = new ElasticsearchException("foo", new ElasticsearchException("bar", new IllegalArgumentException("index is closed", new RuntimeException("foobar"))));
|
ElasticsearchException ex = new ElasticsearchException("foo", new ElasticsearchException("bar", new IllegalArgumentException("index is closed", new RuntimeException("foobar"))));
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
ex.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
ex.toXContent(builder, PARAMS);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
String expected = "{\"type\":\"exception\",\"reason\":\"foo\",\"caused_by\":{\"type\":\"exception\",\"reason\":\"bar\",\"caused_by\":{\"type\":\"illegal_argument_exception\",\"reason\":\"index is closed\",\"caused_by\":{\"type\":\"runtime_exception\",\"reason\":\"foobar\"}}}}";
|
String expected = "{\"type\":\"exception\",\"reason\":\"foo\",\"caused_by\":{\"type\":\"exception\",\"reason\":\"bar\",\"caused_by\":{\"type\":\"illegal_argument_exception\",\"reason\":\"index is closed\",\"caused_by\":{\"type\":\"runtime_exception\",\"reason\":\"foobar\"}}}}";
|
||||||
|
@ -209,7 +211,7 @@ public class ESExceptionTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex);
|
ElasticsearchException.toXContent(builder, PARAMS, ex);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
String expected = "{\"type\":\"file_not_found_exception\",\"reason\":\"foo not found\"}";
|
String expected = "{\"type\":\"file_not_found_exception\",\"reason\":\"foo not found\"}";
|
||||||
|
@ -220,7 +222,7 @@ public class ESExceptionTests extends ESTestCase {
|
||||||
QueryParsingException ex = new TestQueryParsingException(new Index("foo"), 1, 2, "foobar", null);
|
QueryParsingException ex = new TestQueryParsingException(new Index("foo"), 1, 2, "foobar", null);
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex);
|
ElasticsearchException.toXContent(builder, PARAMS, ex);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
String expected = "{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\",\"line\":1,\"col\":2}";
|
String expected = "{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\",\"line\":1,\"col\":2}";
|
||||||
assertEquals(expected, builder.string());
|
assertEquals(expected, builder.string());
|
||||||
|
@ -230,13 +232,13 @@ public class ESExceptionTests extends ESTestCase {
|
||||||
ElasticsearchException ex = new RemoteTransportException("foobar", new FileNotFoundException("foo not found"));
|
ElasticsearchException ex = new RemoteTransportException("foobar", new FileNotFoundException("foo not found"));
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex);
|
ElasticsearchException.toXContent(builder, PARAMS, ex);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
XContentBuilder otherBuilder = XContentFactory.jsonBuilder();
|
XContentBuilder otherBuilder = XContentFactory.jsonBuilder();
|
||||||
|
|
||||||
otherBuilder.startObject();
|
otherBuilder.startObject();
|
||||||
ex.toXContent(otherBuilder, ToXContent.EMPTY_PARAMS);
|
ex.toXContent(otherBuilder, PARAMS);
|
||||||
otherBuilder.endObject();
|
otherBuilder.endObject();
|
||||||
assertEquals(otherBuilder.string(), builder.string());
|
assertEquals(otherBuilder.string(), builder.string());
|
||||||
assertEquals("{\"type\":\"file_not_found_exception\",\"reason\":\"foo not found\"}", builder.string());
|
assertEquals("{\"type\":\"file_not_found_exception\",\"reason\":\"foo not found\"}", builder.string());
|
||||||
|
@ -248,7 +250,7 @@ public class ESExceptionTests extends ESTestCase {
|
||||||
ex.addHeader("test_multi", "some value", "another value");
|
ex.addHeader("test_multi", "some value", "another value");
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
ElasticsearchException.toXContent(builder, ToXContent.EMPTY_PARAMS, ex);
|
ElasticsearchException.toXContent(builder, PARAMS, ex);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
assertThat(builder.string(), Matchers.anyOf( // iteration order depends on platform
|
assertThat(builder.string(), Matchers.anyOf( // iteration order depends on platform
|
||||||
equalTo("{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\",\"line\":1,\"col\":2,\"header\":{\"test_multi\":[\"some value\",\"another value\"],\"test\":\"some value\"}}"),
|
equalTo("{\"type\":\"test_query_parsing_exception\",\"reason\":\"foobar\",\"index\":\"foo\",\"line\":1,\"col\":2,\"header\":{\"test_multi\":[\"some value\",\"another value\"],\"test\":\"some value\"}}"),
|
||||||
|
|
|
@ -78,6 +78,7 @@ import java.nio.file.FileVisitor;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -525,7 +526,7 @@ public class ExceptionSerializationTests extends ESTestCase {
|
||||||
try {
|
try {
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
x.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
x.toXContent(builder, new ToXContent.MapParams(Collections.singletonMap(ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "true")));
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
return builder.string();
|
return builder.string();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
package org.elasticsearch.action.search;
|
package org.elasticsearch.action.search;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.action.support.IndicesOptions;
|
import org.elasticsearch.action.support.IndicesOptions;
|
||||||
import org.elasticsearch.test.StreamsUtils;
|
import org.elasticsearch.test.StreamsUtils;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
@ -28,6 +29,7 @@ import org.elasticsearch.test.ESTestCase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
@ -123,7 +125,7 @@ public class MultiSearchRequestTests extends ESTestCase {
|
||||||
public void testResponseErrorToXContent() throws IOException {
|
public void testResponseErrorToXContent() throws IOException {
|
||||||
MultiSearchResponse response = new MultiSearchResponse(new MultiSearchResponse.Item[]{new MultiSearchResponse.Item(null, new IllegalStateException("foobar")), new MultiSearchResponse.Item(null, new IllegalStateException("baaaaaazzzz"))});
|
MultiSearchResponse response = new MultiSearchResponse(new MultiSearchResponse.Item[]{new MultiSearchResponse.Item(null, new IllegalStateException("foobar")), new MultiSearchResponse.Item(null, new IllegalStateException("baaaaaazzzz"))});
|
||||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
response.toXContent(builder, new ToXContent.MapParams(Collections.singletonMap(ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "true")));
|
||||||
assertEquals("\"responses\"[{\"error\":{\"root_cause\":[{\"type\":\"illegal_state_exception\",\"reason\":\"foobar\"}],\"type\":\"illegal_state_exception\",\"reason\":\"foobar\"}},{\"error\":{\"root_cause\":[{\"type\":\"illegal_state_exception\",\"reason\":\"baaaaaazzzz\"}],\"type\":\"illegal_state_exception\",\"reason\":\"baaaaaazzzz\"}}]",
|
assertEquals("\"responses\"[{\"error\":{\"root_cause\":[{\"type\":\"illegal_state_exception\",\"reason\":\"foobar\"}],\"type\":\"illegal_state_exception\",\"reason\":\"foobar\"}},{\"error\":{\"root_cause\":[{\"type\":\"illegal_state_exception\",\"reason\":\"baaaaaazzzz\"}],\"type\":\"illegal_state_exception\",\"reason\":\"baaaaaazzzz\"}}]",
|
||||||
builder.string());
|
builder.string());
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,7 @@ public class BytesRestResponseTests extends ESTestCase {
|
||||||
|
|
||||||
DetailedExceptionRestChannel(RestRequest request) {
|
DetailedExceptionRestChannel(RestRequest request) {
|
||||||
super(request, true);
|
super(request, true);
|
||||||
|
request.params().put(ElasticsearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue