Promtail เป็น log collection agent ที่ Grafana Labs พัฒนาเพื่อเก็บ log จาก server หรือ container แล้วส่งต่อไปยัง Loki สำหรับจัดเก็บและค้นหา ด้วยโครงสร้างที่เน้น label discovery คล้าย Prometheus แต่ทำงานกับไฟล์ log แทน metric บทความนี้ครอบคลุมวิธีติดตั้ง, การกำหนด scrape target, pipeline แปลง log, relabeling และ best practice ที่ทีมใช้จริงเวลา deploy บน server หลากหลายประเภท
Promtail ทำอะไรและเหมาะกับกรณีไหน
หน้าที่หลักมี 3 อย่าง: ค้นหา log file ที่ต้องเก็บ (discovery), อ่านและตาม position (tail), และ push log ไป Loki พร้อม label agent ทำงานเป็น stateless process เบา กิน RAM ประมาณ 50-200 MB และสามารถ deploy เป็น sidecar, DaemonSet บน Kubernetes หรือ systemd service บน bare metal ก็ได้ จุดแข็งคือ integration กับ service discovery แบบ Prometheus — ดึง label ของ Kubernetes pod, Docker container, หรือ Consul service มาใส่ใน log stream อัตโนมัติ
กรณีที่ agent ตัวนี้ทำได้ดี: Kubernetes log collection (DaemonSet 1 pod/node), log file server แบบ traditional, systemd journal, และ Windows Event Log กรณีที่ควรใช้ Fluent Bit หรือ Vector แทน: pipeline ที่ต้องแปลง log ก่อนส่งออกหลาย destination (Loki + S3 + Kafka), หรือทีมที่มี standard log agent เดิมอยู่แล้ว
Architecture และ Data Flow
Promtail มี component ย่อย 3 ส่วน: Targets Discovery — หาว่าต้องอ่าน log จากที่ไหน (static paths, Kubernetes API, journal, syslog), Scraper + Pipeline — อ่าน log แล้ว parse, filter, เพิ่ม label ผ่าน stages, และ Client — push log ไป Loki ด้วย HTTP batch API พร้อม retry และ backpressure handling state ของ position file (positions.yaml) ถูกเก็บไว้ local เพื่อให้ start ใหม่แล้วอ่านต่อจากจุดเดิม ไม่อ่านซ้ำ
ตัวอย่าง Config พื้นฐาน
# promtail-config.yaml
server:
http_listen_port: 9080
positions:
filename: /var/lib/promtail/positions.yaml
clients:
- url: http://loki.monitoring.svc:3100/loki/api/v1/push
tenant_id: team-platform
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
host: web-01
__path__: /var/log/*.log
- job_name: nginx
static_configs:
- targets:
- localhost
labels:
job: nginx
app: api
__path__: /var/log/nginx/*.log
pipeline_stages:
- regex:
expression: '^(?P<remote>[\w\.]+).*"(?P<method>\w+) (?P<path>\S+).*" (?P<status>\d+)'
- labels:
method:
status:
ส่วน __path__ เป็น meta-label พิเศษที่บอกว่าต้องตาม log file ไหน รองรับ glob pattern และ symlink การตั้ง label เช่น job, host, app ควรมี cardinality ต่ำเพื่อไม่ให้ระเบิด index ของ Loki
Pipeline Stages — แปลง Log ก่อนส่ง
Pipeline คือชุด stage ที่รันตามลำดับ แต่ละ stage เปลี่ยน log line หรือ label ได้ stage ที่ใช้บ่อย:
- regex / json / logfmt — parse structure ของ log line ไปเก็บใน
extractedmap เพื่อใช้ใน stage ถัดไป - timestamp — ดึง field timestamp จาก log มาใช้แทนเวลา ingest (สำคัญเวลา replay log เก่า)
- labels — promote field ใน extracted map เป็น label (ระวัง cardinality)
- output — เปลี่ยน content ของ log line (เช่น เอาเฉพาะ message, ตัด prefix)
- match — branch pipeline ตามเงื่อนไข label หรือ selector
- drop — ทิ้ง log ที่ไม่ต้องการส่ง (noise filter)
- multiline — รวม log หลายบรรทัดเป็น entry เดียว (stack trace)
ตัวอย่าง Kubernetes DaemonSet Config
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
pipeline_stages:
- cri: {}
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_node_name
target_label: node
- source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- source_labels:
- __meta_kubernetes_pod_label_app
target_label: app
- source_labels:
- __meta_kubernetes_pod_name
target_label: pod
- action: replace
target_label: __path__
source_labels:
- __meta_kubernetes_pod_uid
- __meta_kubernetes_pod_container_name
separator: /
replacement: /var/log/pods/*$1/*.log
Config นี้ดึง label จาก Kubernetes pod meta แล้ว promote เป็น label log stream ด้วย relabel_configs ทำให้ Loki รู้ว่า log line ไหนมาจาก namespace, app, pod ใด — query ได้ทันที
Relabeling — ปรับ Label ก่อน Scrape
Relabel ทำงานบน meta-label (prefix __meta_) ที่ discovery ให้มา — เช่น namespace, pod name, container name, label ของ pod เทคนิคที่ใช้บ่อย: drop log ของบาง container (sidecar, istio-proxy), merge label หลายตัวเป็น label เดียว, rename label เพื่อให้ match กับ convention ของทีม
Action ที่ใช้ได้: replace, keep, drop, hashmod, labelmap, labeldrop, labelkeep — ตรงกันกับของ Prometheus แต่ทำงานบน log stream แทน metric target
Systemd Journal และ Syslog
สำหรับ server ที่ใช้ systemd ใช้ journal source ได้โดยตรง — ไม่ต้องตาม file path ตัวแทนอ่านจาก journal API แล้ว extract field เช่น _SYSTEMD_UNIT, _HOSTNAME, PRIORITY เป็น label นี่เป็นทางเลือกที่ดีสำหรับ log ของ service เช่น nginx.service, postgresql.service ที่ใช้ journal เป็นปลายทางมาตรฐาน
ส่วน syslog source รองรับ RFC5424 ผ่าน TCP/UDP port 1514 (default) เหมาะกับอุปกรณ์ network gear ที่ส่ง syslog ออกมา เช่น firewall, switch
Troubleshooting ที่พบบ่อย
- Log ไม่ส่งไป Loki — ตรวจ endpoint ใน
clients.url, network connectivity, tenant ID, และ/metricsของ Promtail ดูpromtail_sent_bytes_total - Position file หาย — start แล้วอ่าน log เก่าซ้ำทั้งหมด เหตุจาก volume ที่ mount ไม่ persistent — ต้อง bind path ของ
positions.filenameไป volume - Label cardinality สูง — เช็ค
loki_distributor_ingester_append_failures_totalถ้า active stream ต่อ tenant สูง ต้องลด label ที่ unique ต่อ request - Log ล่าช้า — ดู
promtail_stream_lag_secondsถ้าค่าสูง ตรวจว่า Loki push rate limit หรือ Promtail CPU ไม่พอ
สรุป
Agent ตัวนี้เหมาะกับทีมที่ตั้งต้น log aggregation บน Loki เพราะติดตั้งง่าย รู้จัก Kubernetes discovery ได้ดี และ pipeline stage เพียงพอสำหรับ parse log รูปแบบส่วนใหญ่ — ทั้ง JSON, Nginx access log, application log การวาง label design ให้ low cardinality และเข้าใจ relabel ตั้งแต่แรกช่วยให้ระบบ scale ได้ราบรื่น
สำหรับ workload ที่ต้องการ feature ขั้นสูง เช่น multiple output, advanced enrichment, หรือ buffer ขนาดใหญ่ ทีมควรพิจารณา Vector หรือ Fluent Bit แทน — ทั้งสองทำงานร่วมกับ Loki ได้เช่นกันและไม่ผูกกับ Grafana Labs ecosystem โดยตรง

