Skip to content

Latest commit

 

History

History
106 lines (85 loc) · 4.21 KB

Insight-Embedding.md

File metadata and controls

106 lines (85 loc) · 4.21 KB

GraalVM Insight: Embedding

GraalVM Insight is a multipurpose, flexible tool providing enourmous possiblilities when it comes to dynamic understanding of user application behavior. See its manual for more details. Read on to learn how to embed Insight into your own application.

Embedding Insight into Java Application

GraalVM languages can be embedded into custom Java applications via polyglot Context API. Insight isn't an exception and it can also be controlled via the same API as well. See formal Insight documentation for more details:

final Engine engine = context.getEngine();
Instrument instrument = engine.getInstruments().get("insight");
Function<Source, AutoCloseable> access = instrument.lookup(Function.class);
AutoCloseable handle = access.apply(agentSrc);

Obtain Engine for your Context and ask for insight instrument. Then create Source with your Insight script and apply it while obtaining its instrumentation handle. Use handle.close() to disable all the script's instrumentations when when no longer needed.

Ignoring Internal Scripts

Often one wants to treat certain code written in a dynamic language as a priviledged one - imagine various bindings to OS concepts or other features of one's application. Such scripts are better to remain blackboxed and hidden from Insight instrumentation capabilities.

To hide priviledged scripts from Insight sight mark such scripts as internal. By default Insight ignores and doesn't process internal scripts.

Embedding Insight into node.js Application

The Insight hacker's manual shows many examples of using Insight with node - however most of them rely on the command line option --insight and don't benefit from the dynamic nature of Insight much. Let's fix that by showing how to create an admin server. Define adminserver.js:

function initialize(insight, require) {
    const http = require("http");
    const srv = http.createServer((req, res) => {
        let method = req.method;
        if (method === 'POST') {
            var data = '';
            req.on('data', (chunk) => {
                data += chunk.toString();
            });
            req.on('end', () => {
                const fn = new Function('insight', data);
                try {
                    fn(insight);
                    res.write('GraalVM Insight hook activated\n');
                } finally {
                    res.end();
                }
            });
        }
    });
    srv.listen(9999, () => console.log("Admin ready at 9999"));
}


let waitForRequire = function (event) {
  if (typeof process === 'object' && process.mainModule && process.mainModule.require) {
    insight.off('source', waitForRequire);
    initialize(insight, process.mainModule.require.bind(process.mainModule));
  }
};

insight.on('source', waitForRequire, { roots: true });

which opens an HTTP server at port 9999 and listens for incoming scripts to be applied any time later. Invoke your application as

$ node --insight=adminserver.js --experimental-options yourapp.js
Admin ready at 9999

and while it is running connect to the admin port. Send in any Insight script you want. For example following script is going to observe who calls process.exit:

$ curl --data \
  'insight.on("enter", (ctx, frame) => { console.log(new Error("call to exit").stack); }, \
  { roots: true, rootNameFilter: "exit" });' \
  -X POST http://localhost:9999/

When writing your own adminserver.js pay attention to security. Insight scripts are very powerful and you want only authorized persons to apply arbitrary hooks to your application. Don't open the admin server port to everybody.

Where next?

Read about more Insight use-cases in its hacker's manual.