콘텐츠로 이동

OpenTelemetry Node.js

OpenTelemetry Node.js 자동 계측 모듈은 시작 매개변수를 통해 사전 로드되어 애플리케이션 의존성이 로드되기 전에 Hook을 등록합니다. 비즈니스 코드를 수정할 필요 없이 지원되는 웹 프레임워크, HTTP 클라이언트, 데이터베이스 및 메시지 큐 호출을 수집할 수 있습니다.

표준 OpenTelemetry 기능 외에도 Guance는 Node.js에 Profile 확장 기능을 제공합니다. 이 기능은 @cloudcare/profiler-nodejs@datadog/pprof를 기반으로 하며, wall, heap profile을 수집하고 DataKit의 /profiling/v1/input 엔드포인트를 통해 전송합니다. Profile 확장은 OpenTelemetry 공식 표준 기능이 아니므로, 이 문서에서는 코드 없는 방식 외의 추가 방안으로 소개합니다.

이 문서에서는 DataKit의 OpenTelemetry 수집기를 사용하여 OTLP 데이터를 수신하고 Guance로 전달합니다:

Node.js 애플리케이션 + OpenTelemetry 자동 계측 모듈 -> OTLP -> DataKit -> Guance

전제 조건

  • OpenTelemetry JavaScript에서 현재 지원하는 Node.js LTS 버전 사용
  • 애플리케이션이 npm, pnpm 또는 Yarn을 사용하여 의존성 관리
  • DataKit이 설치되어 있고 대상 Guance 워크스페이스에 연결되어 있음
  • Node.js 애플리케이션에서 DataKit으로의 네트워크 연결 가능: OTLP/HTTP는 DataKit HTTP 포트 9529 사용, OTLP/gRPC는 기본적으로 4317 사용

버전 및 확장 지원

  • Node.js: 자동 계측 패키지는 일반적으로 ^18.19.0 또는 >=20.6.0을 요구하며, 프로덕션 환경에서는 현재 지원되는 LTS 버전을 사용하고 실제 설치된 패키지의 engines 선언을 기준으로 합니다.
  • OpenTelemetry: 현재 안정 버전을 사용하고 lockfile을 통해 실제 배포 버전을 고정하는 것이 좋습니다.
  • Profile 확장 패키지: @cloudcare/profiler-nodejs
  • 기본 Profiling 전송 주소: http://127.0.0.1:9529/profiling/v1/input

1. OpenTelemetry 수집기 활성화

DataKit 설치 디렉터리의 conf.d/opentelemetry로 이동합니다. 수집기 설정 파일이 아직 없으면 예제 파일을 복사합니다:

cd /usr/local/datakit/conf.d/opentelemetry
sudo cp opentelemetry.conf.sample opentelemetry.conf

opentelemetry.conf에 최소한 다음 수신 설정이 포함되어 있는지 확인합니다:

[[inputs.opentelemetry]]
  # Guance에서 태그로 유지할 사용자 정의 속성을 화이트리스트에 추가합니다.
  customer_tags = ["team", "project"]

  [inputs.opentelemetry.http]
    http_status_ok = 200
    trace_api = "/otel/v1/traces"
    metric_api = "/otel/v1/metrics"
    logs_api = "/otel/v1/logs"

  [inputs.opentelemetry.grpc]
    addr = "127.0.0.1:4317"
    max_payload = 16777216

수신 주소는 다음과 같습니다:

프로토콜 데이터 유형 DataKit 수신 주소
OTLP/HTTP + Protobuf Trace http://<DataKit-IP>:9529/otel/v1/traces
OTLP/HTTP + Protobuf Metric http://<DataKit-IP>:9529/otel/v1/metrics
OTLP/HTTP + Protobuf Log http://<DataKit-IP>:9529/otel/v1/logs
OTLP/gRPC Trace, Metric, Log http://<DataKit-IP>:4317

Node.js 애플리케이션과 DataKit가 동일한 호스트에 있지 않은 경우, 실제 배포 환경에 맞게 DataKit 리스닝 주소, 방화벽 또는 기타 네트워크 액세스 제어를 조정해야 합니다. gRPC의 경우 addr을 애플리케이션에서 액세스 가능한 리스닝 주소(예: 0.0.0.0:4317)로 변경할 수 있습니다. OTLP 수신 포트를 공용 네트워크에 직접 노출하지 마십시오.

DataKit를 재시작하고 서비스를 확인합니다:

sudo datakit service restart
curl http://127.0.0.1:9529/v1/ping

2. 애플리케이션에 OpenTelemetry 연결

자동 계측 모듈 설치

애플리케이션 프로젝트 디렉터리에서 npm 공식 저장소를 통해 OpenTelemetry 공식 패키지를 설치합니다:

npm install --save \
  @opentelemetry/api \
  @opentelemetry/auto-instrumentations-node

@opentelemetry/auto-instrumentations-node에는 Node.js SDK, 자동 계측 라이브러리 및 일반적인 exporter가 포함되어 있습니다. 이 패키지는 지원되고 실제로 로드된 라이브러리에 대해서만 텔레메트리 데이터를 생성합니다. 애플리케이션에서 사용하는 프레임워크나 클라이언트가 지원 목록에 없으면 해당 Span이 자동으로 생성되지 않습니다.

환경 변수를 통한 시작

다음은 OTLP/HTTP + Protobuf를 예로 들어, 기본적으로 Trace는 활성화하고 Metric과 Log는 비활성화합니다:

export OTEL_SERVICE_NAME="order-service"
export OTEL_RESOURCE_ATTRIBUTES="env=prod,version=1.0.0,team=backend"

export OTEL_TRACES_EXPORTER="otlp"
export OTEL_METRICS_EXPORTER="none"
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 OTEL_PROPAGATORS="tracecontext,baggage"

export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"
node app.js

OTEL_EXPORTER_OTLP_ENDPOINT는 기본 주소입니다. OTLP/HTTP exporter는 데이터 유형에 따라 자동으로 /v1/traces, /v1/metrics 또는 /v1/logs를 추가하여 최종적으로 DataKit의 /otel/v1/* 경로에 매핑됩니다.

애플리케이션에 이미 NODE_OPTIONS가 설정되어 있는 경우, 기존 매개변수를 유지하면서 --require @opentelemetry/auto-instrumentations-node/register를 추가하고 기존 값을 덮어쓰지 않도록 주의하십시오. PM2, systemd, Supervisor 또는 npm scripts 시나리오에서는 OTEL_*NODE_OPTIONS를 실제 애플리케이션 프로세스의 시작 환경에 작성해야 합니다.

시작 매개변수를 통한 로드

NODE_OPTIONS를 설정하지 않고 Node.js 시작 명령에서 직접 모듈을 사전 로드할 수도 있습니다:

node --require @opentelemetry/auto-instrumentations-node/register app.js

자동 계측 모듈은 애플리케이션 코드 및 해당 의존성이 로드되기 전에 실행되어야 합니다. node app.js 시작 후에 동적으로 모듈을 로드하지 마십시오. 그렇지 않으면 이미 로드된 라이브러리가 계측되지 않을 수 있습니다.

일반적인 시작 방법

npm script를 통해 시작:

NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register" npm start

PM2를 통해 시작하는 경우, ecosystem.config.jsenv 설정에 변수를 넣거나 프로세스 관리 플랫폼의 환경 변수 기능을 통해 주입할 수 있습니다. 설정을 변경한 후에는 애플리케이션 프로세스를 재시작해야 합니다. 핫 리로드만으로는 사전 로드 모듈이 다시 로드되지 않을 수 있습니다.

OTLP/gRPC 사용

OTLP/gRPC로 변경하려면 프로토콜과 endpoint만 변경하면 됩니다:

export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://127.0.0.1:4317"

gRPC endpoint에는 /v1/traces와 같은 HTTP 경로를 추가할 수 없습니다.

3. 데이터 전송 매개변수

기본 매개변수

환경 변수 설명 권장값 또는 예시
OTEL_SERVICE_NAME service.name을 설정합니다. 설정하지 않으면 서비스를 안정적으로 식별할 수 없습니다. order-service, 프로덕션 환경에서는 반드시 명시적으로 설정해야 합니다.
OTEL_RESOURCE_ATTRIBUTES 리소스 속성, 쉼표로 구분된 key=value 형식입니다. env=prod,version=1.0.0,team=backend
OTEL_TRACES_EXPORTER Trace 내보내기 도구입니다. DataKit로 전송할 때는 otlp로 설정하고, 비활성화할 때는 none으로 설정합니다.
OTEL_METRICS_EXPORTER Metric 내보내기 도구입니다. 메트릭을 전송해야 하는 경우 otlp로 설정하고, 그렇지 않으면 none으로 설정합니다.
OTEL_LOGS_EXPORTER Log 내보내기 도구입니다. 로그를 전송해야 하는 경우 otlp로 설정하고, 그렇지 않으면 none으로 설정합니다.
OTEL_PROPAGATORS 서비스 간 컨텍스트 전파 형식입니다. 기본값 tracecontext,baggage; 전체 링크에서 호환성을 유지해야 합니다.
OTEL_SDK_DISABLED OpenTelemetry SDK를 비활성화합니다. 기본값 false; 긴급하게 비활성화해야 하는 경우 true로 설정합니다.

service.name은 Guance에서 서비스 소속을 식별하는 데 사용됩니다. envversion을 함께 설정하여 환경 및 버전별로 필터링하는 것이 좋습니다. 기타 사용자 정의 리소스 속성은 DataKit customer_tags 화이트리스트에 추가된 후에만 태그로 유지됩니다. 속성 이름의 ._로 변환됩니다.

Node.js 자동 계측 매개변수

환경 변수 설명 기본값 또는 예시
NODE_OPTIONS 애플리케이션 의존성 로드 전에 자동 계측 등록 모듈을 사전 로드합니다. --require @opentelemetry/auto-instrumentations-node/register
OTEL_NODE_RESOURCE_DETECTORS 특정 리소스 탐지기를 활성화합니다. 여러 개는 쉼표로 구분합니다. 기본값 all; env,host,os,process 또는 none으로 설정 가능합니다.
OTEL_NODE_ENABLED_INSTRUMENTATIONS 나열된 계측만 활성화합니다. 이름에 @opentelemetry/instrumentation- 접두사를 포함하지 않습니다. http,express,pg
OTEL_NODE_DISABLED_INSTRUMENTATIONS 기본 목록에서 특정 계측을 비활성화합니다. fs,grpc
OTEL_LOG_LEVEL OpenTelemetry 내부 진단 로그 레벨입니다. 프로덕션 환경에서는 info 권장; 문제 해결 시에만 일시적으로 debug 사용합니다.

활성화 및 비활성화 목록을 동시에 설정하는 경우, 먼저 OTEL_NODE_ENABLED_INSTRUMENTATIONS가 적용된 후 비활성화 목록이 적용됩니다. 동일한 계측이 두 목록에 모두 있는 경우 최종적으로 비활성화됩니다. 복잡한 단일 계측 설정은 환경 변수만으로 완전히 구성할 수 없으며, 이 문서의 코드 없는 연결 범위를 벗어납니다.

OTLP 매개변수

환경 변수 설명 권장값 또는 예시
OTEL_EXPORTER_OTLP_PROTOCOL 모든 신호의 OTLP 프로토콜입니다. DataKit는 http/protobuf 또는 grpc를 지원합니다.
OTEL_EXPORTER_OTLP_ENDPOINT 모든 신호에 공통으로 사용되는 기본 주소입니다. HTTP: http://datakit-host:9529/otel; gRPC: http://datakit-host:4317.
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT Trace 전용 주소로, 공통 주소보다 우선합니다. http://datakit-host:9529/otel/v1/traces
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT Metric 전용 주소로, 공통 주소보다 우선합니다. http://datakit-host:9529/otel/v1/metrics
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT Log 전용 주소로, 공통 주소보다 우선합니다. http://datakit-host:9529/otel/v1/logs
OTEL_EXPORTER_OTLP_HEADERS 모든 OTLP 요청에 포함되는 요청 헤더입니다. 여러 값은 쉼표로 구분합니다. x-tenant=tenant-a; DataKit expected_headers와 일치해야 합니다.
OTEL_EXPORTER_OTLP_COMPRESSION OTLP 요청 압축 방식입니다. 호스트 간 전송 시 gzip으로 설정할 수 있습니다.
OTEL_EXPORTER_OTLP_TIMEOUT 단일 내보내기 타임아웃(밀리초)입니다. 10000

DataKit의 OTLP/HTTP 수집은 Protobuf만 지원합니다. http/protobuf를 사용하고 http/json은 사용하지 마십시오. 공통 endpoint와 특정 데이터 유형의 endpoint가 동시에 존재하는 경우, 특정 데이터 유형의 설정이 우선합니다.

샘플링 및 배치 전송 매개변수

환경 변수 설명 기본값 또는 예시
OTEL_TRACES_SAMPLER Trace 헤더 샘플러입니다. 기본값 parentbased_always_on; 비율 샘플링은 parentbased_traceidratio를 사용합니다.
OTEL_TRACES_SAMPLER_ARG 샘플러 매개변수입니다. 0.1은 루트 Trace의 10%를 샘플링함을 의미합니다.
OTEL_BSP_SCHEDULE_DELAY Span 배치 내보내기 간격(밀리초)입니다. 기본값 5000.
OTEL_BSP_MAX_QUEUE_SIZE 내보내기 대기 중인 Span 큐의 최대 크기입니다. 기본값 2048.
OTEL_BSP_MAX_EXPORT_BATCH_SIZE 배치당 최대 내보내기 Span 수입니다. 기본값 512.
OTEL_BSP_EXPORT_TIMEOUT Span 배치 내보내기 타임아웃(밀리초)입니다. 기본값 30000.
OTEL_METRIC_EXPORT_INTERVAL Metric 내보내기 간격(밀리초)입니다. 기본값 60000.

프로덕션 환경에서는 트래픽과 데이터 예산에 따라 샘플링 비율을 설정해야 합니다. 애플리케이션 측 헤더 샘플링과 DataKit 측 샘플링을 동시에 활성화하면 최종 유지율이 중첩되어 낮아지므로, 샘플링 위치를 통일하여 계획해야 합니다.

추가: 코드 방식 연결

이 문서에서는 앞서 설명한 코드 없는 방식을 우선 권장합니다. Resource, Exporter 또는 개별 계측을 정밀하게 제어해야 하는 경우 기존 SDK 코드 방식도 사용할 수 있습니다.

의존성 설치

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

예제 코드

OpenTelemetry는 비즈니스 모듈이 로드되기 전에 초기화되어야 합니다:

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

const resource = resourceFromAttributes({
  'service.name': 'orders-api',
  'service.version': '1.0.0',
  'deployment.environment.name': '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();
  require('./app');
}

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

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

코드 방식과 NODE_OPTIONS=--require .../register를 동시에 사용하여 두 개의 SDK를 중복 초기화하지 않도록 주의하십시오. 코드 방식을 선택한 경우, 코드 없는 방식의 등록 모듈 사전 로드 매개변수를 제거해야 합니다.

추가: Node.js Profile 확장

Node.js Profile은 표준 OpenTelemetry Trace 및 Metric 외에 성능 프로파일링 데이터를 보완하는 데 사용됩니다. 현재 지원되는 profile 유형:

  • wall;
  • heap.

실제 연결 시에는 먼저 wall을 활성화하여 수집 오버헤드와 전송 링크의 안정성을 확인한 후 필요에 따라 heap을 활성화하는 것이 좋습니다.

Profile 확장 설치

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

최소 연결 예제

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

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

async function main() {
  await profiler.start();
  require('./app');
}

process.once('SIGTERM', async () => {
  await profiler.shutdown();
  process.exit(0);
});

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

OpenTelemetry SDK와 함께 사용

애플리케이션이 이전 섹션의 SDK 코드 방식을 사용하는 경우, 동일한 Resource를 재사용할 수 있습니다:

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

const resource = resourceFromAttributes({
  'service.name': 'orders-api',
  'service.version': '1.2.3',
  'deployment.environment.name': '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();
  require('./app');
}

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

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

링크를 확인할 때 수동으로 한 번 수집을 트리거할 수 있습니다:

await profiling.collectOnce();

Profile 권장 설정

매개변수 기본값 설명
endpoint http://127.0.0.1:9529/profiling/v1/input Profile 업로드 주소입니다.
profileTypes ['wall', 'heap'] 수집 유형입니다. 먼저 ['wall']을 사용하는 것이 좋습니다.
intervalMillis 60000 주기적 수집 간격입니다.
wallDurationMillis 10000 단일 wall profile 지속 시간입니다.

기본적으로 확장은 60초마다 한 번씩 수집을 수행하며, wall profile은 10초 동안 지속되고 데이터를 /profiling/v1/input으로 전송합니다. 현재 exporter는 wall.pprof, space.pprof 및 이번 수집을 설명하는 event.json을 전송합니다. 여기서 profilerddtrace, familynodejs, formatpprof이며, Guance의 Node.js Profile 구문 분석 링크와의 호환성을 위해 사용됩니다.

실행 환경에 globalThis.fetch가 없는 경우 fetch 구현을 명시적으로 제공해야 합니다. 프로세스 종료 전에 profile이 손실되는 것을 방지하려면 종료 신호 처리기에서 shutdown()을 호출해야 합니다. Trace와 Metric만 필요한 경우 Profile 확장을 설치할 필요가 없습니다.

연결 확인

지원되는 계측 라이브러리를 통해 처리된 애플리케이션 경로를 요청한 후, DataKit 호스트에서 수신 로그를 확인합니다:

curl http://127.0.0.1:8080/
sudo tail -f /usr/local/datakit/log/gin.log | grep '/otel/v1/'

/otel/v1/traces에 대한 POST 요청이 나타나고 응답 코드가 200이면 DataKit이 Trace를 수신한 것입니다. 그런 다음 Guance의 애플리케이션 성능 모니터링(APM) > 분산 추적에서 service:order-service로 조회합니다.

데이터가 없는 경우, 자동 계측 패키지가 애플리케이션 프로젝트에 설치되었는지, NODE_OPTIONS가 실제 Node.js 프로세스에 전달되었는지, 등록 모듈이 애플리케이션 의존성보다 먼저 로드되었는지, 코드 경로가 지원되는 계측 라이브러리에 해당하는지, OTLP endpoint에 연결할 수 있는지 순서대로 확인합니다. 문제 해결 시 일시적으로 OTEL_LOG_LEVEL=debug로 설정할 수 있으며, 확인이 완료되면 info로 복원합니다.

Profile 인터페이스 연결 가능성을 확인하려면 다음을 실행합니다:

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

Profile 전송이 성공하면 확장 디버그 로그에 일반적으로 Datakit profiling export succeeded가 나타납니다. 그런 다음 Guance에서 서비스별로 Node.js Profile 데이터를 확인할 수 있습니다.

참고 자료

문서 평가

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