3333import org .elasticsearch .search .builder .SearchSourceBuilder ;
3434
3535import java .io .IOException ;
36+ import java .io .PrintWriter ;
37+ import java .io .StringWriter ;
3638import java .util .ArrayList ;
3739import java .util .Arrays ;
3840import java .util .Base64 ;
@@ -53,6 +55,7 @@ public class Job {
5355
5456 // Constants
5557 public static final boolean DEFAULT_INCLUDE_ATTRIBUTES = true ;
58+ public static final boolean DEFAULT_INCLUDE_ERROR_TRACE = true ;
5659 public static final boolean DEFAULT_INCLUDE_EXPLANATION = false ;
5760 public static final boolean DEFAULT_INCLUDE_HITS = true ;
5861 public static final boolean DEFAULT_INCLUDE_QUERIES = false ;
@@ -65,6 +68,7 @@ public class Job {
6568 // Job configuration
6669 private Input input ;
6770 private boolean includeAttributes = DEFAULT_INCLUDE_ATTRIBUTES ;
71+ private boolean includeErrorTrace = DEFAULT_INCLUDE_ERROR_TRACE ;
6872 private boolean includeExplanation = DEFAULT_INCLUDE_EXPLANATION ;
6973 private boolean includeHits = DEFAULT_INCLUDE_HITS ;
7074 private boolean includeQueries = DEFAULT_INCLUDE_QUERIES ;
@@ -79,6 +83,7 @@ public class Job {
7983 private NodeClient client ;
8084 private Map <String , Set <String >> docIds = new TreeMap <>();
8185 private String error = null ;
86+ private boolean failed = false ;
8287 private List <String > hits = new ArrayList <>();
8388 private int hop = 0 ;
8489 private Set <String > missingIndices = new TreeSet <>();
@@ -89,16 +94,20 @@ public Job(NodeClient client) {
8994 this .client = client ;
9095 }
9196
92- public static String serializeException (Exception e ) throws IOException {
93- String serialized ;
94- if (e instanceof ElasticsearchException ) {
95- ElasticsearchException ee = (ElasticsearchException ) e ;
96- String cause = Strings .toString (ee .toXContent (jsonBuilder ().startObject (), ToXContent .EMPTY_PARAMS ).endObject ());
97- serialized = "{\" error\" :{\" root_cause\" :[" + cause + "],\" type\" :\" " + ElasticsearchException .getExceptionName (ee ) + "\" ,\" reason\" :\" " + e .getMessage () + "\" },\" status\" :" + ee .status ().getStatus () + "}" ;
98- } else {
99- serialized = "{\" error\" :{\" type\" :\" " + e .getClass () + "\" ,\" reason\" :\" " + e .getMessage () + "\" }}" ;
97+ public static String serializeException (Exception e , boolean includeErrorTrace ) {
98+ List <String > errorParts = new ArrayList <>();
99+ if (e instanceof ElasticsearchException )
100+ errorParts .add ("\" by\" :\" elasticsearch\" " );
101+ else
102+ errorParts .add ("\" by\" :\" zentity\" " );
103+ errorParts .add ("\" type\" :\" " + e .getClass ().getCanonicalName () + "\" " );
104+ errorParts .add ("\" reason\" :\" " + e .getMessage () + "\" " );
105+ if (includeErrorTrace ) {
106+ StringWriter traceWriter = new StringWriter ();
107+ e .printStackTrace (new PrintWriter (traceWriter ));
108+ errorParts .add ("\" stack_trace\" :" + Json .quoteString (traceWriter .toString ()) + "" );
100109 }
101- return serialized ;
110+ return String . join ( "," , errorParts ) ;
102111 }
103112
104113 public static String serializeLoggedQuery (Input input , int _hop , int _query , String indexName , String request , String response , List <String > resolvers , TreeMap <Integer , TreeMap <String , TreeMap >> resolversFilterTreeGrouped , List <String > termResolvers , TreeMap <String , TreeMap > termResolversFilterTree ) throws JsonProcessingException {
@@ -522,6 +531,7 @@ private void resetState() {
522531 this .attributes = new TreeMap <>(this .input ().attributes ());
523532 this .docIds = new TreeMap <>();
524533 this .error = null ;
534+ this .failed = false ;
525535 this .hits = new ArrayList <>();
526536 this .hop = 0 ;
527537 this .missingIndices = new TreeSet <>();
@@ -537,6 +547,14 @@ public void includeAttributes(boolean includeAttributes) {
537547 this .includeAttributes = includeAttributes ;
538548 }
539549
550+ public boolean includeErrorTrace () {
551+ return this .includeErrorTrace ;
552+ }
553+
554+ public void includeErrorTrace (boolean includeErrorTrace ) {
555+ this .includeErrorTrace = includeErrorTrace ;
556+ }
557+
540558 public boolean includeExplanation () {
541559 return this .includeExplanation ;
542560 }
@@ -609,6 +627,14 @@ public void input(Input input) {
609627 this .input = input ;
610628 }
611629
630+ public boolean failed () {
631+ return this .failed ;
632+ }
633+
634+ public boolean ran () {
635+ return this .ran ;
636+ }
637+
612638 /**
613639 * Submit a search query to Elasticsearch.
614640 *
@@ -997,7 +1023,6 @@ else if (!resolversClause.isEmpty())
9971023 // Submit query to Elasticsearch.
9981024 SearchResponse response = null ;
9991025 Exception responseError = null ;
1000- boolean fatalError = false ;
10011026 try {
10021027 response = this .search (indexName , query );
10031028 } catch (IndexNotFoundException e ) {
@@ -1006,7 +1031,7 @@ else if (!resolversClause.isEmpty())
10061031 responseError = e ;
10071032 } catch (Exception e ) {
10081033 // Fail the job for any other error.
1009- fatalError = true ;
1034+ this . failed = true ;
10101035 responseError = e ;
10111036 }
10121037
@@ -1028,16 +1053,18 @@ else if (!resolversClause.isEmpty())
10281053 }
10291054 responseString = responseDataCopyObj .toString ();
10301055 } else {
1031- responseString = serializeException (responseError );
1056+ ElasticsearchException e = (ElasticsearchException ) responseError ;
1057+ String cause = Strings .toString (e .toXContent (jsonBuilder ().startObject (), ToXContent .EMPTY_PARAMS ).endObject ());
1058+ responseString = "{\" error\" :{\" root_cause\" :[" + cause + "],\" type\" :\" " + ElasticsearchException .getExceptionName (e ) + "\" ,\" reason\" :\" " + e .getMessage () + "\" },\" status\" :" + e .status ().getStatus () + "}" ;
10321059 }
10331060 String logged = serializeLoggedQuery (this .input , this .hop , _query , indexName , query , responseString , resolvers , resolversFilterTreeGrouped , termResolvers , termResolversFilterTree );
10341061 this .queries .add (logged );
10351062 }
10361063
10371064 // Stop traversing if there was an error not due to a missing index.
10381065 // Include the logged query in the response.
1039- if (fatalError ) {
1040- this .error = serializeLoggedQuery ( this . input , this . hop , _query , indexName , query , serializeException (responseError ), resolvers , resolversFilterTreeGrouped , termResolvers , termResolversFilterTree );
1066+ if (this . failed ) {
1067+ this .error = serializeException (responseError , this . includeErrorTrace );
10411068 return ;
10421069 }
10431070
@@ -1228,7 +1255,7 @@ else if (input.model().matchers().containsKey(matcherName))
12281255 * @return A JSON string to be returned as the body of the response to a client.
12291256 * @throws IOException
12301257 */
1231- public String run () throws IOException , ValidationException {
1258+ public String run () throws IOException {
12321259 try {
12331260
12341261 // Reset the state of the job if reusing this Job object.
@@ -1238,22 +1265,28 @@ public String run() throws IOException, ValidationException {
12381265 this .attributes = new TreeMap <>(this .input .attributes ());
12391266
12401267 // Start timer and begin job
1268+ String response ;
12411269 long startTime = System .nanoTime ();
1242- this .traverse ();
1243- long took = TimeUnit .MILLISECONDS .convert (System .nanoTime () - startTime , TimeUnit .NANOSECONDS );
1244-
1245- // Format response
1246- List <String > responseParts = new ArrayList <>();
1247- responseParts .add ("\" took\" :" + Long .toString (took ));
1248- if (this .error != null )
1249- responseParts .add ("\" error\" :" + this .error );
1250- if (this .includeHits )
1251- responseParts .add ("\" hits\" :{\" total\" :" + this .hits .size () + ",\" hits\" :[" + String .join ("," , this .hits ) + "]}" );
1252- if (this .includeQueries || this .profile )
1253- responseParts .add ("\" queries\" :[" + queries + "]" );
1254- String response = "{" + String .join ("," , responseParts ) + "}" ;
1255- if (this .pretty )
1256- response = Json .ORDERED_MAPPER .writerWithDefaultPrettyPrinter ().writeValueAsString (Json .ORDERED_MAPPER .readTree (response ));
1270+ try {
1271+ this .traverse ();
1272+ } catch (Exception e ) {
1273+ this .failed = true ;
1274+ this .error = serializeException (e , this .includeErrorTrace );
1275+ } finally {
1276+ long took = TimeUnit .MILLISECONDS .convert (System .nanoTime () - startTime , TimeUnit .NANOSECONDS );
1277+ // Format response
1278+ List <String > responseParts = new ArrayList <>();
1279+ responseParts .add ("\" took\" :" + Long .toString (took ));
1280+ if (this .error != null )
1281+ responseParts .add ("\" error\" :{" + this .error + "}" );
1282+ if (this .includeHits )
1283+ responseParts .add ("\" hits\" :{\" total\" :" + this .hits .size () + ",\" hits\" :[" + String .join ("," , this .hits ) + "]}" );
1284+ if (this .includeQueries || this .profile )
1285+ responseParts .add ("\" queries\" :[" + queries + "]" );
1286+ response = "{" + String .join ("," , responseParts ) + "}" ;
1287+ if (this .pretty )
1288+ response = Json .ORDERED_MAPPER .writerWithDefaultPrettyPrinter ().writeValueAsString (Json .ORDERED_MAPPER .readTree (response ));
1289+ }
12571290 return response ;
12581291
12591292 } finally {
0 commit comments