콘텐츠로 이동

OpenTelemetry Node.js

OTEL로 Trace / Metric을 DataKit에 보내기 전에 먼저 수집기 구성이 완료되었는지 확인하세요.

OpenTelemetry Node.js는 Node.js 애플리케이션의 Trace와 Metric 데이터를 수집하고 OTLP 프로토콜로 DataKit에 전송한 뒤, Guance에서 통합 표시할 수 있습니다.

표준 OpenTelemetry 기능 외에도, Guance는 Node.js를 위해 프로파일 확장 기능을 제공합니다. 이 기능은 Guance가 유지보수하고 배포하는 @cloudcare/profiler-nodejs@datadog/pprof를 기반으로 wall / heap profile을 수집하며, DataKit의 /profiling/v1/input 인터페이스를 통해 Guance로 전송할 수 있습니다.

지원 버전

  • 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가 시작되었습니다');
}

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

Node.js Profile 확장

Node.js Profile은 Guance가 현재 Node.js 환경을 위해 제공하는 확장 기능으로, 표준 OTel Trace / Metric 외의 profile 데이터 수집을 보완합니다.

이 기능은 OpenTelemetry 공식 npm 패키지의 일부가 아니라, Guance가 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 설정

대부분의 경우 아래 핵심 매개변수만 확인하면 됩니다.

매개변수 기본값 설명
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/nanoseconds, wall/nanoseconds 포함
  • space.pprof: objects/count, space/bytes 포함

또한 event.json도 함께 포함되며, 다음 값이 들어갑니다.

  • profiler는 고정으로 ddtrace
  • family는 고정으로 nodejs
  • format은 고정으로 pprof

이 구조는 Guance의 현재 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)

Guance 측 데이터 검증

연동을 완료한 뒤 Guance에서 다음을 확인할 수 있습니다.

  1. Trace가 서비스 기준으로 정상 전송되었는지
  2. Metric이 해당 지표 집합에 들어갔는지
  3. Node.js Profile이 서비스 차원에서 표시되는지

주의 사항

  1. Node.js Profile은 Guance의 확장 기능이며, OpenTelemetry 공식 표준 기능이 아닙니다.
  2. 현재는 wallheap 두 종류의 profile만 지원합니다.
  3. 실행 환경에 globalThis.fetch가 없으면 fetch 구현을 명시적으로 전달해야 합니다.
  4. 프로세스 종료 전에 profile이 유실되는 것을 막으려면 종료 시 shutdown()을 호출하는 것이 좋습니다.
  5. Trace / Metric만 필요하다면 @cloudcare/profiler-nodejs를 설치하지 않아도 됩니다.

참고

문서 평가

이 페이지가 도움이 되었나요?