131 lines
4.5 KiB
Markdown
131 lines
4.5 KiB
Markdown
---
|
|
id: observability-opentelemetry
|
|
title: OpenTelemetry — 통합 추적/메트릭/로그
|
|
category: Coding
|
|
status: draft
|
|
source_trust_level: B
|
|
verification_status: conceptual
|
|
created_at: 2026-05-09
|
|
updated_at: 2026-05-09
|
|
tags: [observability, opentelemetry, tracing, vibe-coding]
|
|
tech_stack: { language: "TypeScript / OpenTelemetry SDK", applicable_to: ["Backend"] }
|
|
applied_in: []
|
|
aliases: [otel, distributed tracing, span, instrumentation]
|
|
---
|
|
|
|
# OpenTelemetry
|
|
|
|
> Vendor 중립 표준. 한 SDK 로 trace + metrics + logs 수집 → OTLP → Jaeger / Tempo / Datadog / Honeycomb 어디든. **auto-instrumentation 으로 80% 무료**, 비즈니스 span 만 직접.
|
|
|
|
## 📖 핵심 개념
|
|
- **Trace**: 요청 1건이 만든 span 트리.
|
|
- **Span**: 한 작업 (HTTP, DB query, function call).
|
|
- **Context propagation**: trace-id / span-id 가 외부 호출 / 큐로 이어짐.
|
|
- **Resource**: service name / version / instance.
|
|
- **Exporter**: OTLP gRPC/HTTP 가 표준.
|
|
|
|
## 💻 코드 패턴
|
|
|
|
### Node 부팅 시 셋업
|
|
```ts
|
|
// telemetry.ts (앱 import 보다 먼저)
|
|
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
|
|
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto';
|
|
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
|
|
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
import { Resource } from '@opentelemetry/resources';
|
|
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
|
|
|
|
const sdk = new NodeSDK({
|
|
resource: new Resource({
|
|
[ATTR_SERVICE_NAME]: 'user-service',
|
|
[ATTR_SERVICE_VERSION]: process.env.GIT_SHA,
|
|
}),
|
|
traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT }),
|
|
metricReader: new PeriodicExportingMetricReader({
|
|
exporter: new OTLPMetricExporter({ url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT }),
|
|
exportIntervalMillis: 30_000,
|
|
}),
|
|
instrumentations: [getNodeAutoInstrumentations()],
|
|
});
|
|
|
|
sdk.start();
|
|
|
|
process.on('SIGTERM', () => sdk.shutdown());
|
|
```
|
|
|
|
`node --require ./telemetry.ts app.ts` 로 실행.
|
|
|
|
자동으로 잡히는 것:
|
|
- HTTP server / client
|
|
- Express / Fastify / Koa
|
|
- pg / mysql / redis
|
|
- aws-sdk
|
|
- gRPC
|
|
|
|
### 비즈니스 span 직접
|
|
```ts
|
|
import { trace } from '@opentelemetry/api';
|
|
const tracer = trace.getTracer('user-service');
|
|
|
|
async function processOrder(orderId: string) {
|
|
return tracer.startActiveSpan('order.process', async (span) => {
|
|
span.setAttribute('order.id', orderId);
|
|
try {
|
|
const o = await fetchOrder(orderId); // 자동 child span
|
|
await chargePayment(o); // 자동 child span
|
|
span.setAttribute('order.amount', o.total);
|
|
return o;
|
|
} catch (e) {
|
|
span.recordException(e as Error);
|
|
span.setStatus({ code: 2 /* ERROR */ });
|
|
throw e;
|
|
} finally {
|
|
span.end();
|
|
}
|
|
});
|
|
}
|
|
```
|
|
|
|
### Span 안의 baggage (메타데이터 전파)
|
|
```ts
|
|
import { propagation, context } from '@opentelemetry/api';
|
|
|
|
const baggage = propagation.createBaggage({
|
|
user_id: { value: userId },
|
|
feature_flag_x: { value: 'on' },
|
|
});
|
|
context.with(propagation.setBaggage(context.active(), baggage), () => {
|
|
// 이 안의 모든 외부 호출이 user_id 전파
|
|
});
|
|
```
|
|
|
|
## 🤔 의사결정 기준
|
|
| 도입 단계 | 권장 |
|
|
|---|---|
|
|
| 모놀리스 단일 서비스 | auto-instrumentation 만 |
|
|
| 마이크로서비스 (>3) | auto + 비즈니스 span |
|
|
| 매우 큰 트래픽 (비용) | head sampling (1%) + tail sampling (errors) |
|
|
| Lambda / Edge | OpenTelemetry Lambda Layer |
|
|
| 자체 인프라 | OpenTelemetry Collector + Tempo/Jaeger |
|
|
| SaaS (Datadog/Honeycomb) | OTLP 호환 |
|
|
|
|
## ❌ 안티패턴
|
|
- **모든 함수에 span**: 폭증. 큰 단위 (request, transaction, queue job).
|
|
- **span attribute 에 PII**: 같은 redact 정책. 민감 X.
|
|
- **수동 trace-id 전파**: SDK 가 자동. 직접 설정 시 충돌.
|
|
- **sampling 100% prod**: 비용 폭증. 1-10% + tail sampling for errors.
|
|
- **resource attribute 없음**: 어떤 서비스 / 버전인지 모름.
|
|
- **shutdown 누락**: deploy 시 마지막 span 손실. SIGTERM handler.
|
|
- **로그와 trace 별개**: trace_id 를 로그에 같이 출력 → exemplar 로 그래프 점프.
|
|
|
|
## 🤖 LLM 활용 힌트
|
|
- "auto-instrumentation 먼저, 비즈니스 span 만 직접" 명시.
|
|
- service.name / version / env 리소스 필수.
|
|
- shutdown handler.
|
|
|
|
## 🔗 관련 문서
|
|
- [[Observability_Correlation_IDs]]
|
|
- [[Observability_RED_USE_Metrics]]
|