Experimental feature in GraalVM

使用 Insight 进行追踪

可以使用 GraalVM Insight 通过标准的 OpenTracing API 实现流畅、声明式、临时的跟踪。可以将跟踪添加到正在运行的应用程序中,并根据需要进行自定义,以提取调查任何错误行为事件所需的信息。

以下示例将展示 GraalVM Insight 的跟踪功能。首先,安装 Jaeger 的 Node.js 客户端侧仪器库

./bin/npm install jaeger-client@3.17.1

现在可以使用 OpenTracing API(由 jaeger-client 模块提供)在你的仪器 agent.js 中通过 tracer 对象进行操作(在它可用后,将在本指南的后面部分讨论)

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.jsemit 函数的 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: 'https://#: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);

有了这两个文件,就可以启动 node 应用程序以及代理。但首先,启动 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

现在可以连接到 Jaeger UI(可通过 https://#:16686/ 访问),并对服务器进行一些负载测试

ab -c 10 -n 10000 https://#:8080/

服务器在处理请求时会在控制台中打印详细信息,而 Jaeger UI 会显示跟踪信息

Jaeger UI

本指南介绍了如何使用跟踪来增强普通的 Node.js 应用程序。跟踪信息保存在自己的 agent.js 文件中,可以在启动时(此处演示)或在需要时 动态 应用。

要了解有关 Insight 的更多信息,并找到一些有挑战性的任务,请访问 Insight 手册

联系我们