Skip to content

Commit df7a57a

Browse files
authored
[jsscripting] Improve logging on JS error (openhab#16445)
* [jsscripting] Improve script error logging * [jsscripting] Suppress some warnings * [jsscripting] Throw ISE instead of RE * [jsscripting] Minor null annotation improvements Include fileName or ruleUID or transformation UID in the logger name used by the logged error stack trace. Signed-off-by: Florian Hotze <[email protected]>
1 parent c9f8324 commit df7a57a

File tree

2 files changed

+44
-12
lines changed

2 files changed

+44
-12
lines changed

bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/DebuggingGraalScriptEngine.java

+35-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import javax.script.Invocable;
1616
import javax.script.ScriptEngine;
1717

18+
import org.eclipse.jdt.annotation.Nullable;
1819
import org.graalvm.polyglot.PolyglotException;
1920
import org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable;
2021
import org.slf4j.Logger;
@@ -28,22 +29,52 @@
2829
class DebuggingGraalScriptEngine<T extends ScriptEngine & Invocable & AutoCloseable>
2930
extends InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable<T> {
3031

31-
private static final Logger STACK_LOGGER = LoggerFactory
32-
.getLogger("org.openhab.automation.script.javascript.stack");
32+
private static final String SCRIPT_TRANSFORMATION_ENGINE_IDENTIFIER = "openhab-transformation-script-";
33+
34+
private @Nullable Logger logger;
3335

3436
public DebuggingGraalScriptEngine(T delegate) {
3537
super(delegate);
3638
}
3739

3840
@Override
3941
public Exception afterThrowsInvocation(Exception e) {
42+
if (logger == null) {
43+
initializeLogger();
44+
}
45+
4046
Throwable cause = e.getCause();
4147
if (cause instanceof IllegalArgumentException) {
42-
STACK_LOGGER.error("Failed to execute script:", e);
48+
logger.error("Failed to execute script:", e);
4349
}
4450
if (cause instanceof PolyglotException) {
45-
STACK_LOGGER.error("Failed to execute script:", cause);
51+
logger.error("Failed to execute script:", cause);
4652
}
4753
return e;
4854
}
55+
56+
/**
57+
* Initializes the logger.
58+
* This cannot be done on script engine creation because the context variables are not yet initialized.
59+
* Therefore, the logger needs to be initialized on the first use after script engine creation.
60+
*/
61+
private void initializeLogger() {
62+
Object fileName = delegate.getContext().getAttribute("javax.script.filename");
63+
Object ruleUID = delegate.getContext().getAttribute("ruleUID");
64+
Object ohEngineIdentifier = delegate.getContext().getAttribute("oh.engine-identifier");
65+
66+
String identifier = "stack";
67+
if (fileName != null) {
68+
identifier = fileName.toString().replaceAll("^.*[/\\\\]", "");
69+
} else if (ruleUID != null) {
70+
identifier = ruleUID.toString();
71+
} else if (ohEngineIdentifier != null) {
72+
if (ohEngineIdentifier.toString().startsWith(SCRIPT_TRANSFORMATION_ENGINE_IDENTIFIER)) {
73+
identifier = ohEngineIdentifier.toString().replaceAll(SCRIPT_TRANSFORMATION_ENGINE_IDENTIFIER,
74+
"transformation.");
75+
}
76+
}
77+
78+
logger = LoggerFactory.getLogger("org.openhab.automation.script.javascript." + identifier);
79+
}
4980
}

bundles/org.openhab.automation.jsscripting/src/main/java/org/openhab/automation/jsscripting/internal/OpenhabGraalJSScriptEngine.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -72,24 +72,24 @@ public class OpenhabGraalJSScriptEngine
7272
extends InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable<GraalJSScriptEngine> {
7373

7474
private static final Logger LOGGER = LoggerFactory.getLogger(OpenhabGraalJSScriptEngine.class);
75-
private static Source GLOBAL_SOURCE;
75+
private static final Source GLOBAL_SOURCE;
7676
static {
7777
try {
7878
GLOBAL_SOURCE = Source.newBuilder("js", getFileAsReader("node_modules/@jsscripting-globals.js"),
7979
"@jsscripting-globals.js").cached(true).build();
8080
} catch (IOException e) {
81-
throw new RuntimeException("Failed to load @jsscripting-globals.js", e);
81+
throw new IllegalStateException("Failed to load @jsscripting-globals.js", e);
8282
}
8383
}
8484

85-
private static Source OPENHAB_JS_SOURCE;
85+
private static final Source OPENHAB_JS_SOURCE;
8686
static {
8787
try {
8888
OPENHAB_JS_SOURCE = Source
8989
.newBuilder("js", getFileAsReader("node_modules/@openhab-globals.js"), "@openhab-globals.js")
9090
.cached(true).build();
9191
} catch (IOException e) {
92-
throw new RuntimeException("Failed to load @openhab-globals.js", e);
92+
throw new IllegalStateException("Failed to load @openhab-globals.js", e);
9393
}
9494
}
9595
private static final String OPENHAB_JS_INJECTION_CODE = "Object.assign(this, require('openhab'));";
@@ -134,7 +134,7 @@ public class OpenhabGraalJSScriptEngine
134134
private final JSRuntimeFeatures jsRuntimeFeatures;
135135

136136
// these fields start as null because they are populated on first use
137-
private String engineIdentifier;
137+
private @Nullable String engineIdentifier;
138138
private @Nullable Consumer<String> scriptDependencyListener;
139139

140140
private boolean initialized = false;
@@ -239,10 +239,11 @@ protected void beforeInvocation() {
239239
}
240240

241241
// these are added post-construction, so we need to fetch them late
242-
this.engineIdentifier = (String) ctx.getAttribute(CONTEXT_KEY_ENGINE_IDENTIFIER);
243-
if (this.engineIdentifier == null) {
242+
String localEngineIdentifier = (String) ctx.getAttribute(CONTEXT_KEY_ENGINE_IDENTIFIER);
243+
if (localEngineIdentifier == null) {
244244
throw new IllegalStateException("Failed to retrieve engine identifier from engine bindings");
245245
}
246+
engineIdentifier = localEngineIdentifier;
246247

247248
ScriptExtensionAccessor scriptExtensionAccessor = (ScriptExtensionAccessor) ctx
248249
.getAttribute(CONTEXT_KEY_EXTENSION_ACCESSOR);
@@ -262,7 +263,7 @@ protected void beforeInvocation() {
262263

263264
// Wrap the "require" function to also allow loading modules from the ScriptExtensionModuleProvider
264265
Function<Function<Object[], Object>, Function<String, Object>> wrapRequireFn = originalRequireFn -> moduleName -> scriptExtensionModuleProvider
265-
.locatorFor(delegate.getPolyglotContext(), engineIdentifier).locateModule(moduleName)
266+
.locatorFor(delegate.getPolyglotContext(), localEngineIdentifier).locateModule(moduleName)
266267
.map(m -> (Object) m).orElseGet(() -> originalRequireFn.apply(new Object[] { moduleName }));
267268
delegate.getBindings(ScriptContext.ENGINE_SCOPE).put(REQUIRE_WRAPPER_NAME, wrapRequireFn);
268269
delegate.put("require", wrapRequireFn.apply((Function<Object[], Object>) delegate.get("require")));

0 commit comments

Comments
 (0)