Wide Events بدل metrics و logs و traces متفرقة — Full Stack Tips ج٣٧
بدل 3 حاجات منفصلة، سجّل event واحد عريض لكل request فيه كل الـ context. الفكرة من مقال Ivan Burmistrov عن تجربته مع Scuba في Meta، وإزاي تطبّقها.
الـ dashboard بيقولك إن فيه مشكلة، بس الـ metrics ما فيهاش الحقل اللي يقولك هي فين بالظبط، واللوجز سطور نص مش عارف تعمل عليها group by. لو المشهد ده مألوف، فالفكرة اللي في المقال ده ممكن تغيّر طريقة تفكيرك في الـ observability. النهارده في سلسلة «Full Stack Tips» (الجزء ٣٧) هنتكلم عن Wide Events.
الفكرة من فين؟
الفكرة من مقال لـ Ivan Burmistrov بعنوان «All you need is Wide Events, not Metrics, Logs and Traces». Ivan اشتغل في Meta، وكان بيستخدم أداة داخلية اسمها Scuba، وبيوصفها إنها أحسن نظام observability استخدمه. المقال رجع للصفحة الأولى في Hacker News من كام يوم، وده اللي فكّرني بيه.
الفكرة ببساطة: بدل ما تفكر في 3 حاجات منفصلة (metrics و logs و traces)، سجّل wide event: حدث واحد عريض فيه كل الـ context، زي JSON document.
1. event واحد لكل request فيه كل حاجة
لكل request أو job، اكتب event واحد فيه كل الحقول اللي ممكن تحتاجها بعدين، حتى لو مش شايف لها لازمة دلوقتي. ده جزء من المثال اللي في المقال:
{
"Placement": "mobile_feed",
"UserOS": "Android",
"OSVersion": "14"
}
المقال بيسمّيها wide لأنك بتتشجّع ترمي فيها أي context ممكن يفيد. والهدف إنك تبقى جاهز لـ unknown unknowns: حاجات مش ممكن تفكر فيها دلوقتي، وهتظهر بعدين وقت التحقيق في حادثة.
2. لو بتعمل sampling، سجّل samplingRate
في Scuba، كل event لازم يكتب حقل اسمه samplingRate، وهو الـ rate اللي الـ event ده اتعمله sampling بيه. الأداة بتستخدمه علشان ترجّع الأرقام لحجمها الحقيقي في الرسوم. يعني الـ query الحقيقية تحت الغطا شكلها كده:
SELECT SUM(samplingRate) FROM AdImpressions WHERE IsTest = False
بدل COUNT(*) اللي هتديك رقم أقل من الحقيقة لو فيه sampling.
3. الـ traces نفسها wide events
حسب المقال، الـ traces والـ spans هي wide events فيها حقول TraceId و SpanId و ParentSpanId. تقدر تفلتر كل الـ spans بتاعة TraceId معيّن وترتّبها بعلاقة SpanId و ParentSpanId وترسم الشجرة. والكاتب بيقول إنه لما حاول يربط الفكرة بـ OpenTelemetry، لقى إن أقرب حاجة للـ wide event هي الـ Span.
4. وقت الحادثة: slice and dice
هنا القوة الحقيقية. في مثال المقال، المشكلة اتحصرت خطوة بخطوة:
- جمّع حسب نوع الحملة، ولاحظ إن نوع معيّن شكله مختلف.
- فلتر على Android بس.
- وصل لأحدث إصدار OS مع إصدارات معيّنة من التطبيق.
التركيبة دي ما كانش ممكن تعمل لها metric جاهز مقدمًا، لأنك ما كنتش تعرف إنك هتحتاجها.
طب والـ metrics والـ cardinality؟
- الـ cardinality: حسب المقال، مش مشكلة هنا، لأن الـ events بتتخزن raw ومش متجمّعة مسبقًا، فأي حقل ممكن يبقى بأي cardinality.
- الـ metrics: ممكن تبقى هي كمان event كل فترة فيه حالة السيستم (CPU وcounters مختلفة)، زي ما Prometheus بياخد snapshot كل شوية بالـ scraping.
خلي بالك
الحقول الكتير مش معناها تحط أي حاجة. ما تحطش passwords أو tokens أو بيانات شخصية جوه الـ event، لأن الـ events دي بتتخزن وبيقراها ناس وأدوات كتير.
رأيي
ابدأ صغير: middleware يكتب event واحد مع نهاية كل request، فيه route و status و duration و user plan و app version. مش محتاج تغيّر الـ stack بتاعك كله مرة واحدة. ولو بتستخدم OpenTelemetry أصلًا، زوّد attributes على الـ spans بدل ما تكتب لوجز نص متفرقة. هتستغرب قد إيه ده هيوفّر عليك وقت في أول حادثة.
إنت بتعمل debugging للـ production بإيه دلوقتي؟ لوجز ولا traces ولا events؟
المصادر
- Observability
- Backend
- OpenTelemetry
- Debugging
- Full Stack Tips