Correlation IDs แบบครบวงจรอธิบายวิธีสร้าง ID ใน frontend ส่งผ่าน APIs และรวมไว้ในล็อก เพื่อให้ฝ่ายซัพพอร์ตติดตามปัญหาได้อย่างรวดเร็ว

ฝ่ายซัพพอร์ตแทบจะไม่มีรายงานบั๊กที่ชัดเจน ผู้ใช้อาจบอกว่า "กด Pay แล้วล้มเหลว" แต่การคลิกเดียวอาจผ่านมาเบราว์เซอร์ เกตเวย์ API เซอร์วิสชำระเงิน ฐานข้อมูล และงานแบ็คกราวด์ แต่ละส่วนบันทึกแค่ชิ้นของเรื่อง ณ เวลาและเครื่องที่ต่างกัน หากไม่มีป้ายร่วมเดียว คุณจะต้องเดาว่าแถวล็อกไหนเกี่ยวข้องกัน
correlation ID คือป้ายร่วมนี้ มันเป็น ID เดียวที่แนบกับการกระทำของผู้ใช้หนึ่งรายการ (หรือเวิร์กโฟลว์เชิงตรรกะหนึ่งรายการ) และถูกส่งผ่านทุกคำขอ การ retry และการเรียกข้ามเซอร์วิส เมื่อมีการครอบคลุมแบบ end-to-end จริง ๆ คุณสามารถเริ่มจากคำร้องเรียนของผู้ใช้แล้วดึงไทม์ไลน์เต็มข้ามระบบได้
คนมักสับสนกับ ID ที่คล้ายกัน นี่คือการแยกที่ชัดเจน:
สิ่งที่ "ดี" ดูตรงไปตรงมา: ผู้ใช้รายงานปัญหา คุณขอ correlation ID ที่แสดงใน UI (หรือในหน้าซัพพอร์ต) แล้วใครก็ได้ในทีมค้นหาเรื่องเต็มได้ในไม่กี่นาที คุณจะเห็นคำขอจาก frontend การตอบจาก API ขั้นตอน backend และผลจากฐานข้อมูล ทั้งหมดถูกเชื่อมด้วย ID เดียวกัน
ก่อนจะสร้างอะไร ให้ตกลงกฎไม่กี่ข้อ ถ้าทีมแต่ละทีมเลือกชื่อ header หรือฟิลด์ล็อกต่างกัน ฝ่ายซัพพอร์ตก็ยังต้องเดา
เริ่มจากชื่อหลักชื่อเดียวและใช้มันทุกที่ ตัวเลือกที่พบบ่อยคือ HTTP header อย่าง X-Correlation-Id พร้อมฟิลด์ล็อกเชิงโครงสร้างอย่าง correlation_id เลือกการสะกดและตัวพิมพ์ตัวเดียว จดเอกสาร และตรวจสอบว่า reverse proxy หรือเกตเวย์จะไม่เปลี่ยนชื่อหรือทิ้ง header นั้น
เลือกฟอร์แมตรที่สร้างง่ายและแชร์ในตั๋วหรือแชทได้ปลอดภัย UUID ทำงานได้ดีเพราะไม่ชนและเรียบง่าย เก็บให้สั้นพอที่จะคัดลอก แต่ไม่สั้นจนเสี่ยงชน ความสม่ำเสมอสำคัญกว่าความฉลาดเฉพาะตัว
นอกจากนี้ ให้กำหนดว่าต้องแสดง ID ที่ไหนเพื่อให้มนุษย์ใช้งานได้จริง ในทางปฏิบัติ นั่นหมายความว่ามันต้องปรากฏในคำขอ ล็อก และผลลัพธ์ข้อผิดพลาด และค้นหาได้ในเครื่องมือที่ทีมใช้
กำหนดระยะเวลาที่ ID หนึ่งตัวควรมีชีวิต ค่าเริ่มต้นที่ดีคือหนึ่งการกระทำของผู้ใช้ เช่น "กด Pay" หรือ "บันทึกโปรไฟล์" สำหรับเวิร์กโฟลว์ยาวที่ข้ามเซอร์วิสและคิว ให้เก็บ ID เดิมจนกว่าเวิร์กโฟลว์จะจบ แล้วเริ่มใหม่สำหรับการกระทำถัดไป หลีกเลี่ยงการใช้ "ID เดียวสำหรับทั้ง session" เพราะการค้นหาจะมีเสียงดังเร็ว
กฎแข็งข้อหนึ่ง: ห้ามใส่ข้อมูลส่วนบุคคลใน ID เลย ไม่มีอีเมล เบอร์โทร รหัสผู้ใช้ หรือเลขคำสั่ง ถ้าต้องการบริบทนั้น ให้ล็อกในฟิลด์แยกต่างหากที่มีการควบคุมความเป็นส่วนตัว
ตำแหน่งที่ง่ายที่สุดในการเริ่ม correlation ID คือช่วงที่ผู้ใช้เริ่มการกระทำที่คุณสนใจ: กด "บันทึก" ส่งฟอร์ม หรือลูปที่กระตุ้นหลายคำขอ ถ้ารอให้ backend สร้าง คุณมักจะเสียส่วนแรกของเรื่อง (ข้อผิดพลาด UI, retry, คำขอที่ยกเลิก)
ใช้ฟอร์แมตรันดอมและไม่ซ้ำ UUID v4 เป็นตัวเลือกทั่วไปเพราะสร้างง่ายและโอกาสชนต่ำ เก็บให้ทึบ (ไม่ใส่ชื่อผู้ใช้ อีเมล หรือ timestamp) เพื่อไม่รั่วข้อมูลส่วนตัวลงใน header และล็อก
ถือว่า "เวิร์กโฟลว์" เป็นการกระทำของผู้ใช้หนึ่งรายการที่อาจกระตุ้นหลายคำขอ: ตรวจสอบ, อัปโหลด, สร้างเรคอร์ด แล้วรีเฟรชลิสต์ สร้าง ID หนึ่งตัวเมื่อเวิร์กโฟลว์เริ่ม แล้วเก็บมันจนกว่าเวิร์กโฟลว์จะจบ (สำเร็จ ล้มเหลว หรือผู้ใช้ยกเลิก) รูปแบบง่าย ๆ คือเก็บไว้ใน state ของคอมโพเนนต์หรือออบเจกต์ context คำขอขนาดเล็ก
ถ้าผู้ใช้เริ่มการกระทำเดียวกันสองครั้ง ให้สร้าง correlation ID ใหม่สำหรับครั้งที่สอง จะช่วยให้ซัพพอร์ตแยกความต่างระหว่าง "คลิกเดียวแล้ว retry" กับ "ส่งสองครั้งแยกกัน"
เพิ่ม ID ไปกับทุกการเรียก API ที่เวิร์กโฟลว์นั้นกระตุ้น โดยปกติผ่าน header เช่น X-Correlation-ID ถ้าคุณใช้ไคลเอนต์ API ร่วม (fetch wrapper, Axios instance ฯลฯ) ให้ส่ง ID หนึ่งครั้งแล้วให้ไคลเอนต์ฉีดเข้าไปในทุกคำขอ
// 1) when the user action starts
const correlationId = crypto.randomUUID(); // UUID v4 in modern browsers
// 2) pass it to every request in this workflow
await api.post('/orders', payload, {
headers: { 'X-Correlation-ID': correlationId }
});
await api.get('/orders/summary', {
headers: { 'X-Correlation-ID': correlationId }
});
ถ้า UI ทำคำขอแบ็คกราวด์ที่ไม่เกี่ยวข้องกับการกระทำ (polling, analytics, auto-refresh) อย่าใช้ ID เดียวกับเวิร์กโฟลว์นั้น เก็บ correlation IDs ให้เป็นจังหวะเดียว เรื่องเดียวต่อ ID
เมื่อคุณสร้าง correlation ID ในเบราว์เซอร์ งานของคุณคือ: มันต้องออกจาก frontend กับทุกคำขอและมาถึงไม่เปลี่ยนแปลงในทุกขอบเขตของ API นี่คือจุดที่มักพังเมื่อทีมเพิ่ม endpoint ใหม่, client ใหม่, หรือ middleware ใหม่
ค่าเริ่มต้นที่ปลอดภัยที่สุดคือ header HTTP บนทุกการเรียก (เช่น X-Correlation-Id) Header เพิ่มได้ง่ายที่จุดเดียว (fetch wrapper, Axios interceptor, เลเยอร์เครือข่ายมือถือ) และไม่ต้องเปลี่ยน payload
ถ้าคุณมีคำขอข้ามต้นกำเนิด (cross-origin) ให้แน่ใจว่า API อนุญาต header นั้น มิฉะนั้นเบราว์เซอร์อาจบล็อกอย่างเงียบ ๆ และคุณจะคิดว่ากำลังส่งอยู่ทั้งที่ไม่ได้ส่ง
ถ้าจำเป็นต้องใส่ ID ใน query string หรือ request body (บางเครื่องมือภายนอกหรือการอัปโหลดไฟล์บังคับ) ให้ทำให้สม่ำเสมอและเขียนลงเอกสาร เลือกชื่อฟิลด์เดียวและใช้ทุกที่ อย่าใช้สลับกันเช่น correlationId, requestId, และ cid ขึ้นอยู่กับ endpoint
การ retry เป็นกับดักอีกอย่างหนึ่ง ถ้าเป็นการ retry ของการกระทำเดียวกัน ให้เก็บ correlation ID เดิม เช่น: ผู้ใช้กด "บันทึก" แล้วเน็ตล่ม client retry การ POST ซัพพอร์ตควรเห็นเส้นทางเชื่อมเดียว ไม่ใช่สามเส้นที่ไม่เกี่ยวข้อง การคลิกใหม่ของผู้ใช้ (หรืองานแบ็คกราวด์ใหม่) ควรได้ ID ใหม่
สำหรับ WebSockets ให้ใส่ ID ในซองข้อความไม่ใช่แค่ในการจับมือเริ่มต้น การเชื่อมต่อหนึ่งอาจพกการกระทำของผู้ใช้หลายรายการ
ถ้าต้องการตรวจสอบความน่าเชื่อถืออย่างรวดเร็ว ให้ทำง่าย ๆ:
correlationId ชัดเจนขอบระบบของ API ของคุณ (gateway, load balancer, หรือบริการเว็บแรกที่รับทราฟฟิก) คือที่ที่ correlation IDs จะเชื่อถือได้หรือกลายเป็นการเดา ปฏิบัติต่อ entry point นี้เป็นแหล่งความจริง
รับ ID ขาเข้าถ้าคลไคลเอนต์ส่งมา แต่ไม่ควรสมมติว่ามันมีตลอด ให้สร้างใหม่ทันทีถ้ามันขาดหายเพื่อให้ทำงานต่อได้เมื่อบาง client เก่าเกินไปหรือคอนฟิกผิด
ทำการตรวจสอบแบบเบา ๆ เพื่อไม่ให้ค่าที่ไม่ดีมาปนเปื้อนล็อก เก็บให้ยืดหยุ่น: ตรวจความยาวและอักขระที่อนุญาต แต่หลีกเลี่ยงรูปแบบเข้มงวดที่ปฏิเสธทราฟฟิกจริง ตัวอย่าง: อนุญาต 16-64 ตัวอักษรและตัวอักษร ตัวเลข ขีด และขีดล่าง หากค่าไม่ผ่าน ให้แทนด้วย ID ใหม่แล้วทำต่อ
ทำให้ ID มองเห็นได้สำหรับผู้เรียก แสดงมันใน response headers เสมอ และรวมไว้ใน bodies ของ error ด้วย วิธีนี้ผู้ใช้คัดลอกจาก UI ได้ หรือซัพพอร์ตสามารถขอแล้วหาทางแทรซได้ทันที
นโยบาย edge เชิงปฏิบัติจะเป็นแบบนี้:
X-Correlation-ID (หรือ header ที่เลือก) จากคำขอX-Correlation-ID ในทุกการตอบกลับ รวมถึงข้อผิดพลาดตัวอย่าง payload ของข้อผิดพลาด (สิ่งที่ซัพพอร์ตควรเห็นในตั๋วและภาพหน้าจอ):
{
"error": {
"code": "PAYMENT_FAILED",
"message": "We could not confirm the payment.",
"correlation_id": "c3a8f2d1-9b24-4c61-8c4a-2a7c1b9c2f61"
}
}
เมื่อคำขอเข้าถึง backend ให้ถือว่า correlation ID เป็นส่วนหนึ่งของ context ของคำขอ ไม่ใช่สิ่งที่เก็บในตัวแปร global ตัวแปร global จะพังเมื่อคุณจัดการคำขอสองคำขอพร้อมกัน หรือเมื่องานแบบอะซิงก์ยังทำต่อหลังการตอบ
กฎที่ขยายได้: ทุกฟังก์ชันที่อาจล็อกหรือเรียกเซอร์วิสอื่นควรรับ context ที่มี ID ลงไปด้วย ในบริการที่เขียนด้วย Go นั่นมักหมายถึงการส่ง context.Context ผ่าน handler โลจิกธุรกิจ และโค้ด client
เมื่อ Service A เรียก Service B ให้คัดลอก ID เดิมเข้าไปในคำขอขาออก อย่าสร้าง ID ใหม่กลางทาง เว้นแต่ว่าคุณเก็บของเดิมไว้เป็นฟิลด์แยกต่างหาก (เช่น parent_correlation_id) หากเปลี่ยน ID ซัพพอร์ตจะเสียเส้นเดียวที่เชื่อมเรื่องทั้งหมด
การส่งต่อมักถูกลืมในจุดที่คาดไว้: งานแบ็คกราวด์ที่ถูก kick off ระหว่างคำขอ, retry ในไลบรารี client, webhook ที่เรียกทีหลัง, และการเรียกแบบ fan-out ข้อความอะซิงก์ใด ๆ (คิว/งาน) ควรพก ID และ logic retry ทุกตัวควรเก็บมันไว้
ล็อกควรถูกโครงสร้างด้วยชื่อฟิลด์คงที่อย่าง correlation_id เลือกการสะกดหนึ่งแบบและใช้ให้ทั่ว หลีกเลี่ยงการผสม requestId, req_id, และ traceId เว้นแต่คุณมีแผนที่ชัดเจน
ถ้าเป็นไปได้ ให้รวม ID ในการมองเห็นฐานข้อมูลด้วย วิธีปฏิบัติที่ใช้งานได้คือเพิ่มมันลงใน comment ของ query หรือ metadata ของ session เพื่อให้ slow query logs แสดงมัน เมื่อมีคนรายงานว่า "ปุ่มบันทึกค้าง 10 วินาที" ซัพพอร์ตสามารถค้นหา correlation_id=abc123 แล้วเห็นล็อก API การเรียกเซอร์วิสถัดไป และคำสั่ง SQL ที่ช้า
correlation ID มีประโยชน์เมื่อคนสามารถหาและตามมันได้ ทำให้มันเป็นฟิลด์ล็อกชั้นหนึ่ง (ไม่ฝังในสตริงข้อความ) และรักษารูปแบบบรรทัดล็อกให้สม่ำเสมอข้ามเซอร์วิส
จับคู่ correlation ID กับชุดฟิลด์เล็ก ๆ ที่ตอบคำถาม: เมื่อไหร่ ที่ไหน อะไร ใคร (ในแบบปลอดภัยต่อผู้ใช้) สำหรับทีมส่วนใหญ่ นั่นคือ:
timestamp (มี timezone)service และ env (api, worker, prod, staging)route (หรือชื่อ operation) และ methodstatus และ duration_msaccount_id หรือ user id แบบ hash ไม่ใช่อีเมล)ด้วยสิ่งนี้ ซัพพอร์ตสามารถค้นหาตาม ID ยืนยันว่ากำลังดูคำขอที่ถูกต้อง และเห็นว่าเซอร์วิสไหนจัดการมัน
มุ่งหา breadcrumb ที่มีประโยชน์ต่อคำขอ ไม่ใช่ทรานสคริปต์ทั้งหมด
rows=12)เพื่อหลีกเลี่ยงล็อกเสียงดังเกินไป ให้เก็บรายละเอียดระดับ debug นอกค่าเริ่มต้นและโปรโมตเฉพาะเหตุการณ์ที่ช่วยตอบคำถามว่า "มันล้มเหลวที่ไหน?" ถ้าบรรทัดไหนไม่ช่วยหาจุดบกพร่องหรือวัดผลกระทบ มันอาจไม่ควรเป็น info-level
การ redaction สำคัญเท่ากับโครงสร้าง ห้ามใส่ PII ใน correlation ID หรือล็อก: ไม่มีอีเมล ชื่อ เบอร์ ที่อยู่เต็ม หรือโทเคนดิบ หากต้องระบุตัวผู้ใช้ให้ล็อก internal ID หรือ hash ทางทางเดียว
ผู้ใช้ส่งข้อความถึงซัพพอร์ตว่า "เช็คเอาต์ล้มเหลวเมื่อกด Pay" คำถามติดตามที่ดีที่สุดคือ: "ช่วยวาง correlation ID ที่แสดงบนหน้าข้อผิดพลาดให้หน่อยได้ไหม?" พวกเขาตอบด้วย cid=9f3c2b1f6a7a4c2f
ซัพพอร์ตมีด้ามจับเดียวที่เชื่อม UI, API, และงานฐานข้อมูล เป้าหมายคือต้นทางทุกบรรทัดล็อกสำหรับการกระทำนั้นมี ID เดียวกัน
ซัพพอร์ตค้นหาในล็อก 9f3c2b1f6a7a4c2f แล้วเห็นการไหล:
frontend INFO cid=9f3c2b1f6a7a4c2f event="checkout_submit" cart=3 items
api INFO cid=9f3c2b1f6a7a4c2f method=POST path=/api/checkout user=1842
api ERROR cid=9f3c2b1f6a7a4c2f msg="payment failed" provider=stripe status=502
จากนั้นวิศวกรตาม ID เดียวกันต่อไปยัง hop ถัดไป จุดสำคัญคือต้องให้การเรียกเซอร์วิส backend (และงานคิวใด ๆ) ส่งต่อ ID ด้วย
payments INFO cid=9f3c2b1f6a7a4c2f action="charge" amount=49.00 currency=USD
payments ERROR cid=9f3c2b1f6a7a4c2f err="timeout" upstream=stripe timeout_ms=3000
db INFO cid=9f3c2b1f6a7a4c2f query="insert into failed_payments" rows=1
ตอนนี้ปัญชัดเจน: เซอร์วิสชำระเงิน timeout หลัง 3 วินาที และบันทึกข้อผิดพลาดถูกเขียน วิศวกรสามารถตรวจดูดีพลอยล่าสุด ยืนยันว่าการตั้งค่า timeout เปลี่ยนหรือไม่ และดูว่ากำลังเกิด retry หรือไม่
เพื่อปิดวง ให้ทำสี่อย่างตรวจสอบ:
วิธีที่เร็วที่สุดที่จะทำให้ correlation IDs ไร้ประโยชน์คือการทำให้สายเชื่อมขาด ความล้มเหลวส่วนใหญ่เกิดจากการตัดสินใจเล็ก ๆ ที่ดูไม่เป็นไรตอนสร้าง แต่กลับเป็นปัญหาเมื่อซัพพอร์ตต้องการคำตอบ
ความผิดพลาดคลาสสิกคือการสร้าง ID ใหม่ทุก hop ถ้าเบราว์เซอร์ส่ง ID เกตเวย์ API ควรเก็บไว้ ไม่ใช่แทนที่มัน ถ้าคุณต้องมี ID ภายในด้วยจริง ๆ (สำหรับข้อความคิวหรืองานแบ็คกราวด์) ให้เก็บของเดิมไว้เป็น parent field เพื่อให้เรื่องยังเชื่อมกัน
ช่องว่างที่พบบ่อยอีกอย่างคือล็อกไม่ครบ ทีมเพิ่ม ID ที่ API แรกแต่ลืมใน worker, scheduled job, หรือเลเยอร์การเข้าถึงฐานข้อมูล ผลคือทางตัน: คุณเห็นคำขอเข้าระบบแต่ไม่เห็นมันไปที่ไหนต่อ
แม้ ID จะมีทุกที่ ก็ยากค้นถ้าทุกเซอร์วิสใช้ชื่อฟิลด์หรือฟอร์แมตต่างกัน เลือกชื่อเดียวและยึดมันข้าม frontend, API, และล็อก (เช่น correlation_id) เลือกฟอร์แมตหนึ่ง (มักเป็น UUID) และถือว่ามัน case-sensitive เพื่อการคัดลอกวางทำงาน
อย่าสูญเสีย ID เมื่อเกิดข้อผิดพลาด ถ้า API ส่ง 500 หรือ validation error ให้รวม correlation ID ในการตอบข้อผิดพลาด (และถ้าเป็นไปได้ใน response header) เพื่อให้ผู้ใช้สามารถวางในแชทซัพพอร์ตแล้วทีมคุณจะติดตามทันที
การทดสอบรวดเร็ว: คนซัพพอร์ตเริ่มจาก ID เดียวแล้วตามมันผ่านทุกบรรทัดล็อกที่เกี่ยวข้องไหม รวมถึงความล้มเหลว?
ใช้เป็นการตรวจพื้นฐานก่อนบอกซัพพอร์ตว่า "แค่ค้นหาในล็อก" วิธีนี้ใช้ได้เมื่อทุก hop ปฏิบัติตามกฎเดียวกัน
correlation_id ในล็อกที่เกี่ยวข้องกับคำขอเป็นฟิลด์เชิงโครงสร้างเลือกการเปลี่ยนแปลงที่เล็กที่สุดที่จะทำให้สายเชื่อมไม่ขาด
correlation_id เดิมและเพิ่ม span_id แยกถ้าต้องการรายละเอียดการทดสอบที่จับช่องว่างได้: เปิด devtools, เริ่มการกระทำหนึ่งครั้ง, คัดลอก correlation ID จากคำขอแรก, แล้วยืนยันว่าเห็นค่าเดียวกันในคำขอ API ที่เกี่ยวข้องทั้งหมดและในทุกบรรทัดล็อกที่เกี่ยวข้อง
Correlation IDs จะช่วยเมื่อทุกคนใช้เหมือนกันทุกครั้ง ถือพฤติกรรม correlation ID เป็นส่วนที่ต้องมีของการปล่อยงาน ไม่ใช่แค่การปรับปรุงล็อกเล็กน้อย
เพิ่มขั้นตอน traceability เล็กน้อยใน definition of done ของคุณสำหรับ endpoint ใหม่หรือการกระทำ UI ครอบคลุมว่ามันสร้าง (หรือ reuse) อย่างไร อยู่ที่ไหนใน flow header ไหนพาไป และแต่ละบริการทำอย่างไรเมื่อ header ขาด
เช็คลิสต์น้ำหนักเบามักเพียงพอ:
correlation_id) ข้ามแอปและเซอร์วิสซัพพอร์ตควรมีสคริปต์ง่าย ๆ เพื่อให้การดีบักเร็วและทำซ้ำได้ ตัดสินใจว่า ID แสดงให้ผู้ใช้เห็นที่ไหน (เช่นปุ่ม "Copy debug ID" บน dialog ข้อผิดพลาด) และจดว่าซัพพอร์ตควรถามอะไรและค้นหาที่ไหน
ก่อนจะพึ่งพามันใน production ให้รัน flow แบบ staged ที่เหมือนการใช้งานจริง: กดปุ่ม, กระตุ้น validation error, แล้วทำการกระทำให้เสร็จ ยืนยันว่าคุณตาม ID เดียวกันจากคำขอเบราว์เซอร์ ผ่านล็อก API เข้า worker ใด ๆ และถึงล็อกคำสั่งฐานข้อมูลถ้าคุณบันทึกไว้
ถ้าคุณสร้างแอปบน Koder.ai จะช่วยให้เขียน header และคอนเวนชันล็อกของ correlation ID ลงใน Planning Mode เพื่อให้ React frontend และ Go services ที่สร้างขึ้นเริ่มสอดคล้องกันโดยดีตั้งแต่ต้น
A correlation ID คือรหัสตัวเดียวที่ใช้แท็กทุกอย่างที่เกี่ยวข้องกับการกระทำหรือเวิร์กโฟลว์ของผู้ใช้หนึ่งรายการ ตั้งแต่เบราว์เซอร์ APIs เซอร์วิส และงานแบ็คกราวด์ ช่วยให้ฝ่ายซัพพอร์ตเริ่มจาก ID เดียวแล้วดึงไทม์ไลน์เต็มได้ แทนการเดาว่าแถวล็อกไหนเกี่ยวข้องกัน
ใช้ correlation ID เมื่อต้องการดีบักกรณีเฉพาะแบบ end-to-end เช่น “กด Pay แล้วล้มเหลว” เพราะ session ID กว้างเกินไป (ครอบหลายการกระทำ) และ request ID แคบเกินไป (ครอบเพียง HTTP request เดียวและเปลี่ยนเมื่อ retry)
สร้างที่ frontend โดยดีที่สุดคือเมื่อต้นของการกระทำของผู้ใช้เริ่มขึ้น (เช่น กดยืนยัน ส่งฟอร์ม หรือเริ่ม flow หลายขั้น) การสร้างที่ฝั่งไคลเอนต์ช่วยเก็บส่วนแรกของเรื่องไว้ เช่น ข้อผิดพลาดใน UI การ retry หรือตัดการร้องขอ
ใช้ค่าที่ทึบและไม่ระบุตัวบุคคล เช่น UUID v4 ที่คัดลอกได้ง่ายและปลอดภัย อย่าใส่ข้อมูลส่วนตัว (อีเมล เบอร์ หรือเลขคำสั่ง) ลงใน ID ให้เก็บบริบทเหล่านั้นในฟิลด์ล็อกที่แยกต่างหากและมีการควบคุมความเป็นส่วนตัว
กำหนดชื่อ header เดียวและใช้ให้ทั่ว เช่น X-Correlation-ID แล้วล็อกภายใต้ฟิลด์ที่สอดคล้องกันอย่าง correlation_id ความสม่ำเสมอสำคัญกว่าชื่อที่เฉพาะเจาะจง
ถ้ามันยังเป็นการกระทำเดิม (เช่น client retry ของ POST เดิม) ให้ใช้ correlation ID เดิม เพื่อให้ล็อกเชื่อมต่อกัน สร้าง ID ใหม่เมื่อเป็นการกระทำใหม่ของผู้ใช้จริง ๆ เช่นกดอีกครั้งในเวลาถัดไป
API entry point ควรรับ ID ที่มาพร้อมคำขอ ถ้ามี และถ้าไม่มีหรือไม่ถูกต้องให้สร้างใหม่ทันที แล้ว echo ค่า ID นั้นกลับใน response (รวมถึง error) เพื่อให้ผู้ใช้หรือซัพพอร์ตคัดลอกได้จาก UI
ใส่ลงใน context ของการร้องขอและคัดลอกไปกับทุกการเรียกถัดไป รวมทั้ง HTTP/gRPC ภายในและงานคิว หลีกเลี่ยงการสร้าง correlation ID ใหม่กลางทาง หากต้องการรายละเอียดเพิ่มให้สร้างตัวระบุภายในแยกต่างหากโดยไม่ทำลายสายเชื่อมต่อเดิม
ล็อกเป็นฟิลด์เชิงโครงสร้างตัวแรก เช่น correlation_id เพื่อให้ค้นหาได้ง่าย จับคู่กับฟิลด์สำคัญอื่น ๆ เช่น ชื่อเซอร์วิส เส้นทาง สถานะ เวลา และตัวระบุผู้ใช้ที่ไม่เปิดเผยข้อมูล เพื่อให้แทรซ์ไม่จบที่เหตุการณ์ล้มเหลว
ทดสอบโดยกดการกระทำหนึ่งครั้ง คัดลอก correlation ID จากคำขอแรกหรือหน้าข้อผิดพลาด แล้วยืนยันว่า ID เดียวกันปรากฏใน header ของคำขอที่เกี่ยวข้องทั้งหมดและบรรทัดล็อกของทุกเซอร์วิสที่เกี่ยวข้อง ถ้า ID หายไปใน worker, retry หรือ response ของ error แก้จุดนั้นก่อน