ข้ามไปยังเนื้อหา

Structured Logging and Log Facets

structured log (JSON) ทำให้ Processing Pipeline ดึง attribute แบบมี type ได้เชื่อถือได้ แทนที่จะพึ่ง Grok parsing ของข้อความอิสระที่เปราะบาง และ attribute พวกนั้นกลายเป็น Facet ที่ filter, group และ aggregate ได้ใน Logs Explorer — แต่ทำได้เฉพาะ log ที่เข้า index จริง ๆ เท่านั้น

Grok Parser ดึง attribute ออกจากบรรทัดที่ไม่มีโครงสร้างแบบ 2024-01-15 ERROR user=42 duration=812ms checkout failed ได้ แต่ pattern ทุกตัวคือการเดิมพันว่า log จะคงรูปแบบนั้นเป๊ะ ๆ ตลอด แค่เพิ่มคำ, สลับตำแหน่ง field หรือมี service หนึ่งที่ log ต่างจากอีก service เล็กน้อย Grok pattern ก็หยุด match แบบเงียบ ๆ — หรือแย่กว่านั้นคือ match ผิด

structured log หลบปัญหานี้ไปเลย เพราะ field มีชื่อและ type อยู่แล้วก่อนที่ Datadog จะเห็นด้วยซ้ำ:

{
"timestamp": "2024-01-15T10:22:31Z",
"level": "error",
"service": "checkout-api",
"user": { "id": 42 },
"duration_ms": 812,
"message": "checkout failed"
}

ตรงนี้ Processing Pipeline ไม่ต้องใช้ Grok Parser เลยสำหรับ field ที่เป็น key ที่มีชื่ออยู่แล้ว — level, service, user.id, duration_ms มาเป็น attribute แบบมี type ให้อัตโนมัติ Grok ยังมีประโยชน์กับส่วนของ message ที่ยังเป็นข้อความอิสระอยู่ (field message เอง หรือ log จากระบบที่คุณคุม format ไม่ได้) แต่เส้นทางที่เชื่อถือได้สำหรับอะไรก็ตามที่คุณคุมได้ คือ log เป็น JSON ตั้งแต่แรก

พอ log มี attribute ที่มีโครงสร้างแล้ว — ไม่ว่าจะดึงมาด้วย Grok หรือเป็น JSON field แต่แรก — Datadog แปลง attribute นั้นให้เป็น Facet ได้ คือ field ที่ Logs Explorer มองว่า filter, group และ chart ได้ เหมือนกับที่เว็บไซต์ทั่วไป facet ผลการค้นหา การ facet บน status_code ทำให้ filter เป็น status_code:500 ได้ หรือ group ผลค้นหาตาม status_code เพื่อดู breakdown ส่วนการ facet บน service ทำให้แบ่ง query ไหนก็ได้ตาม service ที่สร้าง log แต่ละตัว

structure ที่สอดคล้องกันข้าม service คือสิ่งที่ทำให้ facet มีประโยชน์จริงในระดับ organization ถ้า service หนึ่งเรียก field นี้ว่า status_code อีกตัวเรียก httpStatus และอีกตัวฝังไว้ในข้อความที่ไม่ได้ parse คุณ facet ข้ามทั้งสามตัวให้สอดคล้องกันไม่ได้ นี่คือเหตุผลที่การ remap สำคัญ ในการทำให้ log มีรูปร่างสอดคล้องกัน:

  • Status Remapper — map field severity ที่แต่ละ service เรียกไม่เหมือนกัน (level, severity, log.level, …) เข้ากับ facet status มาตรฐานของ Datadog เพื่อให้ “ขอดู error ทั้งหมดจากทุก service” เป็น query เดียว แทนที่จะเป็น query ละ service
  • Message Remapper — กำหนดว่า attribute ไหนคือ message หลักที่มนุษย์อ่านได้ของ log เพื่อให้ Logs Explorer แสดงคอลัมน์ message ที่สมเหตุสมผล ไม่ว่า service ต้นทางจะเรียก field นั้นว่าอะไร

นี่คือประเด็นที่ผูกกลับไปหาบทที่แล้วโดยตรง Log Analytics — การ breakdown แบบ group-by, computed measure และ aggregation อื่น ๆ บน facet — ทำงานได้เฉพาะกับ log ที่ถูก index จริง ๆ เท่านั้น Exclusion Filter ที่กัน log level:debug ไม่ให้เข้า index ไม่ได้แค่ซ่อน log พวกนั้นจากการค้นหาตรง ๆ เท่านั้น แต่ยังหมายความว่า log พวกนั้นปรากฏใน Log Analytics aggregation ไหนไม่ได้เลย เพราะไม่มีอะไรถูก index ให้ aggregate

ถ้าต้องการ slice-and-dice field บน log ที่ปกติถูก Exclusion Filter drop ทิ้ง คุณมีสามทางเลือกเดียวกับที่บทก่อนให้ไว้แล้ว มาใช้กับความต้องการนี้โดยเฉพาะ:

  1. ปิด Exclusion Filter ชั่วคราวหรือทำให้แคบลง เพื่อให้ log ที่ต้องวิเคราะห์ถูก index จริง
  2. generate log-based metric แทน — COUNT หรือ DISTRIBUTION ที่คำนวณจาก ingest stream เต็ม ๆ ให้ trend ได้โดยไม่ต้อง index log เลย
  3. Rehydrate ช่วงเวลาที่เกี่ยวข้องจาก Log Archive เข้า temporary index รันการวิเคราะห์ แล้วปล่อยให้ temporary index หมดอายุไป
Want to group-by @http.status_code on logs currently excluded by level:debug filter?
-> Option 1: relax the Exclusion Filter (costs indexing $$, gets full Log Analytics)
-> Option 2: log-based metric on @http.status_code (cheap, but only pre-defined aggregations)
-> Option 3: Rehydrate the time range (temporary cost, full Log Analytics for that window)
flowchart LR
  A["JSON log\nlevel, service, duration_ms"] --> B[Processing Pipeline\nStatus Remapper, Message Remapper]
  B --> C[Typed attributes]
  C --> D[Facets in Logs Explorer\nfilter / group / chart]
  D --> E{Log actually indexed?}
  E -->|yes| F[Log Analytics: group-by,\ncomputed measures work]
  E -->|no, excluded| G[No Log Analytics\nuse log-based metric or Rehydration]
From structured field to facet to analytics
ทำไม JSON field ที่เป็น native ถึงเชื่อถือได้กว่า field ที่ Grok parse จากข้อความอิสระ
Facet ใน Logs Explorer คืออะไร
Status Remapper ทำอะไรให้กับหลาย service พร้อมกัน
field หนึ่งถูก exclude จาก index ด้วย Exclusion Filter Log Analytics group-by บน field นั้นจะเป็นยังไง