通过OpenTelemetry为应用埋点并上报链路数据至云监控2.0后,云监控2.0即可开始监控应用,您可以查看应用拓扑、调用链路、异常事务、慢事务和SQL分析等一系列监控数据。本文介绍如何使用OpenTelemetry对Node.js Express应用进行自动或手动埋点并上报数据。
前提条件
支持的运行时环境:
OpenTelemetry 目前支持 Node.js v18 及以上版本。注意,仅支持 Node.js 的 Active(活跃)或 Maintenance LTS(长期维护)版本。虽然更早的 Node 版本可能可以工作,但它们未经过 OpenTelemetry 官方测试,因此不保证能够正常运行。
更多版本兼容性问题,请查看 Supported Runtimes。
支持的库和框架:许多流行的 Node.js 库都支持自动埋点。完整列表请参见Supported instrumentations。
步骤一:获取接入点信息
登录云监控2.0控制台,选择目标工作空间,在左侧导航栏选择 。
在服务端应用区域单击Node.js卡片,然后选择接入协议类型为Opentelemetry。
在参数配置区域单击LicenseKey右侧的点击获取,然后根据需求选择埋点方式、连接方式、上报方式,并输入应用名称、版本号和部署环境。
页面下方将会根据配置参数生成相应的接入代码,代码中包含了Endpoint、LicenseKey等接入点信息。
设置依赖库
自动埋点(推荐)
安装依赖包。
@opentelemetry/api 和 @opentelemetry/auto-instrumentations-node 包用于提供 API、SDK 和插桩工具。
npm install --save @opentelemetry/api npm install --save @opentelemetry/auto-instrumentations-node
配置以下环境变量,然后启动应用程序。
HTTP上报
将步骤一获取到的接入点信息替换到以下代码中。
export OTEL_SERVICE_NAME=<service name> export OTEL_RESOURCE_ATTRIBUTES=service.name=<service name>,acs.cms.workspace=<workspace>,service.version=<service version>,deployment.environment=<environment> export OTEL_TRACES_EXPORTER=otlp export OTEL_LOGS_EXPORTER=none export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=<traces.endpoint> export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=<metrics.endpoint> export OTEL_EXPORTER_OTLP_HEADERS="x-arms-license-key=<license-key>,x-arms-project=<arms-project>,x-cms-workspace=<workspace>" export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register" node app.js
gRPC上报
将步骤一获取到的接入点信息替换到以下代码中。
export OTEL_SERVICE_NAME=<service name> export OTEL_RESOURCE_ATTRIBUTES=service.name=<service name>,acs.cms.workspace=<workspace>,service.version=<service version>,deployment.environment=<environment> export OTEL_TRACES_EXPORTER=otlp export OTEL_LOGS_EXPORTER=none export OTEL_EXPORTER_OTLP_ENDPOINT=<endpoint> export OTEL_EXPORTER_OTLP_HEADERS="<license-key>,x-arms-project=<arms-project>,x-cms-workspace=<workspace>" export OTEL_EXPORTER_OTLP_PROTOCOL=grpc export OTEL_NODE_RESOURCE_DETECTORS="env,host,os" export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register" node app.js
说明如要添加更多 OpenTelemetry 环境变量,请查看OpenTelemetry Node.js 自动埋点配置。
手动埋点
(可选)创建示例应用程序。
这一步将演示如何构建一个简单的 Web 应用程序。如果您已经有编写好的 Node.js 应用程序,这一步可跳过。
新建一个项目目录,在目录下执行以下命令创建一个空的 package.json 文件。
npm init -y
安装依赖包。
npm install express
编写应用代码,创建一个名为 app.js 的文件,添加以下内容。
这段代码模拟扔骰子游戏,返回1-6之间的一个随机数。
/*app.js*/ const express = require('express'); const PORT = parseInt(process.env.PORT || '8080'); const app = express(); function getRandomNumber(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } app.get('/rolldice', (req, res) => { res.send(getRandomNumber(1, 6).toString()); }); app.listen(PORT, () => { console.log(`Listening for requests on http://localhost:${PORT}`); });
此时应用已经编写完成,执行以下命令运行应用,访问地址为
http://localhost:8080/rolldice
。node app.js
导入 OpenTelemetry 相关依赖。
安装 OpenTelemetry Node SDK 和自动插桩包。
HTTP上报
npm install @opentelemetry/sdk-node \ @opentelemetry/api \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/sdk-trace-node \ @opentelemetry/exporter-trace-otlp-proto
gRPC上报
npm install @opentelemetry/sdk-node \ @opentelemetry/api \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/sdk-trace-node \ @opentelemetry/exporter-trace-otlp-grpc
auto-instrumentations-node 包会自动监控代码中常用的第三方库(如 Express),当这些库被调用时自动生成追踪数据。
配置 OpenTelemetry。
为了让 OpenTelemetry 能够自动收集应用程序的追踪数据并上报到云监控2.0平台,需要创建一个插桩配置文件。该文件负责初始化 SDK、配置数据导出器和启用自动插桩功能。
创建一个名为 instrumentation.js 的文件,将步骤一获取到的接入点信息替换到以下代码中。
HTTP上报
/*instrumentation.js*/ const opentelemetry = require('@opentelemetry/sdk-node'); const { getNodeAutoInstrumentations, } = require('@opentelemetry/auto-instrumentations-node'); const { OTLPTraceExporter, } = require('@opentelemetry/exporter-trace-otlp-proto'); const sdk = new opentelemetry.NodeSDK({ traceExporter: new OTLPTraceExporter({ url: "<endpoint>", headers: { 'x-arms-license-key': '<license-key>', 'x-arms-project': '<arms-project>', 'x-cms-workspace': '<workspace>' }, }), instrumentations: [getNodeAutoInstrumentations()], }); sdk.start();
gRPC上报
/*instrumentation.js*/ const opentelemetry = require('@opentelemetry/sdk-node'); const { getNodeAutoInstrumentations, } = require('@opentelemetry/auto-instrumentations-node'); const { OTLPTraceExporter, } = require('@opentelemetry/exporter-trace-otlp-grpc'); const sdk = new opentelemetry.NodeSDK({ traceExporter: new OTLPTraceExporter({ url: "<endpoint>", headers: { 'x-arms-license-key': '<license-key>', 'x-arms-project': '<arms-project>', 'x-cms-workspace': '<workspace>' }, }), instrumentations: [getNodeAutoInstrumentations()], }); sdk.start();
(可选)手动创建 Span。
虽然 auto-instrumentations-node 已经能够捕获大部分常见框架和库的调用,但在某些场景下您可能需要手动创建 Span 来获得更细粒度的追踪信息。 手动创建 Span 时,需要做以下几件事情:
获取 Tracer: 在应用程序中任何需要手动编写代码创建 Span 的地方,都应该调用 getTracer 来获取一个 tracer。
创建和管理 Span: 在需要创建 Span 的代码中,调用 startActiveSpan 方法来创建一个 span,并使用 end 方法来结束 span。
在原有的app.js上进行修改,支持输出多次扔骰子的结果。以下代码展示了如何为每次掷骰子操作创建独立的 Span,以获得更细粒度的追踪信息。
/*app.js*/ const { trace } = require('@opentelemetry/api'); const express = require('express'); const tracer = trace.getTracer('demo', '0.1.0'); const PORT = parseInt(process.env.PORT || '8080'); const app = express(); function rollOnce(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } function rollTheDice(rolls, min, max) { // 创建一个 span return tracer.startActiveSpan('rollTheDice', (span) => { const result = []; for (let i = 0; i < rolls; i++) { result.push(rollOnce(min, max)); } // 确保结束 span span.end(); return result; }); } app.get('/rolldice', (req, res) => { const rolls = req.query.rolls ? parseInt(req.query.rolls.toString()) : NaN; if (isNaN(rolls)) { res .status(400) .send("Request parameter 'rolls' is missing or not a number."); return; } res.send(JSON.stringify(rollTheDice(rolls, 1, 6))); }); app.listen(PORT, () => { console.log(`Listening for requests on http://localhost:${PORT}`); });
运行应用。
node --require ./instrumentation.js app.js