Experimental feature in GraalVM

アプリケーションへのInsightの埋め込み

JavaへのInsightの埋め込み #

Graal言語(Truffleフレームワークで実装された言語、たとえばJavaScript、Python、Ruby、Rなど)は、Polyglot Context APIを介してカスタムJavaアプリケーションに埋め込むことができます。 GraalVM Insightも同じAPIで制御できます。次のようにします。

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

ContextEngineを取得し、insightインストゥルメントを要求します。

次に、GraalVM Insightスクリプトを使用して`Source`を作成し、インストゥルメンテーションハンドルを取得しながら適用します。 不要になったら、`handle.close()`を使用してスクリプトのすべてのインストゥルメンテーションを無効にします。 例: ```java Source instrument = Source.create("js", """ insight.on('return', function(ctx, frame) { console.log(`Instrumented where = ${frame.where}`); }, { roots: true, rootNameFilter: 'end', }); """); Source script = Source.create("js", """ function end() { var where = 'end'; console.log(where + ' invoked') } end(); """); try (Context context = Context.newBuilder().build()) { @SuppressWarnings("unchecked") Function<Source, AutoCloseable> insight = context.getEngine().getInstruments().get("insight").lookup(Function.class); // インストゥルメンテーションなしで実行 context.eval(script); // インストゥルメンテーションを使用して実行 try (AutoCloseable handle = insight.apply(instrument)) { context.eval(script); } // インストゥルメンテーションなしで実行 context.eval(script); } ``` [埋め込み依存関係の設定](/latest/reference-manual/embed-languages/#dependency-setup)を参照してください。 `insight`への依存関係を追加します: ``` org.graalvm.polyglot insight 23.1.1 pom ``` ### 内部スクリプトの無視 特権的なコードとして、動的言語で記述された特定のコードを扱うことがよくあります。 OSの概念やアプリケーションのその他の機能へのさまざまなバインディングを想像してみてください。 このようなスクリプトは、ブラックボックス化してGraalVM Insightのインストゥルメンテーション機能から隠しておく方が適切です。 特権スクリプトを非表示にするには、[内部としてマークします](https://graalvm.dokyumento.jp/sdk/javadoc/org/graalvm/polyglot/Source.Builder.html#internal-boolean-)。 デフォルトでは、GraalVM Insightは内部スクリプトを無視して処理しません。 ### Insightスクリプトの機能の拡張 GraalVM InsightをJavaアプリケーションに埋め込む場合、評価されているInsightスクリプトで追加のオブジェクトを使用できるようにすることができます。 例: ```java @TruffleInstrument.Registration( id = "meaningOfWorld", name = "世界の意義", version = "demo", services = { Insight.SymbolProvider.class } ) public final class MeaningOfWorldInstrument extends TruffleInstrument { @Override protected void onCreate(Env env) { Map<String, Integer> symbols = Collections.singletonMap("meaning", 42); Insight.SymbolProvider provider = () -> symbols; env.registerService(provider); } } ``` 前述のJavaコードは、評価されるすべてのInsightスクリプトに新しいシンボル`meaning`を登録するインストゥルメントを作成します。 各スクリプトはそれを参照して使用できます。たとえば、メソッド呼び出しの数を制限するために使用できます。 ```java insight.on('enter', (ctx, frames) => { if (--meaning <= 0) throw 'Stop!' }, { roots : true }); ``` 単純な値と複雑なオブジェクトの両方を公開できます。 詳細については、[javadoc](https://graalvm.dokyumento.jp/tools/javadoc/org/graalvm/tools/insight/Insight.SymbolProvider.html)を参照してください。 インストゥルメンテーションは、プログラム実行の多くの側面を変更する可能性があり、セキュリティサンドボックスの対象ではありません。 ## Node.jsへのInsightの埋め込み [Insightマニュアル](/latest/tools/graalvm-insight/manual/)には、`node`でGraalVM Insightを使用する多くの例が示されています。 ただし、それらのほとんどはコマンドラインオプション`--insight`に依存しており、ツールの動的な性質の利点がありません。 次の例は、管理サーバーを作成する方法を示しています。 このコードを`adminserver.js`に保存します。 ```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フックがアクティブになりました\n'); } finally { res.end(); } }); } }); srv.listen(9999, () => console.log("管理者は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 }); ``` プログラムはポート`9999`でHTTPサーバーを開き、後で適用される受信スクリプトをリッスンします。 アプリケーションを起動します。 ```bash node --insight=adminserver.js yourapp.js 管理者は9999で準備完了 ``` 実行中に、管理ポートに接続します。 GraalVM Insightスクリプトを送信します。 たとえば、次のスクリプトは、`process.exit`を誰が呼び出すかを観察します。 ```bash curl --data \ 'insight.on("enter", (ctx, frame) => { console.log(new Error("exitの呼び出し").stack); }, \ { roots: true, rootNameFilter: "exit" });' \ -X POST http://localhost:9999/ ``` 独自の`adminserver.js`を作成するときは、セキュリティに注意してください。 許可されたユーザーのみがアプリケーションに任意のフックを適用する必要があります。 管理サーバーポートを全員に開放しないでください。 ### 次に読むもの Insightの詳細とユースケースについては、[Insightマニュアル](/latest/tools/graalvm-insight/manual/)を参照してください。 必須の_HelloWorld_の例から始まり、より難しいタスクを示します。

お問い合わせ