เมื่อรวบรวม Logs จากหลาย ๆ service เข้าสู่ Loki แล้ว ขั้นตอนต่อไปคือการค้นหาและวิเคราะห์ Logs เหล่านั้นเพื่อ debug ปัญหา, ตรวจจับ error หรือทำ alerting ซึ่งจำเป็นต้องใช้ภาษา query ที่ออกแบบมาโดยเฉพาะสำหรับ log data — LogQL คือคำตอบ
LogQL (Loki Query Language) คือภาษาค้นหา logs ของ Grafana Loki ที่ได้รับแรงบันดาลใจมาจาก PromQL (ของ Prometheus) ทำให้ผู้ที่คุ้นเคยกับ Prometheus สามารถเรียนรู้ได้เร็ว บทความนี้จะอธิบายโครงสร้าง LogQL, log stream selector, filter expressions, metric queries, และตัวอย่างการใช้งานจริงที่ช่วยให้คุณค้นหา logs ได้อย่างมีประสิทธิภาพ
LogQL คืออะไร และทำงานอย่างไร
LogQL เป็น query language ที่แบ่งการทำงานเป็น 2 ประเภทหลัก — Log Queries ที่คืนค่าเป็น log lines ตรง ๆ และ Metric Queries ที่แปลง logs เป็นตัวเลขสำหรับวาดกราฟหรือทำ alert การ query เริ่มต้นด้วย log stream selector ซึ่งใช้ labels (เช่น job, instance, env) เพื่อเลือก log streams ก่อน จากนั้นจึง filter เนื้อหาด้วย text matching หรือ regex
ข้อได้เปรียบของ LogQL คือการใช้ index เฉพาะ labels (ไม่ index เนื้อหา logs) ทำให้ประหยัด storage มาก แต่ผู้ใช้ต้องออกแบบ labels ให้ดีและหลีกเลี่ยงปัญหา high cardinality สำหรับ filter content ใช้การ scan แบบ compressed chunk ซึ่งเร็วพอสำหรับ time range ที่ไม่กว้างเกินไป
Log Stream Selector — เลือก stream ก่อนเสมอ
ทุก query ต้องเริ่มด้วย log stream selector ในเครื่องหมาย {} เพื่อระบุ labels ที่ต้องการ ตัวอย่างการใช้งาน operator:
# เลือก logs จาก job=nginx ทั้งหมด
{job="nginx"}
# matcher แบบ != (ไม่ใช่)
{job="nginx", env!="dev"}
# matcher แบบ regex =~ (matches)
{job=~"nginx|apache"}
# matcher แบบ regex !~ (not matches)
{job="api", path!~"/health.*"}
ข้อควรระวังคือต้องมี matcher อย่างน้อย 1 ตัวที่เป็น = หรือ =~ ที่ไม่ match กับค่าว่าง — ไม่สามารถใช้ {job=~".+"} โดด ๆ ได้ การออกแบบ labels ที่ดีควรมี cardinality ต่ำ (เช่น job, env, cluster) และหลีกเลี่ยง labels ที่มีค่าแตกต่างกันมาก (เช่น user_id, request_id)
Log Filter Expressions — กรองเนื้อหา
หลังจากเลือก stream แล้ว สามารถกรองเนื้อหา logs ต่อด้วย filter operators 4 แบบ — |= (contains), != (not contains), |~ (regex match), และ !~ (regex not match) filter เหล่านี้สามารถเชื่อมต่อกันได้หลายตัว และจะทำงานจากซ้ายไปขวา
# หา logs ที่มีคำว่า error
{job="api"} |= "error"
# exclude health check
{job="api"} |= "error" != "/health"
# regex match status code 5xx
{job="nginx"} |~ "status=5[0-9]{2}"
# หลาย filter เชื่อมกัน
{job="api"} |= "error" |= "database" != "retry"
เทคนิคสำคัญคือการเรียงลำดับ filter จาก selective ที่สุดก่อน (ลด log volume เร็วที่สุด) เพราะ Loki ต้อง scan chunks ตามลำดับ การใช้ |= แบบ exact string match จะเร็วกว่า regex มาก ควรเลือกใช้ regex เมื่อจำเป็นจริง ๆ เท่านั้น
Parser Expressions — แยก structured logs
LogQL รองรับ parser สำหรับแยก log ออกเป็น labels เพิ่มเติม ทำให้สามารถ filter หรือ aggregate ตาม field ได้ Parser หลัก ได้แก่ json, logfmt, regexp, pattern, และ unpack การแยก label แบบ on-the-fly นี้ไม่ได้ทำให้ index ใหญ่ขึ้น เพราะเกิดใน query time เท่านั้น
# JSON parser
{job="api"} | json | status_code="500"
# logfmt parser (key=value format)
{job="api"} | logfmt | duration > 1s
# pattern parser (เร็วกว่า regex)
{job="nginx"} | pattern `<ip> - - <_> "<method> <path> <_>" <status>`
| status >= 500
# regexp parser (ช้าแต่ยืดหยุ่น)
{job="app"} | regexp "user=(?P<user>[a-z]+)"
หลัง parse แล้ว สามารถใช้ operators เปรียบเทียบ เช่น >, <, >=, != กับ field ที่ได้ และยังใช้ | line_format เพื่อเปลี่ยนรูปแบบ output หรือ | label_format เพื่อเปลี่ยนชื่อ label ได้
Metric Queries — แปลง Logs เป็นตัวเลข
Metric queries แปลง log stream เป็น time series สำหรับวาดกราฟหรือตั้ง alert ฟังก์ชันหลักแบ่งเป็น 2 กลุ่ม — Range aggregations (ทำงานกับช่วงเวลา) และ Unwrap aggregations (ทำงานกับค่าตัวเลขที่ extract จาก logs)
# นับจำนวน logs ต่อวินาที (rate)
rate({job="api"} |= "error" [5m])
# นับจำนวน logs ทั้งหมดในช่วง
count_over_time({job="nginx"} [5m])
# group by label
sum by (status) (
rate({job="nginx"} | json [1m])
)
# unwrap: คำนวณค่าเฉลี่ย field ที่เป็นตัวเลข
avg_over_time(
{job="api"} | json | unwrap duration [5m]
)
Metric queries เหล่านี้สามารถใช้ใน Grafana dashboard หรือ Loki ruler สำหรับตั้ง alert ได้โดยตรง เช่น alert เมื่อ error rate เกิน 10/s ติดต่อกัน 5 นาที ซึ่งทำให้ Loki ไม่ใช่แค่ log storage แต่เป็น observability backend ที่สมบูรณ์
ตัวอย่าง Query ใช้งานจริง
ตัวอย่าง LogQL queries ที่ใช้บ่อยในงาน ops จริง:
# Top 10 endpoints ที่มี error 5xx
topk(10,
sum by (path) (
count_over_time(
{job="nginx"} | pattern `<_> "<_> <path> <_>" <status>`
| status =~ "5.."
[5m]
)
)
)
# p95 latency ต่อ service
quantile_over_time(0.95,
{env="prod"} | json | unwrap latency_ms [5m]
) by (service)
# หา request ที่ user กำหนด
{job="api"} | json | user_id="12345" | line_format "{{.timestamp}} {{.msg}}"
Best Practices สำหรับเขียน LogQL
แนวทางที่ช่วยให้ query ทำงานเร็วและประหยัด resource:
- ใช้ label selector ที่เฉพาะเจาะจงที่สุด — อย่าใช้
{env="prod"}โดด ๆ ถ้าเจาะจงลงไปที่ job ได้ - ลด time range เมื่อไม่จำเป็น — query 24 ชั่วโมงช้ากว่า 1 ชั่วโมงหลายเท่า
- เรียง filter จาก exact match ก่อน regex —
|= "error"เร็วกว่า|~ "err.*" - หลีกเลี่ยง parser ซ้อน ๆ — parse ครั้งเดียวใช้หลาย filter ดีกว่า
- ใช้
patternแทนregexpถ้า log มี format ที่แน่นอน เพราะเร็วกว่ามาก - ทดสอบ query บน Grafana Explore ก่อนนำไปใส่ใน dashboard หรือ alert rule
สรุป
LogQL เป็นภาษา query ที่ออกแบบมาให้ค้นหา logs ได้อย่างมีประสิทธิภาพ โดยเริ่มจาก label selector, filter เนื้อหา, parse structured logs, และแปลงเป็น metrics สำหรับ dashboard/alert ได้ในภาษาเดียว การเรียนรู้ LogQL ให้ลึกจะช่วยให้ debug ระบบได้เร็วและประหยัด storage ไปพร้อมกัน
เริ่มต้นจาก query พื้นฐานก่อน เช่น {job="..."} |= "error" แล้วค่อยเพิ่มความซับซ้อนเมื่อคุ้นเคย ฝึกเขียน query บน Grafana Explore ทุกวันจะช่วยให้เชี่ยวชาญได้เร็ว เพราะ observability stack เป็นทักษะที่ต้องมีสำหรับทีม DevOps และ SRE ยุคปัจจุบัน

