Home > Blog > tech

Observability และ OpenTelemetry คืออะไร? สอน Traces, Metrics, Logs แบบครบวงจร 2026

observability opentelemetry guide
Observability OpenTelemetry Guide 2026
2026-04-10 | tech | 3800 words

ในยุคที่ระบบซอฟต์แวร์เป็น Microservices และ Distributed Systems การที่แค่ดูว่า CPU เกิน 80% จะไม่เพียงพออีกต่อไป คุณต้องเข้าใจว่า Request ของ User เดินทางผ่านระบบอย่างไร ใช้เวลาเท่าไหร่ในแต่ละ Service และ Error เกิดขึ้นที่จุดไหน นี่คือหัวใจของ Observability

บทความนี้จะสอน Observability ตั้งแต่แนวคิดพื้นฐานจนถึงการ Implement ด้วย OpenTelemetry (OTel) ซึ่งเป็นมาตรฐานเปิดที่ได้รับการยอมรับมากที่สุดในปี 2026

Observability คืออะไร?

Observability คือความสามารถในการเข้าใจสถานะภายในของระบบ (Internal State) โดยดูจาก Output ที่ระบบปล่อยออกมา โดยไม่ต้องเข้าไป Debug ใน Production โดยตรง

แนวคิดนี้มาจาก Control Theory ในวิศวกรรม: ระบบจะ Observable ได้ก็ต่อเมื่อคุณสามารถอนุมานสถานะภายในจากข้อมูลที่ออกมาจากระบบได้

Observability vs Monitoring

ด้านMonitoringObservability
คำถาม"มีอะไรพังไหม?""ทำไมถึงพัง?" + "ตรงไหนพัง?"
แนวทางตั้ง Alert ล่วงหน้า (Known unknowns)สำรวจข้อมูลเพื่อหาปัญหาใหม่ (Unknown unknowns)
ข้อมูลMetrics + AlertsTraces + Metrics + Logs + Events
เหมาะกับMonolithic, ระบบง่ายMicroservices, Distributed Systems

Three Pillars of Observability

Observability ตั้งอยู่บน 3 เสาหลัก (Three Pillars) ที่ทำงานร่วมกัน:

1. Logs (บันทึกเหตุการณ์)

Log คือข้อความที่บันทึกเหตุการณ์ที่เกิดขึ้นในระบบ ณ เวลาใดเวลาหนึ่ง เป็นข้อมูลที่ละเอียดที่สุด

# Unstructured Log (แบบเก่า)
2026-04-10 14:30:22 ERROR Failed to process order #12345

# Structured Log (แบบใหม่ — JSON)
{
  "timestamp": "2026-04-10T14:30:22Z",
  "level": "ERROR",
  "message": "Failed to process order",
  "service": "order-service",
  "order_id": "12345",
  "trace_id": "abc123def456",
  "span_id": "span789",
  "user_id": "u-5678",
  "error": "PaymentGatewayTimeout"
}
Best Practice: ใช้ Structured Logging (JSON) เสมอ จะทำให้ค้นหา กรอง และวิเคราะห์ได้ง่ายมากขึ้น และควรใส่ trace_id เพื่อเชื่อมโยง Log กับ Trace

2. Metrics (ตัวเลขวัดผล)

Metrics คือค่าตัวเลขที่วัดได้ตามเวลา (Time-series data) เช่น จำนวน Request, Response Time, Error Rate

# Metric Types
Counter   — ค่าที่เพิ่มขึ้นเรื่อยๆ (เช่น total_requests)
Gauge     — ค่าที่ขึ้นลงได้ (เช่น current_memory_usage)
Histogram — กระจายตัวของค่า (เช่น request_duration_seconds)

# ตัวอย่าง Prometheus Metrics
http_requests_total{method="GET", endpoint="/api/orders", status="200"} 15234
http_request_duration_seconds_bucket{le="0.1"} 12000
http_request_duration_seconds_bucket{le="0.5"} 14500
http_request_duration_seconds_bucket{le="1.0"} 15100

3. Traces (การติดตาม Request)

Trace คือการบันทึกเส้นทางของ Request ตั้งแต่ต้นจนจบ ผ่านทุก Service ที่เกี่ยวข้อง ทำให้เห็นภาพรวมของ Distributed Transaction

# Trace ประกอบด้วย Spans
Trace ID: abc123def456
├── Span: API Gateway (12ms)
│   ├── Span: Auth Service (3ms)
│   ├── Span: Order Service (45ms)
│   │   ├── Span: Database Query (8ms)
│   │   └── Span: Payment Service (30ms)
│   │       └── Span: External Payment API (25ms)
│   └── Span: Notification Service (5ms)
Total Duration: 52ms

OpenTelemetry (OTel) คืออะไร?

OpenTelemetry คือโปรเจกต์ Open Source ภายใต้ CNCF (Cloud Native Computing Foundation) ที่เป็นมาตรฐานสำหรับการเก็บข้อมูล Observability ทั้ง Traces, Metrics และ Logs โดยรวม OpenTracing กับ OpenCensus เข้าด้วยกัน

OTel เป็นโปรเจกต์ที่มี Activity สูงเป็นอันดับ 2 ใน CNCF (รองจาก Kubernetes) และเป็นมาตรฐานที่ Vendor ทุกเจ้ารองรับ

OTel Architecture

┌────────────────────────────────────────────┐
│           Your Application                  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐ │
│  │ OTel API │  │ OTel SDK │  │ Auto-    │ │
│  │          │→ │          │→ │ Instrument│ │
│  └──────────┘  └──────────┘  └──────────┘ │
└──────────────────┬─────────────────────────┘
                   │ OTLP (OpenTelemetry Protocol)
                   ▼
         ┌─────────────────┐
         │  OTel Collector  │
         │ ┌─────┐┌──────┐ │
         │ │Recv ││Proc  │ │
         │ └─────┘└──────┘ │
         │ ┌──────────────┐ │
         │ │  Exporters   │ │
         │ └──────────────┘ │
         └────┬───┬───┬────┘
              │   │   │
     ┌────────┘   │   └────────┐
     ▼            ▼            ▼
  Jaeger     Prometheus     Loki
 (Traces)    (Metrics)     (Logs)
     └────────┬───┘────────┘
              ▼
          Grafana (UI)

OTel SDK: Auto-Instrumentation

วิธีที่ง่ายที่สุดในการเริ่มต้น — ไม่ต้องแก้ Code เลย:

Python

# ติดตั้ง
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install

# รัน Application พร้อม Auto-instrumentation
opentelemetry-instrument \
  --service_name my-python-app \
  --exporter_otlp_endpoint http://otel-collector:4317 \
  python app.py

# รองรับ Framework: Flask, Django, FastAPI, SQLAlchemy, Redis, etc.

Java

# ดาวน์โหลด Java Agent
wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

# รัน Application พร้อม Agent
java -javaagent:opentelemetry-javaagent.jar \
  -Dotel.service.name=my-java-app \
  -Dotel.exporter.otlp.endpoint=http://otel-collector:4317 \
  -jar myapp.jar

# รองรับ: Spring Boot, Quarkus, Micronaut, JDBC, Kafka, gRPC, etc.

Node.js

# ติดตั้ง
npm install @opentelemetry/auto-instrumentations-node \
  @opentelemetry/sdk-node \
  @opentelemetry/exporter-trace-otlp-grpc

# สร้าง tracing.js
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');

const sdk = new NodeSDK({
  serviceName: 'my-node-app',
  traceExporter: new OTLPTraceExporter({ url: 'http://otel-collector:4317' }),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

# รัน
node --require ./tracing.js app.js

Go

// ติดตั้ง
go get go.opentelemetry.io/otel
go get go.opentelemetry.io/otel/sdk
go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc

// Initialize Tracer Provider
func initTracer() func() {
    ctx := context.Background()
    exporter, _ := otlptracegrpc.New(ctx,
        otlptracegrpc.WithEndpoint("otel-collector:4317"),
        otlptracegrpc.WithInsecure(),
    )
    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exporter),
        sdktrace.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceNameKey.String("my-go-app"),
        )),
    )
    otel.SetTracerProvider(tp)
    return func() { tp.Shutdown(ctx) }
}

Manual Instrumentation

สำหรับ Business Logic ที่ต้องการ Trace เฉพาะจุด:

# Python Manual Span
from opentelemetry import trace

tracer = trace.get_tracer("order-service")

def process_order(order_id: str):
    with tracer.start_as_current_span("process_order") as span:
        span.set_attribute("order.id", order_id)
        span.set_attribute("order.type", "standard")

        # ขั้นตอนย่อย
        with tracer.start_as_current_span("validate_order"):
            validate(order_id)

        with tracer.start_as_current_span("charge_payment") as pay_span:
            result = charge(order_id)
            pay_span.set_attribute("payment.method", result.method)
            pay_span.set_attribute("payment.amount", result.amount)

        with tracer.start_as_current_span("send_notification"):
            notify(order_id)

        span.set_status(trace.Status(trace.StatusCode.OK))

W3C Trace Context

OpenTelemetry ใช้ W3C Trace Context เป็นมาตรฐานในการส่ง Trace ID ข้าม Service (Context Propagation):

# HTTP Header ที่ OTel ใส่ให้อัตโนมัติ
traceparent: 00-abc123def456789-span789abc-01
tracestate: vendor1=value1,vendor2=value2

# Format: version-trace_id-parent_span_id-trace_flags
# trace_id: 32 hex characters (16 bytes)
# parent_span_id: 16 hex characters (8 bytes)
# trace_flags: 01 = sampled

OpenTelemetry Collector

OTel Collector เป็นตัวกลางที่รับ Telemetry Data จาก Application แล้วส่งต่อไป Backend ทำหน้าที่เป็น Proxy/Pipeline:

# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 5s
    send_batch_size: 1024
  memory_limiter:
    check_interval: 1s
    limit_mib: 512
  attributes:
    actions:
      - key: environment
        value: production
        action: upsert

exporters:
  otlp/jaeger:
    endpoint: jaeger:4317
    tls:
      insecure: true
  prometheus:
    endpoint: 0.0.0.0:8889
  loki:
    endpoint: http://loki:3100/loki/api/v1/push

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [otlp/jaeger]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [prometheus]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, batch, attributes]
      exporters: [loki]
ทำไมต้องใช้ Collector? แทนที่จะให้ App ส่งตรงไป Backend — Collector ช่วย Buffering, Retry, Batching, Filtering และเปลี่ยน Backend ได้โดยไม่ต้องแก้ Code ของ App

Backends: เก็บข้อมูลที่ไหน?

ประเภทBackendจุดเด่น
TracesJaegerOpen Source, UI ดี, ค้นหา Trace ง่าย
TracesTempo (Grafana)ต้นทุนต่ำ ใช้ Object Storage, Scale ดี
TracesZipkinเก่าแก่ เสถียร Community ใหญ่
MetricsPrometheusมาตรฐาน Pull-based, PromQL ทรงพลัง
MetricsMimir (Grafana)Long-term storage, Multi-tenant
LogsLoki (Grafana)เหมือน Prometheus แต่สำหรับ Logs, ต้นทุนต่ำ
LogsElasticsearchFull-text search, Kibana UI
All-in-oneGrafana CloudManaged service ครบจบ

Grafana: Unified Dashboard

Grafana เป็น UI ที่เชื่อมทุกอย่างเข้าด้วยกัน สามารถดู Traces, Metrics, Logs ในหน้าจอเดียว และ Correlate ข้อมูลข้ามกันได้:

# Docker Compose สำหรับ Full Observability Stack
version: '3.8'
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:latest
    volumes:
      - ./otel-config.yaml:/etc/otelcol/config.yaml
    ports:
      - "4317:4317"   # OTLP gRPC
      - "4318:4318"   # OTLP HTTP

  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686" # Jaeger UI
      - "4317"        # OTLP

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_AUTH_ANONYMOUS_ENABLED=true

Distributed Tracing Deep Dive

Distributed Tracing เป็นส่วนที่สำคัญที่สุดของ Observability เพราะช่วยให้เห็นปัญหาที่ Metrics และ Logs เพียงอย่างเดียวจะไม่เห็น:

ตัวอย่าง: หา Bottleneck

# Trace แสดงให้เห็นว่า Payment Service ช้า
GET /api/checkout (total: 2.3s)
├── auth-service: verify-token (15ms)
├── cart-service: get-items (45ms)
├── inventory-service: check-stock (120ms)
├── payment-service: process-payment (1,800ms)  ← BOTTLENECK!
│   ├── fraud-check (200ms)
│   ├── gateway-call (1,500ms)  ← External API ช้า
│   └── save-transaction (100ms)
└── notification-service: send-email (50ms)

# โดย Metrics จะเห็นแค่ "checkout API ช้า 2.3s"
# แต่ Trace บอกได้ว่าช้าเพราะ Payment Gateway

SLO / SLI / Error Budget

OpenTelemetry ช่วยวัด SLI (Service Level Indicators) เพื่อกำหนด SLO (Service Level Objectives):

คำศัพท์ความหมายตัวอย่าง
SLIค่าที่วัดได้จริง99.2% ของ Request สำเร็จ
SLOเป้าหมายที่ตั้งไว้99.9% availability
SLAสัญญากับลูกค้า99.5% uptime หรือคืนเงิน
Error BudgetDowntime ที่ยอมรับได้0.1% = 43.8 นาที/เดือน
# PromQL สำหรับ SLI
# Availability SLI
sum(rate(http_requests_total{status!~"5.."}[30d]))
/
sum(rate(http_requests_total[30d]))

# Latency SLI (p99 < 500ms)
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

Observability-Driven Development

แนวคิดสมัยใหม่ที่ว่า "เขียน Instrumentation ก่อน เขียน Code":

  1. Define SLOs — กำหนดเป้าหมายของระบบก่อน
  2. Instrument First — เพิ่ม Traces/Metrics ตั้งแต่เริ่มเขียน Code
  3. Test in Production — ใช้ Observability เพื่อ Validate ใน Production
  4. Alert on SLOs — Alert เมื่อ Error Budget ใกล้หมด ไม่ใช่ Alert ทุกอย่าง

Cost of Observability

Observability ใช้ทรัพยากรมาก — Traces โดยเฉพาะ:

กลยุทธ์ลดค่าใช้จ่าย

# OTel Collector: Tail-based Sampling
processors:
  tail_sampling:
    decision_wait: 10s
    policies:
      - name: errors
        type: status_code
        status_code:
          status_codes: [ERROR]
      - name: slow-traces
        type: latency
        latency:
          threshold_ms: 1000
      - name: percentage
        type: probabilistic
        probabilistic:
          sampling_percentage: 10

Vendor Comparison

Platformจุดเด่นPricing Modelเหมาะกับ
DatadogAll-in-one, APM ดีมาก, UI สวยPer host + ingestionEnterprise ที่มีงบ
New RelicFree tier ใจกว้าง, Full-stackPer GB ingestedStartup ถึง Enterprise
HoneycombQuery ทรงพลัง, BubbleUpPer eventทีมที่เน้น Debug
Grafana CloudOpen Source-based, ยืดหยุ่นPer metric/log/traceทีมที่ชอบ OSS
Self-hostedฟรี ควบคุมเต็มที่ค่า Infra เองทีมที่มี DevOps แข็ง

สรุป

Observability ไม่ใช่แค่เรื่องของ Tool แต่เป็นวิธีคิดในการออกแบบระบบ ในปี 2026 OpenTelemetry ได้กลายเป็นมาตรฐานที่ไม่มีใครหลีกเลี่ยงได้ ไม่ว่าจะใช้ Vendor ไหน ข้อมูลที่เก็บด้วย OTel จะ Portable และไม่ถูก Lock-in

เริ่มต้นด้วย Auto-instrumentation ก่อน — ใช้เวลาไม่ถึง 10 นาทีก็ได้ Traces แรก จากนั้นค่อยเพิ่ม Custom Spans, Metrics, และ Structured Logs ตามความต้องการของทีม


Back to Blog | iCafe Forex | SiamLanCard | Siam2R