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

Continuous Profiler และ Error Tracking

tracing บอกคุณว่าตรงไหนที่ช้าหรือ fail — service ไหน, span ไหน — ส่วน Continuous Profiler กับ Error Tracking บอกคุณว่าทำไม ลงลึกถึงฟังก์ชันที่กิน CPU หรือ root cause ที่ถูก dedup มาจากกอง stack trace ที่ซ้ำกัน

Continuous Profiler รันตลอดเวลาบน production ด้วย overhead ต่ำ เก็บ CPU time, wall-time และ allocation ระดับโค้ด — ฟังก์ชันและ call stack แต่ละตัว ไม่ใช่แค่ aggregate ระดับ service เพราะ always-on แทนที่จะเป็นอะไรที่คุณเปิดทีหลังตอน investigate incident ข้อมูลจึงพร้อมอยู่แล้วตั้งแต่ก่อนคุณต้องการด้วยซ้ำ

profiler ผูก sample ของตัวเองกลับไปหา service, endpoint และแม้แต่ trace ที่เกิดขึ้นด้วย ความเชื่อมโยงนี้เองที่ทำให้ profiler มีประโยชน์ตอน debug request ที่ช้า — แทนที่จะเดาว่าส่วนไหนของ checkout-web ที่แพง คุณกระโดดจาก trace ที่ช้าตรงเข้าไปหา flame graph ว่าฟังก์ชันไหนกำลังรันอยู่และนานแค่ไหนระหว่าง request นั้น

# ddtrace's profiler starts alongside the tracer — no separate instrumentation needed
from ddtrace.profiling import Profiler
prof = Profiler()
prof.start()

พอทั้ง tracer และ profiler รันพร้อมกัน span ที่ช้าใน trace หนึ่งจะพาคุณตรงไปที่ flame graph ระดับฟังก์ชันของช่วงเวลานั้นพอดี — tracing จำกัดให้เหลือ span ไหน profiler จำกัดให้เหลือ บรรทัดโค้ดไหน

Error Tracking เอา error event ที่มาจาก trace และ log แล้ว group กับ dedup error ที่คล้ายกันให้เป็น issue เดียวอัตโนมัติ แทนที่จะปล่อยให้คุณต้องมาสังเกตเองว่า NullPointerException ตัวเดิมเกิดขึ้นไปแล้ว 482 ครั้งตลอดหนึ่งสัปดาห์ของ trace แต่ละ issue มี lifecycle ที่คุณจัดการได้ชัดเจน — ปกติคือ new, triaged และ resolved — error ที่เกิดซ้ำ ๆ จึงกลายเป็นสิ่งเดียวที่ทีมของคุณ track จนปิดได้ แทนที่จะเป็น event หลายร้อยตัวที่ดูเหมือนไม่เกี่ยวกันเลย

{
"issue": {
"fingerprint": "[email protected]_discount",
"status": "new",
"occurrences": 482,
"first_seen": "2026-07-01T10:03:00Z",
"last_seen": "2026-07-08T09:12:00Z",
"example_trace_ids": ["6141ee2f9a4d4b2e8f3c1a90", "9af23cd1b8e7f4a6c2d5e901"]
}
}

สังเกต field example_trace_ids — Error Tracking เก็บ link กลับไปหา example trace จริงของ issue นั้นไว้ด้วย คุณจึงกระโดดจาก “issue นี้เกิดไปแล้ว 482 ครั้ง” ตรงเข้าไปหา occurrence จริงหนึ่งตัวเพื่อดู context ของ request รอบ ๆ ได้

สองเครื่องมือนี้รวมกันแล้วปิดช่องว่างที่ tracing เพียงอย่างเดียวทิ้งไว้

  • Tracing — service ไหนและ span ไหนที่ช้าหรือ fail
  • Continuous Profiler — ฟังก์ชันไหนระดับโค้ดที่กิน CPU/wall-time/allocation ระหว่าง span ที่ช้านั้น
  • Error Tracking — span ที่ fail นั้นอยู่ใน issue ที่ dedup แล้วอันไหน และ issue นั้นอยู่ที่จุดไหนใน lifecycle new/triaged/resolved

ไม่มีเครื่องมือไหนแทนที่ tracing ทั้งคู่เริ่มจาก trace หรือ span แล้วลงลึกไปอีกระดับกว่าที่ “service ไหน” จะพาไปถึงได้

flowchart LR
  Trace[Slow or failing trace] --> Where[Tracing: which service, which span]
  Where --> Profiler[Continuous Profiler: which function, CPU/wall-time/allocations]
  Where --> ErrorTracking[Error Tracking: deduplicated issue, new/triaged/resolved]
  Profiler --> WhySlow[Why it is slow]
  ErrorTracking --> WhyFailing[Why it is failing]
From where to why
Continuous Profiler เพิ่มอะไรเข้ามาเหนือกว่าที่ tracing แสดงให้เห็นอยู่แล้ว
Error Tracking ทำอะไรกับ error ตัวเดิม 482 occurrence ที่กระจายอยู่ในหลาย trace
ทำไม Continuous Profiler ถึงถูกเรียกว่า "always-on" แทนที่จะเป็นอะไรที่เปิดใช้ตอน incident
สรุปเป็นประโยคเดียว tracing กับสองเครื่องมือนี้แบ่งหน้าที่กันยังไง