Experimental feature in GraalVM

以洞察力追蹤

可以透過標準 OpenTracing API 使用 GraalVM Insight 實作平滑、宣告式、隨選追蹤。追蹤可以新增到執行中的應用程式中,並可以即時自訂以提取調查任何錯誤事件所需的正確資訊。

以下範例將示範使用 GraalVM Insight 的追蹤功能。首先,安裝適用於 Node.js 的 Jaeger 用戶端檢測程式庫

./bin/npm install jaeger-client@3.17.1

現在您可以使用 jaeger-client 模組提供的 OpenTracing API,透過 tracer 物件在您的檢測 agent.js 中進行操作 (一旦它可用,稍後將在本指南中討論)

let initialize = function(tracer) {
    var counter = 0;

    insight.on('enter', function(ctx, frame) {
        const args = frame.args;
        if ('request' !== frame.type || args.length !== 2 || typeof args[0] !== 'object' || typeof args[1] !== 'object') {
            return;
        }
        const req = args[0];
        const res = args[1];
        const span = tracer.startSpan("request");
        span.setTag("span.kind", "server");
        span.setTag("http.url", req.url);
        span.setTag("http.method", req.method);
        res.id = ++counter;
        res.span = span;
        console.log(`agent: handling #${res.id} request for ${req.url}`);
    }, {
        roots: true,
        rootNameFilter: 'emit',
        at: {
            sourcePath: '.*events.js'
        }
    });

    insight.on('return', function(ctx, frame) {
        var res = frame['this'];
        if (res.span) {
            res.span.finish();
            console.log(`agent: finished #${res.id} request`);
        } else {
            //Caused, for example, by Tracer itself connecting to the Jaeger server
        }
    }, {
        roots: true,
        rootNameFilter: 'end',
        at: {
            sourcePath: '.*_http_outgoing.js'
        }
    });
    console.log('agent: ready');
};

系統會掛鉤到 emit('request', ...)res.end() 函式,這些函式用於初始化對 HTTP 請求的回應並完成它。由於 res 物件是一個動態 JavaScript 物件,因此可以在 events.js 來源的 emit 函式的 enter 處理程式中將 idspan 屬性新增到其中。然後可以在 end 函式的 return 處理程式中使用這些屬性。

GraalVM Insight 提供對 frame 變數及其欄位的存取權。因此,檢測可以讀取 req.urlreq.method 的值,並將它們作為 span.setTag 值提供給 OpenTracing 伺服器。

使用此檢測,只需能夠在適當的時間啟用它即可。查看將 Insight 嵌入 Node.js 應用程式章節,了解如何建立管理伺服器並在需要時動態套用任何追蹤指令碼 (包括基於 OpenTracing 的指令碼)。就本指南而言,將使用更簡單的方法。

當提供 jaeger 物件時啟用檢測

let initializeJaeger = function (ctx, frame) {
    insight.off('enter', initializeJaeger);

    let jaeger = frame.jaeger;

    var initTracer = jaeger.initTracer;
    console.log('agent: Jaeger tracer obtained');

    // See schema https://github.com/jaegertracing/jaeger-client-node/blob/master/src/configuration.js#L37
    var config = {
      serviceName: 'insight-demo',
      reporter: {
        // Provide the traces endpoint. This forces the client to connect directly to the Collector and send
        // spans over HTTP
        collectorEndpoint: 'http://localhost:14268/api/traces',
        // Provide username and password if authentication is enabled in the Collector
        // username: '',
        // password: '',
      },
      sampler: {
          type : 'const',
          param : 1
      }
    };
    var options = {
      tags: {
        'insight-demo.version': '1.1.2',
      },
    //  metrics: metrics,
      logger: console,
      sampler: {
          type : 'const',
          param : 1
      }
    };

    var tracer = initTracer(config, options);
    initialize(tracer);
};

insight.on('return', initializeJaeger, {
  roots: true,
  rootNameFilter: 'jaegerAvailable'
});

此檢測需要主伺服器指令碼的協助。讓 server.js 取得 jaeger-client 模組,並透過 jaegerAvailable 函式將其傳遞給代理程式。然後它會建立一個典型的 HTTP 伺服器。server.js 的內容為

function jaegerAvailable(jaeger) {
    console.log("Providing Jaeger object to the agent");
}
jaegerAvailable(require("jaeger-client"));

const http = require("http");
const srv = http.createServer((req, res) => {
    console.log(`server: obtained request ${res.id}`);
    setTimeout(() => {
        res.write(`OK# ${res.id}`);
        console.log(`server: replied to request ${res.id}`);
        res.end();
    }, 5);
});
srv.listen(8080);

有了這兩個檔案,您可以啟動節點應用程式以及代理程式。但是,首先,啟動 Jaeger 伺服器

docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
-p 5775:5775/udp   -p 6831:6831/udp   -p 6832:6832/udp \
-p 5778:5778   -p 16686:16686   -p 14268:14268   -p 9411:9411 \
jaegertracing/all-in-one:latest

./bin/node --insight=agent.js server.js
Providing Jaeger object to the agent
agent: Jaeger tracer obtained
Initializing Jaeger Tracer with RemoteReporter and ConstSampler(always)
agent: ready

現在您可以連線到 http://localhost:16686/ 上可用的 Jaeger UI,並讓伺服器承載一些負載

ab -c 10 -n 10000 http://localhost:8080/

伺服器會在處理請求時將詳細資訊列印到主控台,而 Jaeger UI 則會填滿追蹤

Jaeger UI

這就完成了如何使用追蹤增強一般 Node.js 應用程式的指南。追蹤會保留在其自身的 agent.js 檔案中,並且可以在啟動時 (此處示範) 或在需要時動態套用。

若要進一步了解 Insight 並尋找一些具有挑戰性的任務,請前往Insight 手冊

與我們聯繫