JavaScript Execution Environment Remote Debugging

 

Smile 2022.05 introduced support for JavaScript remote debugging via a Chrome browser.

Remote JavaScript debugging is enabled for a module in the "JavaScript Execution Environment" section of the module configuration. After enabling debug on the module, when you restart the module, if the module has any javascript callbacks configured, you will see a message in the logs that looks something like this:

Smile CDR JavaScript debugging enabled.  Please copy-paste the following URL into a Chrome browser to continue startup: devtools://devtools/bundled/inspector.html?v8only=true&experiments=true&ws=localhost:9930/018b9c18-5efa-4163-b40d-a4b0b56bb4b3

The JavaScript Execution Environment presents itself to debug clients as a Node.js target, so this URL uses Chrome's inspector.html debugger front end.

Alternative Front End

Earlier Smile CDR releases logged Chrome's js_app.html front end instead.

Both front ends debug the same target, but if js_app.html opens a blank page with no source code, keep the ws= portion of the logged URL exactly as it appears and substitute the older front end:

devtools://devtools/bundled/js_app.html?ws=localhost:9930/018b9c18-5efa-4163-b40d-a4b0b56bb4b3

The module will pause until you click the "Resume script execution" button, the blue arrow on the top-left of this image:

Debug Buttons

From here, you can set breakpoints, examine variables, step into functions, and any other typical debugging activity.

Configuration

Debug Host Address and Port control the address and port that the JavaScript Execution Environment binds its debug listener to, and Secure controls whether that listener uses TLS.

The default host address is localhost, which binds the loopback interface only, so the debugger can be reached only from the machine running Smile CDR.

Setting a host address that is reachable from the network — including the wildcard address 0.0.0.0, which binds every interface — makes the debugger reachable from every host that can route to that port. See Debugging a Containerized Deployment below for the one case where a wildcard bind is expected.

If Suspend is set to "No", then the log message with the URL will still be written to the log, but the module will not pause and wait for the debug client to connect. The debug client can connect any time after the log message appears.

If no Path is set, then the server will create a new random UUID every time the server restarts. You can override this and set the path what you want it to be. E.g. if you set the path to mysecretpath then the URL you need to connect to will look like:

Smile CDR JavaScript debugging enabled.  Please copy-paste the following URL into a Chrome browser to continue startup: devtools://devtools/bundled/inspector.html?v8only=true&experiments=true&ws=localhost:9930/mysecretpath

Setting the path can be useful if you are frequently restarting your module so your chrome debugger can reconnect to the same url after every restart.

However, keep in mind that anyone with access to that port will be able to connect to this debug URL and potentially gain access to the system via the JavaScript execution environment; so we recommend if you set the Path that you choose a name that is difficult to guess.

Debugging a Containerized Deployment

A listener bound to localhost inside a container cannot be reached from outside that container. Traffic published with docker run -p arrives on the container's network interface rather than its loopback interface, so a debug client running on the host is refused.

To debug JavaScript in a containerized Smile CDR, set Debug Host Address to the wildcard address 0.0.0.0 so that the listener also accepts connections arriving on the container's network interface.

Because 0.0.0.0 binds every interface inside the container, publish the debug port bound to loopback on the host so that only the host itself can reach the debugger:

docker run -p 127.0.0.1:9930:9930 ...

Publishing the port as -p 9930:9930 instead binds it on every interface of the host, which leaves the debugger reachable from anywhere that can route to the host.

When Debug Host Address is set to 0.0.0.0, the URL written to the log contains 0.0.0.0 rather than a hostname a browser can connect to:

Smile CDR JavaScript debugging enabled.  Please copy-paste the following URL into a Chrome browser to continue startup: devtools://devtools/bundled/inspector.html?v8only=true&experiments=true&ws=0.0.0.0:9930/mysecretpath

Replace 0.0.0.0 with the address on which you published the port — localhost in the docker run example above — before pasting the URL into Chrome.

Troubleshooting

If the debug URL does not open a working debugger, confirm that the debug listener is actually running.

The listener answers the standard Chrome DevTools discovery endpoints, so a request to /json/list on the debug port reports the target it has registered:

curl -s http://localhost:9930/json/list

A JSON array describing a GraalVM target means the listener is running and the problem lies with the debug client.

An empty response or a refused connection means nothing is listening; check the following:

  • The module creates its debug listener the first time a JavaScript callback runs, so the listener may not exist until the module has handled one request that invokes the target script.
  • If the configured port is already in use, the module logs the debug URL and then reports a BindException, and continues to run without a debugger. Search the log for BindException to rule this out.
  • Secure changes the endpoint to HTTPS, which the chrome://inspect page cannot use. Leave Secure set to "No" while debugging.