本文介绍通过opentelemetry-js SDK将NodeJS应用的Trace数据接入到日志服务的操作步骤。

前提条件

  • 已创建Trace实例。更多信息,请参见创建Trace实例
  • 已安装NodeJS v8.5.0及以上版本的开发环境。

(推荐)方案一:半自动接入

NodeJS支持在http、https、grpc、express、mysql、mongodb、redis等框架中通过引入依赖包的方式自动上传Trace数据。详细的框架列表请参见opentelemetry-node-js-contrib。此处以express为例,介绍半自动接入方案。更多示例请参见examples

  1. 安装依赖包。
    npm install --save @opentelemetry/api
    npm install --save @opentelemetry/node
    npm install --save @opentelemetry/tracing
    npm install --save @opentelemetry/exporter-collector-grpc
    npm install --save @opentelemetry/instrumentation
    npm install --save @opentelemetry/plugin-http
    npm install --save @opentelemetry/plugin-express
  2. 初始化Tracer并启动express。

    如下代码中的变量需根据实际情况替换。关于变量的详细说明,请参见表 1

    const opentelemetry = require('@opentelemetry/api');
    const {BatchSpanProcessor, ConsoleSpanExporter} = require('@opentelemetry/tracing');
    const { NodeTracerProvider } = require('@opentelemetry/node');
    const { CollectorTraceExporter } =  require('@opentelemetry/exporter-collector-grpc');
    const ExpressLayerType = require('@opentelemetry/plugin-express')
    const grpc = require('grpc');
    
    var os = require("os");
    var hostname = os.hostname();
    
    class AttributeSpanProcessor {
      onStart(span, _context) {
        span.setAttribute("host.name", hostname);
        span.setAttribute("service.version", "${version}");
      }
      onEnd(_span) {}
      shutdown() {
        return Promise.resolve();
      }
      forceFlush() {
        return Promise.resolve();
      }
    }
    
    var url = "${endpoint}"
    
    var logStdout = false
    if (url == "stdout") {
      logStdout = true
    }
    var meta = new grpc.Metadata();
    meta.add('x-sls-otel-project', '${project}');
    meta.add('x-sls-otel-instance-id', '${instance}');
    meta.add('x-sls-otel-ak-id', '${access-key-id}');
    meta.add('x-sls-otel-ak-secret', '${access-key-secret}');
    const collectorOptions = {
      serviceName: "${service}",
      url: url,
      credentials: grpc.credentials.createSsl(),
      metadata: meta
    };
    
    const exporter = new CollectorTraceExporter(collectorOptions);
    const provider = new NodeTracerProvider({
      plugins: {
        http: {
          enabled: true,
          path: '@opentelemetry/plugin-http',
          ignoreIncomingPaths: [new RegExp('.*(png|html)')],
        },
        express: {
          enabled: true,
          // You may use a package name or absolute path to the file.
          path: '@opentelemetry/plugin-express',
          ignoreLayers: [new RegExp('middleware.*')],
          ignoreLayersType: [ExpressLayerType.MIDDLEWARE],
        },
      }
    });
    
    if (!logStdout) {
      provider.addSpanProcessor(new AttributeSpanProcessor())
      provider.addSpanProcessor(new BatchSpanProcessor(exporter));
    } else {
      provider.addSpanProcessor(new AttributeSpanProcessor())
      var stdexporter = new ConsoleSpanExporter();
      provider.addSpanProcessor(new BatchSpanProcessor(stdexporter));
    }
    provider.register();
    var tracer = opentelemetry.trace.getTracer("front-end");
    
    
    var express = require('express');
    var app = express()
    
    app.get('/hello', function (req, res, next) {
      res.send("success");
    });
    
    var server = app.listen(8079, function () {
      var port = server.address().port;
      console.log("App now running in %s mode on port %d", app.get("env"), port);
    });
    表 1. 变量说明
    变量 说明 示例
    ${endpoint} 接入地址,格式为${project}.${region-endpoint}:Port,其中:
    • ${project}:日志服务Project名称。
    • ${region-endpoint}:Project访问域名,支持公网和阿里云内网(经典网络、VPC)。更多信息,请参见服务入口
    • Port:网络端口,固定为10010。
    test-project.cn-hangzhou.log.aliyuncs.com:10010
    ${project} 日志服务Project名称。 test-project
    ${instance} Trace服务实例名称。 test-traces
    ${access-key-id} 阿里云账号AccessKey ID。

    建议您使用只具备日志服务Project写入权限的RAM用户的AccessKey(包括AccessKey ID和AccessKey Secret)。授予RAM用户向指定Project写入数据权限的具体操作,请参见授权。如何获取AccessKey的具体操作,请参见访问密钥

    ${access-key-secret} 阿里云账号AccessKey Secret。

    建议您使用只具备日志服务Project写入权限的RAM用户的AccessKey。

    ${service} 服务名。根据您的实际场景取值即可。 payment
    ${version} 服务版本号。建议按照va.b.c格式定义。 v0.1.2
  3. 访问服务,触发Trace数据生成并发送。
    127.0.0.1:8079/hello

方案二:手动构造Trace数据并发送

如果您使用的是自建框架或有其他需求,可以手动构造Trace数据并发送到日志服务。更多信息,请参见opentelemetry-js

  1. 安装依赖包。
    npm install --save @opentelemetry/api
    npm install --save @opentelemetry/node
    npm install --save @opentelemetry/tracing
    npm install --save @opentelemetry/exporter-collector-grpc
  2. 初始化Tracer并启动express。

    如下代码中的变量需根据实际情况替换。更多信息,请参见表 1

    const opentelemetry = require('@opentelemetry/api');
    const {BasicTracerProvider, BatchSpanProcessor, ConsoleSpanExporter} = require('@opentelemetry/tracing');
    const { CollectorTraceExporter } =  require('@opentelemetry/exporter-collector-grpc');
    const grpc = require('grpc');
    
    var os = require("os");
    var hostname = os.hostname();
    
    class AttributeSpanProcessor {
      onStart(span, _context) {
        span.setAttribute("host.name", hostname);
        span.setAttribute("service.version", "${version}");
      }
      onEnd(_span) {}
      shutdown() {
        return Promise.resolve();
      }
      forceFlush() {
        return Promise.resolve();
      }
    }
    
    var url = "${endpoint}"
    
    var logStdout = false
    if (url == "stdout") {
      logStdout = true
    }
    var meta = new grpc.Metadata();
    meta.add('x-sls-otel-project', '${project}');
    meta.add('x-sls-otel-instance-id', '${instance}');
    meta.add('x-sls-otel-ak-id', '${access-key-id}');
    meta.add('x-sls-otel-ak-secret', '${access-key-secret}');
    const collectorOptions = {
      serviceName: "${service}",
      url: url, // url is optional and can be omitted - default is localhost:4317
      credentials: grpc.credentials.createSsl(),
      metadata: meta
    };
    
    const exporter = new CollectorTraceExporter(collectorOptions);
    const provider = new BasicTracerProvider();
    
    if (!logStdout) {
      provider.addSpanProcessor(new AttributeSpanProcessor())
      provider.addSpanProcessor(new BatchSpanProcessor(exporter));
    } else {
      provider.addSpanProcessor(new AttributeSpanProcessor())
      var stdexporter = new ConsoleSpanExporter();
      provider.addSpanProcessor(new BatchSpanProcessor(stdexporter));
    }
    provider.register();
    var tracer = opentelemetry.trace.getTracer("front-end");
    
    var express = require('express');
    
    var app = express()
    
    app.get('/hello', function (req, res, next) {
        const span = tracer.startSpan('hello');
        span.setAttribute('name', 'toma');
        span.setAttribute('age', '26');
        span.addEvent('invoking doWork');
    
        res.send("success");
    
        span.end();
    });
    
    var server = app.listen(8079, function () {
      var port = server.address().port;
      console.log("App now running in %s mode on port %d", app.get("env"), port);
    });
  3. 访问服务,触发Trace数据生成并发送。
    127.0.0.1:8079/hello

后续步骤