ما وراء الـ Console: هندسة الـ Observability بمستوى الإنتاج و OpenTelemetry في التطبيقات الشاملة
توقف عن الاعتماد على السجلات (logs) المشتتة وابدأ في الاستفادة من الـ distributed tracing عبر الـ full stack الخاص بك. يتناول هذا المقال رحلتي في تطبيق OpenTelemetry في البيئات الشاملة لتحقيق observability حقيقية بمستوى الإنتاج.

ما وراء الـ Console: هندسة الـ Observability بمستوى الإنتاج
لنكن صادقين: لقد مررنا جميعاً بهذا الموقف. يقع حادث عالي الأهمية في بيئة الإنتاج (production incident)، ويكون دليلك الوحيد هو خطأ [object Object] مجزأ في مجمع سجلات (log aggregator) لم يشهد أي deployment منذ ثلاثة أسابيع. في عالم التطبيقات الشاملة (universal apps)—حيث قد يعمل نفس المنطق (logic) على متصفح، أو جهاز محمول عبر React Native، أو Node.js edge function—فإن الاعتماد على console.log أو تقارير الأخطاء المعزولة يشبه محاولة رسم خريطة لنظام مترو الأنفاق من خلال النظر عبر قشة.
على مدار العام الماضي، كنت مهووساً بالانتقال لما هو أبعد من مجرد "logging" والدخول في مجال الـ Observability (o11y) باستخدام OpenTelemetry (OTel). إليكم كيف قمت بهندسة هذه الأنظمة للتعامل مع تعقيدات التطبيقات الشاملة.
مغالطة السجل (The Fallacy of the Log)
الـ Logs هي أحداث، أما الـ Traces فهي قصص. عندما يواجه مستخدم في لندن تأخيراً (lag) قدره 500 مللي ثانية عند الضغط على زر الدفع، يخبرك الـ log أن ذلك قد حدث. أما الـ trace فيخبرك أن الـ frontend span انتظر gateway span، والذي تعطل بسبب قفل قاعدة البيانات (database lock) في microservice مختلف تماماً.
في التطبيقات الشاملة، يكمن التحدي في Context Propagation. كيف تضمن أن الـ traceId الذي تم إنشؤه على جهاز Android ينجو من الانتقال إلى الـ Go backend الخاص بك ومن ثم إلى استعلام Postgres؟
المعمارية: الـ OTel Collector هو أفضل صديق لك
أحد النجاحات التي حققتها كان التوقف عن إرسال البيانات مباشرة من العميل (client) إلى مزود الخدمة (مثل Honeycomb أو Datadog). بدلاً من ذلك، بدأت في استخدام OpenTelemetry Collector كـ sidecar أو كخدمة مستقلة.
هذا يسمح لتطبيقات العميل بأن تكون "dumb". فهي تقوم بدفع الـ spans عبر OTLP (OpenTelemetry Protocol) إلى collector مدار، والذي يتولى بعد ذلك المهمة الثقيلة المتمثلة في تنظيف الـ PII (بيانات التعريف الشخصية)، والـ sampling، والتصدير إلى وجهات متعددة.
التنفيذ: الـ Universal Tracer
إليك نسخة مبسطة من كيفية تهيئة global tracer يعمل عبر مختلف البيئات. المفتاح هنا هو الـ BatchSpanProcessor—فأنت لا تريد أبداً تعطيل الـ UI thread أثناء إرسال بيانات الـ telemetry.
حل مشكلة الجوال: Offline Spans
تتضمن التطبيقات الشاملة غالباً React Native. وعلى عكس المتصفح، تفقد الأجهزة المحمولة الاتصال باستمرار. إذا حاولت إرسال span بينما المستخدم في نفق، فسيضيع.
لحل هذه المشكلة، قمت بتنفيذ Persistent Span Store مخصص. بدلاً من التصدير الفوري، نقوم بتخزين الـ spans مؤقتاً في التخزين المحلي للجهاز (مثل SQLite أو MMKV) ونقوم بإرسالها بمجرد أن تعطي NetInfo API إشارة بوجود اتصال مستقر. اتضح أن مراقبة سلوك "الوضع غير المتصل" (offline mode) غالباً ما تكون أكثر قيمة من مراقبة المسار الطبيعي (happy path).
الـ Instrumentation التلقائي مقابل اليدوي
بينما تعد مكتبات الـ auto-instrumentation لـ fetch أو XMLHttpRequest رائعة لتحقيق نتائج سريعة، إلا أنها غالباً ما تسبب الكثير من الضجيج (noise). لقد انتقلت إلى نهج هجين (Hybrid Approach):
- Auto-instrumentation لطلبات الشبكة وتغييرات التنقل (navigation).
- Manual instrumentation لمنطق العمل الهام (مثل
calculate_risk_scoreأوprocess_payment).
الـ Sampling: القاتل الصامت للميزانية
في بيئة إنتاج تحتوي على ملايين الـ spans، فإن إرسال كل شيء سيؤدي إلى إفلاس ميزانية السحابة الخاصة بك. أوصي بـ Tail-based Sampling. بدلاً من أن يقرر العميل ما يجب إرساله (Head-based)، ينظر الـ OTel Collector إلى الـ trace بالكامل. إذا كان الـ trace يحتوي على خطأ أو latency عالية بشكل غير عادي، فإنه يحتفظ به كاملاً. أما إذا كان مجرد 200 OK عادي، فإنه يتجاهل 95% منها.
النتيجة: من التخمين إلى المعرفة
منذ الانتقال إلى هذه المعمارية، انخفض معدل الـ MTTR (متوسط وقت الإصلاح) لدينا بشكل كبير. لم نعد نسأل "ماذا حدث؟"؛ بل ننظر إلى waterfall chart ونسأل "لماذا استغرق استدعاء قاعدة البيانات المحدد هذا 4 ثوانٍ؟"
إن هندسة الـ observability لا تتعلق فقط بإضافة الأدوات؛ بل تتعلق بتغيير عقليتك من "هل يعمل؟" إلى "كيف هو الأداء بالنسبة للمستخدم في الوقت الفعلي؟"
إذا لم تستكشف OpenTelemetry لتطبيقاتك الشاملة بعد، فابدأ صغيراً. قم بعمل instrumentation لأهم API call لديك. ستفاجأ بما يحدث حقاً خلف الكواليس.