diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/ScenarioErrorHandler.java b/engine-core/src/main/java/io/nosqlbench/engine/core/ScenarioErrorHandler.java
new file mode 100644
index 000000000..f08bfc006
--- /dev/null
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/ScenarioErrorHandler.java
@@ -0,0 +1,83 @@
+package io.nosqlbench.engine.core;
+
+import io.nosqlbench.nb.api.errors.BasicError;
+import org.graalvm.polyglot.PolyglotException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.script.ScriptException;
+
+/**
+ * This class is meant to consolidate the error handling logic for the varios types of errors
+ * that may bubble up from the layers within NoSQLBench. As a layered system, some of the included
+ * libraries tend to layer the exceptions beyond a point of recognizability. The logic in this
+ * class should do the following:
+ *
+ *
+ * - Report an error in the most intelligible way to the user.
+ *
+ *
+ * That is all. When this error handler is invoked, it is a foregone conclusion that the scenario
+ * is not able to continue, else the error would have been trapped and handled internal to a lower-level
+ * class. It is the calling exception handler's responsibility to finally shut down the scenario
+ * cleanly and return appropriately. Thus, You should not throw errors from this class. You should only
+ * unwrap and explain errors, sending contents to the logfile as appropriate.
+ *
+ */
+public class ScenarioErrorHandler {
+
+ private final static Logger logger = LoggerFactory.getLogger(ScenarioErrorHandler.class);
+
+ public static void handle(String script, Throwable t, boolean wantsStackTraces) {
+ if (t instanceof ScriptException) {
+ handleScriptException(script, (ScriptException) t, wantsStackTraces);
+ } else if (t instanceof BasicError) {
+ handleBasicError((BasicError) t, wantsStackTraces);
+ } else if (t instanceof Exception){
+ handleInternalError((Exception) t, wantsStackTraces);
+ }
+ }
+
+ private static void handleInternalError(Exception e, boolean wantsStackTraces) {
+ String prefix = "internal error: ";
+ if (!e.getCause().getClass().getCanonicalName().contains("io.nosqlbench")) {
+ prefix = "Error from driver or included library: ";
+ }
+
+ if (wantsStackTraces) {
+ logger.error(prefix + e.getMessage(),e);
+ } else {
+ logger.error(e.getMessage());
+ logger.error("for the full stack trace, run with --show-stacktraces");
+ }
+ }
+
+ private static void handleScriptException(String script, ScriptException e, boolean wantsStackTraces) {
+ Throwable cause = e.getCause();
+ if (cause instanceof PolyglotException) {
+ Throwable hostException = ((PolyglotException) cause).asHostException();
+ if (hostException instanceof BasicError) {
+ handleBasicError((BasicError)hostException, wantsStackTraces);
+ } else {
+ handle(script,hostException, wantsStackTraces);
+ }
+ } else {
+ if (wantsStackTraces) {
+ logger.error("Unknown script exception:",e);
+ } else {
+ logger.error(e.getMessage());
+ logger.error("for the full stack trace, run with --show-stacktraces");
+ }
+ }
+ }
+
+ private static void handleBasicError(BasicError e, boolean wantsStackTraces) {
+ if (wantsStackTraces) {
+ logger.error(e.getMessage(),e);
+ } else {
+ logger.error(e.getMessage());
+ logger.error("for the full stack trace, run with --show-stacktraces");
+ }
+ }
+
+}
diff --git a/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java b/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java
index 95802df3f..3a09e05a6 100644
--- a/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java
+++ b/engine-core/src/main/java/io/nosqlbench/engine/core/script/Scenario.java
@@ -19,16 +19,12 @@ import com.codahale.metrics.MetricRegistry;
import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine;
import io.nosqlbench.engine.core.*;
import io.nosqlbench.engine.core.metrics.PolyglotMetricRegistryBindings;
-import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.engine.api.extensions.ScriptingPluginInfo;
import io.nosqlbench.engine.api.metrics.ActivityMetrics;
import io.nosqlbench.engine.core.metrics.NashornMetricRegistryBindings;
import io.nosqlbench.engine.api.scripting.ScriptEnvBuffer;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
-import org.graalvm.polyglot.Context;
-import org.graalvm.polyglot.EnvironmentAccess;
-import org.graalvm.polyglot.HostAccess;
-import org.graalvm.polyglot.PolyglotAccess;
+import org.graalvm.polyglot.*;
import org.slf4j.LoggerFactory;
import javax.script.*;
@@ -61,17 +57,19 @@ public class Scenario implements Callable {
private ScenarioLogger scenarioLogger;
private ScriptParams scenarioScriptParams;
private Engine engine = Engine.Graalvm;
+ private boolean wantsStackTraces=false;
public enum Engine {
Nashorn,
Graalvm
}
- public Scenario(String name, Engine engine, String progressInterval, boolean wantsGraaljsCompatMode) {
+ public Scenario(String name, Engine engine, String progressInterval, boolean wantsGraaljsCompatMode, boolean wantsStackTraces) {
this.name = name;
this.engine = engine;
this.progressInterval = progressInterval;
this.wantsGraaljsCompatMode = wantsGraaljsCompatMode;
+ this.wantsStackTraces = wantsStackTraces;
}
public Scenario(String name, Engine engine) {
@@ -218,28 +216,10 @@ public class Scenario implements Callable {
}
System.err.flush();
System.out.flush();
- } catch (ScriptException e) {
- String diagname = "diag_" + System.currentTimeMillis() + ".js";
- try {
- Path diagFilePath = Paths.get(scenarioLogger.getLogDir(), diagname);
- Files.writeString(diagFilePath, script);
- } catch (Exception ignored) {
- }
- String errorDesc = "Script error while running scenario:" + e.toString() + ", script content is at " + diagname;
- e.printStackTrace();
- logger.error(errorDesc, e);
- scenarioController.forceStopScenario(5000);
- throw new RuntimeException("Script error while running scenario:" + e.getMessage(), e);
- } catch (BasicError ue) {
- logger.error(ue.getMessage());
- scenarioController.forceStopScenario(5000);
- throw ue;
- } catch (Exception o) {
- String errorDesc = "Non-Script error while running scenario:" + o.getMessage();
- logger.error(errorDesc, o);
- scenarioController.forceStopScenario(5000);
- throw new RuntimeException("Non-Script error while running scenario:" + o.getMessage(), o);
+ } catch (Exception e) {
+ ScenarioErrorHandler.handle(script,e,wantsStackTraces);
} finally {
+ scenarioController.forceStopScenario(5000);
System.out.flush();
System.err.flush();
}