跳转至

OpenTelemetry Node.js

在使用 OTEL 发送 Trace / Metric 到 DataKit 之前,请先确定您已经配置好了采集器

OpenTelemetry Node.js 可以用于采集 Node.js 应用的 Trace 和 Metric 数据,并通过 OTLP 协议上报到 DataKit,再由 观测云 统一展示。

除了标准 OpenTelemetry 能力外,观测云 还为 Node.js 提供了 Profile 扩展能力。该能力基于观测云维护并发布的 @cloudcare/profiler-nodejs@datadog/pprof,可以采集 wall / heap profile,并通过 DataKit 的 /profiling/v1/input 接口上报到 观测云。

版本支持

  • Node.js:^18.19.0>=20.6.0
  • OpenTelemetry:建议使用当前稳定版本
  • Profile 扩展包:@cloudcare/profiler-nodejs
  • 默认 Profiling 上报地址:http://127.0.0.1:9529/profiling/v1/input

自动埋点方式

Node.js 最常用的是通过自动埋点方式快速接入。

1) 安装依赖

npm install \
  @opentelemetry/api \
  @opentelemetry/sdk-node \
  @opentelemetry/auto-instrumentations-node \
  @opentelemetry/exporter-trace-otlp-proto \
  @opentelemetry/exporter-metrics-otlp-proto

2) 环境变量方式

export OTEL_SERVICE_NAME="nodejs-demo"
export OTEL_TRACES_EXPORTER="otlp"
export OTEL_METRICS_EXPORTER="otlp"
export OTEL_LOGS_EXPORTER="none"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:9529/otel"
export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"

然后直接启动你的应用:

node app.js

如果使用默认 HTTP 路径,则 Trace / Metric 实际上报地址分别为:

  • Trace:http://127.0.0.1:9529/otel/v1/traces
  • Metric:http://127.0.0.1:9529/otel/v1/metrics

3) 命令行启动方式

如果不希望通过环境变量注入,也可以在启动命令里直接配置:

OTEL_SERVICE_NAME=nodejs-demo \
OTEL_TRACES_EXPORTER=otlp \
OTEL_METRICS_EXPORTER=otlp \
OTEL_LOGS_EXPORTER=none \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:9529/otel \
NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register" \
node app.js

4) PM2 / Systemd 场景

如果应用通过 PM2、Systemd 或其它进程管理器启动,建议将上述 OTEL_* 环境变量和 NODE_OPTIONS 写入对应的启动配置中。

核心配置通常只有两项:

  • OTEL_SERVICE_NAME
  • NODE_OPTIONS=--require @opentelemetry/auto-instrumentations-node/register

其余 OTLP 参数根据实际 DataKit 地址补充即可。

代码方式接入

如果不适合自动埋点,可以通过代码方式集成 OpenTelemetry SDK。

安装依赖

npm install \
  @opentelemetry/api \
  @opentelemetry/sdk-node \
  @opentelemetry/resources \
  @opentelemetry/semantic-conventions \
  @opentelemetry/exporter-trace-otlp-proto \
  @opentelemetry/exporter-metrics-otlp-proto \
  @opentelemetry/instrumentation-http

示例代码

const { NodeSDK } = require('@opentelemetry/sdk-node');
const { resourceFromAttributes } = require('@opentelemetry/resources');
const {
  ATTR_SERVICE_NAME,
  ATTR_SERVICE_VERSION,
  SEMRESATTRS_DEPLOYMENT_ENVIRONMENT,
} = require('@opentelemetry/semantic-conventions');
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
const {
  OTLPTraceExporter,
} = require('@opentelemetry/exporter-trace-otlp-proto');

const resource = resourceFromAttributes({
  [ATTR_SERVICE_NAME]: 'orders-api',
  [ATTR_SERVICE_VERSION]: '1.0.0',
  [SEMRESATTRS_DEPLOYMENT_ENVIRONMENT]: 'prod',
});

const sdk = new NodeSDK({
  resource,
  traceExporter: new OTLPTraceExporter({
    url: 'http://127.0.0.1:9529/otel/v1/traces',
  }),
  instrumentations: [new HttpInstrumentation()],
});

async function main() {
  await sdk.start();
  console.log('OpenTelemetry Node.js started');
}

main().catch(err => {
  console.error(err);
  process.exit(1);
});

Node.js Profile 扩展

Node.js Profile 是 观测云 当前针对 Node.js 场景提供的扩展能力,用于补充标准 OTel Trace / Metric 之外的 profile 数据采集。

该能力不是 OpenTelemetry 官方 npm 包的一部分,而是由观测云在 OpenTelemetry Node.js 基础上扩展并发布。

当前支持的 profile 类型:

  • wall
  • heap

实际接入时,建议默认先启用 wall,确认链路稳定后再按需开启 heap

获取 @cloudcare/profiler-nodejs

当前 Node.js Profile 扩展包名为:

@cloudcare/profiler-nodejs

如果可以直接访问 npm 公网仓库,可执行:

npm install @cloudcare/profiler-nodejs

安装依赖

npm install \
  @cloudcare/profiler-nodejs \
  @datadog/pprof \
  @opentelemetry/resources \
  @opentelemetry/semantic-conventions

最小接入示例

const { resourceFromAttributes } = require('@opentelemetry/resources');
const {
  ATTR_SERVICE_NAME,
  ATTR_SERVICE_VERSION,
  SEMRESATTRS_DEPLOYMENT_ENVIRONMENT,
} = require('@opentelemetry/semantic-conventions');
const {
  DatakitProfilingExporter,
  NodeProfiling,
} = require('@cloudcare/profiler-nodejs');

const profiler = new NodeProfiling({
  resource: resourceFromAttributes({
    [ATTR_SERVICE_NAME]: 'orders-api',
    [ATTR_SERVICE_VERSION]: '1.2.3',
    [SEMRESATTRS_DEPLOYMENT_ENVIRONMENT]: 'prod',
  }),
  exporter: new DatakitProfilingExporter({
    endpoint: 'http://127.0.0.1:9529/profiling/v1/input',
  }),
  profileTypes: ['wall'],
  cpuProfilingEnabled: true,
});

async function main() {
  await profiler.start();
}

main().catch(err => {
  console.error(err);
  process.exit(1);
});

与 OpenTelemetry SDK 一起使用

如果应用已经接入 OpenTelemetry SDK,可以同时初始化 profiler:

const { NodeSDK } = require('@opentelemetry/sdk-node');
const { resourceFromAttributes } = require('@opentelemetry/resources');
const {
  ATTR_SERVICE_NAME,
  ATTR_SERVICE_VERSION,
  SEMRESATTRS_DEPLOYMENT_ENVIRONMENT,
} = require('@opentelemetry/semantic-conventions');
const {
  DatakitProfilingExporter,
  NodeProfiling,
} = require('@cloudcare/profiler-nodejs');

const resource = resourceFromAttributes({
  [ATTR_SERVICE_NAME]: 'orders-api',
  [ATTR_SERVICE_VERSION]: '1.2.3',
  [SEMRESATTRS_DEPLOYMENT_ENVIRONMENT]: 'prod',
});

const sdk = new NodeSDK({
  resource,
});

const profiling = new NodeProfiling({
  resource,
  exporter: new DatakitProfilingExporter({
    endpoint: 'http://127.0.0.1:9529/profiling/v1/input',
  }),
});

async function main() {
  await sdk.start();
  await profiling.start();
}

process.on('SIGTERM', async () => {
  await profiling.shutdown();
  await sdk.shutdown();
  process.exit(0);
});

main().catch(err => {
  console.error(err);
  process.exit(1);
});

手动触发一次采集

在验证链路时,可以直接执行:

await profiling.collectOnce();

这通常适合:

  • 初次验证 Profiling 接口是否可达;
  • 检查 profile 是否成功生成并发出;
  • 在特定压测窗口内定点采集一次 profile。

Profile 推荐配置

大多数情况下,只需要关注下面几个关键参数:

参数 默认值 说明
endpoint http://127.0.0.1:9529/profiling/v1/input Profile 上传地址
profileTypes ['wall', 'heap'] 采集的 profile 类型,推荐先使用 ['wall']
intervalMillis 60000 周期采集间隔
wallDurationMillis 10000 单次 wall profile 持续时间

如果没有特别的性能调优需求,通常保持默认值即可。

默认行为

默认情况下,Node.js Profile 扩展会:

  • 60 秒执行一次采集;
  • 每轮采集 wallheap 两类 profile;
  • wall profile 默认采集 10 秒;
  • 默认开启 cpuProfilingEnabled
  • 将 profile 发送到 http://127.0.0.1:9529/profiling/v1/input

当前 exporter 会发送两个 pprof 附件:

  • wall.pprof
  • space.pprof

其中:

  • wall.pprof:包含 sample/count、可选 cpu/nanosecondswall/nanoseconds
  • space.pprof:包含 objects/countspace/bytes

同时还会附带一个 event.json,其中:

  • profiler 固定为 ddtrace
  • family 固定为 nodejs
  • format 固定为 pprof

这一布局用于兼容 观测云 当前的 Node.js Profile 解析链路。

验证

验证 Trace / Metric 上报

确认应用可以访问 DataKit OTLP HTTP 端点:

curl -i http://127.0.0.1:9529/otel/v1/traces
curl -i http://127.0.0.1:9529/otel/v1/metrics

验证 Profile 上报

确认应用可以访问 Profiling 接口:

curl -i http://127.0.0.1:9529/profiling/v1/input

验证日志

如果 profile 上报成功,调试日志中通常会出现类似信息:

Datakit profiling export succeeded for 1 profile(s)

验证 观测云 侧数据

完成接入后,可以在 观测云 中检查:

  1. Trace 是否按服务成功上报;
  2. Metric 是否已进入对应指标集;
  3. Node.js Profile 是否已按服务维度展示。

注意事项

  1. Node.js Profile 是 观测云 的扩展能力,不是 OpenTelemetry 官方标准能力;
  2. 当前仅支持 wallheap 两类 profile;
  3. 如果运行环境没有 globalThis.fetch,请显式传入 fetch 实现;
  4. 为避免进程退出前 profile 丢失,建议在进程结束时调用 shutdown()
  5. 如果只需要 Trace / Metric,可不安装 @cloudcare/profiler-nodejs

参考

文档评价

文档内容是否对您有帮助?