@coralogix/opentelemetry-profiling

中文文档
0.2.0发布于 2026/07/30Apache-2.0TypeScriptCommonJS近 30 天下载 3.5万

OpenTelemetry Node.js Profiling SDK

原始使用文档
文档目录27 节
  1. Features
  2. Installation
  3. Quick Start
  4. Configuration
  5. Programmatic
  6. Environment Variables
  7. Exporters
  8. Pprof push (opt-in)
  9. OTLP gRPC (default)
  10. Console
  11. Custom
  12. Trace-Profile Correlation
  13. Span Attribute Extraction
  14. Using with the OpenTelemetry Collector
  15. Default: pprof push
  16. OTLP gRPC
  17. How It Works
  18. Wall-clock vs CPU profiling
  19. Async stack limitation
  20. Source Maps
  21. Examples
  22. API Reference
  23. ProfilingProviderConfig
  24. ProfilingProvider
  25. ProfileData
  26. ProfileExporter
  27. License

@coralogix/opentelemetry-profiling

OpenTelemetry continuous profiling SDK for Node.js. Collects wall-clock and heap profiles using @datadog/pprof and exports them as OTLP (default) or native pprof.

Features

  • Wall-clock profiling — samples JS stacks at regular intervals (default 100Hz), capturing both on-CPU and idle time
  • Heap profiling — samples memory allocations to identify where memory is being consumed
  • Trace-profile correlation — attaches trace_id/span_id labels to samples for active OTel spans
  • Span attribute extraction — copies selected span attributes (e.g. http.route) onto profiling samples
  • Source map support — maps compiled JS filenames/lines back to original TypeScript sources
  • OTLP gRPC export (default) — sends OTLP profiles to OTel Collectors / OTLP-compatible backends
  • Pprof push export — opt-in alternative that sends raw pprof to the OTel Collector's pprofreceiver push endpoint, skipping OTLP conversion entirely
  • OTel environment variables — respects OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTES, OTEL_PROFILES_EXPORTER, etc.
  • Console exporter — debug exporter rendering raw pprof contents

Installation

npm install @coralogix/opentelemetry-profiling

For trace-profile correlation:

npm install @opentelemetry/api @opentelemetry/sdk-trace-node

Quick Start

import { ProfilingProvider } from '@coralogix/opentelemetry-profiling';

const provider = new ProfilingProvider({
  serviceName: 'my-service',
});

await provider.start();

// Your application code...

// On shutdown
await provider.stop();

Configuration

Programmatic

import {
  ProfilingProvider,
  ConsoleProfileExporter,
  OtlpGrpcProfileExporter,
} from '@coralogix/opentelemetry-profiling';

const provider = new ProfilingProvider({
  // Service identification
  serviceName: 'my-service',
  resource: {
    'deployment.environment': 'production',
    'service.version': '1.2.3',
  },

  // Profiler toggles
  wallProfilingEnabled: true,   // default: true
  heapProfilingEnabled: true,   // default: true

  // Collection interval — how often profiles are flushed to the exporter
  collectionIntervalMs: 10_000, // default: 10000 (10s)

  // Wall profiler tuning
  wallSamplingIntervalMicros: 10_000, // default: 10000 (100Hz)

  // Heap profiler tuning
  heapSamplingIntervalBytes: 524_288, // default: 524288 (512KB)
  heapStackDepth: 64,                 // default: 64

  // Trace-profile correlation (requires @opentelemetry/api)
  traceCorrelation: true,

  // Copy these span attributes onto profiling samples
  spanAttributeKeys: ['http.route', 'rpc.method'],

  // Source maps — map compiled JS back to original TypeScript sources
  sourceMapSearchPaths: ['./dist'],

  // Exporters — defaults to [OtlpGrpcProfileExporter]
  exporters: [
    new OtlpGrpcProfileExporter({
      endpoint: 'http://localhost:4317',
      headers: { 'x-api-key': 'secret' },
    }),
    new ConsoleProfileExporter({ verbosity: 'basic' }),
  ],
});

Environment Variables

VariableDescriptionDefault
OTEL_SERVICE_NAMEService name—
OTEL_RESOURCE_ATTRIBUTESComma-separated key=value pairs—
OTEL_PROFILES_EXPORTERComma-separated exporters: pprof, otlp, console, noneotlp
OTEL_EXPORTER_PPROF_ENDPOINTPprof push endpointhttp://localhost:4040/v1/pprof
OTEL_EXPORTER_PPROF_HEADERSHeaders for pprof push (comma-separated k=v)—
OTEL_EXPORTER_OTLP_PROFILES_ENDPOINTProfiles-specific OTLP gRPC endpoint—
OTEL_EXPORTER_OTLP_ENDPOINTGeneral OTLP gRPC endpoint (fallback)http://localhost:4317
OTEL_EXPORTER_OTLP_PROFILES_HEADERSProfiles-specific OTLP headers—
OTEL_EXPORTER_OTLP_HEADERSGeneral OTLP headers (fallback)—
OTEL_PROFILING_WALL_ENABLEDEnable wall-clock profiler (true/false)true
OTEL_PROFILING_HEAP_ENABLEDEnable heap profiler (true/false)true
OTEL_PROFILING_COLLECTION_INTERVAL_MSProfile collection interval10000
OTEL_PROFILING_WALL_SAMPLING_INTERVAL_MICROSWall-clock sample interval (microseconds)10000 (100Hz)
OTEL_PROFILING_HEAP_SAMPLING_INTERVAL_BYTESHeap allocation sample interval (bytes)profiler default
OTEL_PROFILING_HEAP_STACK_DEPTHMax stack frames for heap samplesprofiler default
OTEL_PROFILING_HEAP_SAMPLE_TYPESHeap sample types: bytes, objects, or bothboth
OTEL_PROFILING_TRACE_CORRELATIONAttach trace_id/span_id labels (true/false)true
OTEL_PROFILING_SPAN_ATTRIBUTE_KEYSComma-separated span attribute keys to copy onto samples—
OTEL_PROFILING_SOURCE_MAP_SEARCH_PATHSComma-separated directories scanned for source maps—

Environment variables are overridden by programmatic config.

Exporters

Pprof push (opt-in)

Sends raw pprof bytes (gzipped) over HTTP/1.1 to the OTel Collector's pprofreceiver push endpoint (POST /v1/pprof). No pprof→OTLP conversion happens in the SDK — the collector does it.

Select via OTEL_PROFILES_EXPORTER=pprof.

Resource attributes are sent as a single HTTP header Otel-Resource-Attributes: k=v,k=v (same syntax as OTEL_RESOURCE_ATTRIBUTES). The SDK adds profiler.type=wall|heap to the resource for each export so backends can distinguish profile kinds. The collector must be configured with include_metadata: true and a transform processor that promotes the header into resource attributes — see Using with the OpenTelemetry Collector.

import { PprofPushProfileExporter } from '@coralogix/opentelemetry-profiling';

const exporter = new PprofPushProfileExporter({
  endpoint: 'http://collector:4040/v1/pprof',
  headers: { authorization: 'Bearer …' },
});

OTLP gRPC (default)

Sends profiles to an OTLP-compatible collector via gRPC (HTTP/2 + protobuf). Uses Node's built-in http2 module — no @grpc/grpc-js dependency. Pprof→OTLP conversion happens in the SDK.

Selected by default; also OTEL_PROFILES_EXPORTER=otlp (or otlp_grpc).

import { OtlpGrpcProfileExporter } from '@coralogix/opentelemetry-profiling';

const exporter = new OtlpGrpcProfileExporter({
  endpoint: 'http://localhost:4317',
});

Console

Prints raw pprof contents to stdout. Three verbosity levels:

import { ConsoleProfileExporter } from '@coralogix/opentelemetry-profiling';

// basic — one summary line
new ConsoleProfileExporter({ verbosity: 'basic' });

// normal (default) — summary + resource attrs + table sizes + period info
new ConsoleProfileExporter({ verbosity: 'normal' });

// detailed — also includes top-N functions by leaf sample value
new ConsoleProfileExporter({ verbosity: 'detailed', topN: 10 });

Custom

Implement the ProfileExporter interface. Each exporter receives raw pprof — encode or convert as needed.

import { ProfileExporter, ProfileData, buildRequest, encodeRequest } from '@coralogix/opentelemetry-profiling';

class MyExporter implements ProfileExporter {
  async export(data: ProfileData): Promise<void> {
    // data.profile     — pprof-format Profile object
    // data.profileType — 'wall' | 'heap'
    // data.startedAt / data.stoppedAt — collection window
    // data.resource    — resolved resource attributes
  }

  async shutdown(): Promise<void> {
    // cleanup
  }
}

If your exporter needs an OTLP ExportProfilesServiceRequest, build it on demand:

const request = buildRequest(
  [{ profile: data.profile, profileType: data.profileType, startedAt: data.startedAt, stoppedAt: data.stoppedAt }],
  data.resource,
);
const encoded = encodeRequest(request);

Trace-Profile Correlation

When @opentelemetry/api is installed and a TracerProvider is active, enabling traceCorrelation links profiling samples to the spans they were captured in.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { ProfilingProvider } from '@coralogix/opentelemetry-profiling';

// Set up tracing first
const tracerProvider = new NodeTracerProvider();
tracerProvider.register();

// Then profiling
const profiling = new ProfilingProvider({
  serviceName: 'my-service',
  traceCorrelation: true,
});
await profiling.start();

Each wall-clock sample captured while a span is active gets trace_id and span_id labels in the pprof output.

  • Pprof push path: labels travel through the collector's pprof receiver translator as ordinary sample attributes. Backends key off the trace_id/span_id attributes directly.
  • OTLP path: the converter promotes these labels into the OTLP Link table (sample.linkIndex).

Either shape preserves the same information; only the structural layout differs.

Span Attribute Extraction

Use spanAttributeKeys to copy specific span attributes onto profiling samples. This enables grouping and filtering profiles by attributes like HTTP route or RPC method.

const profiling = new ProfilingProvider({
  traceCorrelation: true,
  spanAttributeKeys: ['http.route', 'rpc.method', 'rpc.service'],
});

Attributes are read from the span at profile collection time, not when the span is activated. This means attributes set after span creation (e.g. http.route set by Express after route matching) are captured correctly.

Note: Span attribute extraction only works for wall-clock profiles. Heap profiles use V8's AllocationProfiler which has no per-allocation context capture, so there's no way to know which span was active when a given allocation occurred.

Using with the OpenTelemetry Collector

Default: pprof push

This SDK sends raw pprof to the collector's pprofreceiver push endpoint. Resource attributes are conveyed in the Otel-Resource-Attributes HTTP header, so the receiver needs include_metadata: true and a transform processor that lifts the header into resource.attributes:

receivers:
  pprof:
    server:
      endpoint: 0.0.0.0:4040
      include_metadata: true

processors:
  transform:
    profile_statements:
      - set(resource.attributes, ParseKeyValue(metadata["otel-resource-attributes"], "=", ","))

exporters:
  debug:
    verbosity: detailed

service:
  pipelines:
    profiles:
      receivers: [pprof]
      processors: [transform]
      exporters: [debug]

Without the transform rule, profiles will arrive with no service.name or other resource attributes — the header carries them, but nothing promotes them by default.

OTLP gRPC

If you opt out of pprof push (OTEL_PROFILES_EXPORTER=otlp), the standard OTLP receiver applies:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

exporters:
  debug:
    verbosity: detailed

service:
  pipelines:
    profiles:
      receivers: [otlp]
      exporters: [debug]

Note: The collector must have the --feature-gates=+service.profilesSupport flag set (or run a version where profiles support is GA).

How It Works

  1. @datadog/pprof drives the actual sampling — it uses a native addon with setitimer(SIGALRM) for wall-clock sampling and V8's AllocationProfiler for heap sampling
  2. Collection loop runs every collectionIntervalMs (default 10s), calling stop(restart=true) on the wall profiler and profile() on the heap profiler
  3. Per-exporter encoding — the provider hands raw pprof to each configured exporter. The pprof push exporter gzip-encodes the bytes and POSTs them. The OTLP exporter converts pprof → OTLP locally (dictionary-based string/function/location/stack tables), encodes as protobuf, frames it with gRPC length-prefixed encoding, and sends via HTTP/2. Conversion only happens for exporters that need it.

Wall-clock vs CPU profiling

The wall profiler samples at regular wall-clock intervals regardless of whether JavaScript is executing. This means:

  • On-CPU work (computation) shows as function frames
  • Off-CPU time (I/O wait, event loop idle) shows as (idle)
  • Both are captured, giving a complete picture of where time is spent

Async stack limitation

When Node.js hits an await, the call stack is unwound — there's no stack to sample. This means a function like await db.query() appears as (idle) samples, not as samples attributed to db.query. Enabling traceCorrelation helps bridge this gap by attributing idle time to the span that was active.

Source Maps

When profiling TypeScript or bundled applications, V8 reports function names and filenames from the compiled JS output. Enable sourceMapSearchPaths to map these back to original source files:

const provider = new ProfilingProvider({
  sourceMapSearchPaths: ['./dist'],
});
await provider.start();

The provider scans the specified directories for .js.map files at startup. Profiles will then show original filenames and line numbers (e.g. src/handler.ts:42 instead of dist/handler.js:120).

Requires your build to emit source maps (e.g. "sourceMap": true in tsconfig.json).

Examples

See the examples/ directory:

API Reference

ProfilingProviderConfig

OptionTypeDefaultDescription
serviceNamestring—Service name (optional; omitted from resource if unset)
resourceRecord<string, string | number | boolean>—Additional resource attributes
exportersProfileExporter[][OtlpGrpcProfileExporter]Exporter instances
traceCorrelationbooleantrueLink samples to active OTel spans
spanAttributeKeysstring[][]Span attributes to copy onto samples
wallProfilingEnabledbooleantrueEnable wall-clock profiling
heapProfilingEnabledbooleantrueEnable heap profiling
collectionIntervalMsnumber10000How often profiles are flushed
wallSamplingIntervalMicrosnumber10000Wall profiler sampling interval (100Hz)
heapSamplingIntervalBytesnumber524288Heap profiler sampling interval (512KB)
heapStackDepthnumber64Max stack depth for heap samples
sourceMapSearchPathsstring[]—Directories to scan for .js.map files

ProfilingProvider

MethodDescription
new ProfilingProvider(config?)Create a provider with optional config
start(): Promise<void>Start profilers and begin periodic collection
stop(): Promise<void>Stop profilers, flush final profiles, shutdown exporter

ProfileData

FieldTypeDescription
profileProfile (from pprof-format)Raw pprof profile
profileType'wall' | 'heap'Type of profile
startedAtDateStart of collection window
stoppedAtDateEnd of collection window
resourceResourceAttributesResolved resource attributes for this profile

ProfileExporter

MethodDescription
export(data: ProfileData): Promise<void>Export a single profile
shutdown(): Promise<void>Clean up resources

License

Apache-2.0

版本与发布记录

@coralogix/opentelemetry-profiling 共发布 1 个版本,首次发布于 2026/07/30;过去 12 个月发布了 1 个版本。

版本发布日期距今
0.2.0latest2026/07/303 个月前

关于 @coralogix/opentelemetry-profiling 的常见问题

@coralogix/opentelemetry-profiling 是什么?

OpenTelemetry Node.js Profiling SDK

如何安装 @coralogix/opentelemetry-profiling?

在项目目录运行 npm install @coralogix/opentelemetry-profiling,或使用 pnpm add / yarn add / bun add。

@coralogix/opentelemetry-profiling 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@coralogix/opentelemetry-profiling 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@coralogix/opentelemetry-profiling 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@coralogix/opentelemetry-profiling 可以商用吗?

@coralogix/opentelemetry-profiling 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@coralogix/opentelemetry-profiling 的下载量有多少?

根据 npm 官方下载统计,@coralogix/opentelemetry-profiling 在 2026/10/11 – 2026/11/09 这 30 天内被下载 35,032 次,日均约 1,168 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@coralogix/opentelemetry-profiling 还在维护吗?

最新版本 0.2.0 发布于 2026/07/30(3 个月前);至今共发布 1 个版本,其中过去 12 个月发布了 1 个;首次发布于 2026/07/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。