المراقبة في PHP: كيف تتوقف عن التخمين وتبدأ برؤية كل شيء بوضوح
\n\nعندما يبدأ تطبيق PHP الخاص بك في التباطؤ، أو إظهار أخطاء 500، أو مجرد التصرف بشكل غريب، أول رد فعل هو النظر في السجلات. لكن السجلات (حتى لو كانت منظمة بشكل مثالي) هي مجرد جزء من اللغز. التطوير الحديث يتطلب أكثر من ذلك بكثير: تحتاج إلى معرفة المدة التي استغرقها كل طلب، الخدمات الخارجية التي تبطئ النظام، و كمية الذاكرة التي يستهلكها نقطة نهاية معينة.
\n\nكل هذا يتعلق بـ المراقبة (observability). في هذه المقالة، سنشرح الأركان الثلاثة للمراقبة في PHP: التتبع، المقاييس، والسجلات. ستتعلم كيفية إعداد مراقبة حقيقية مع أمثلة كود، وستحصل على وصفات جاهزة يمكنك تطبيقها اليوم.
\n\nما هي المراقبة ولماذا يحتاجها مطور PHP؟
\n\nالمراقبة (O11y) هي القدرة على فهم الحالة الداخلية للنظام من خلال مخرجاته الخارجية. في عالم PHP، هذا يعني أنه يمكنك الإجابة على أسئلة مثل:
\n\n- \n
- لماذا استغرق طلب API معين 5 ثوانٍ؟ \n
- ما هو استعلام SQL الذي استغرق أطول وقت في الساعة الماضية؟ \n
- كم عدد الطلبات في الثانية التي يعالجها خادمك الآن؟ \n
- أين بالضبط "تتسرب" الذاكرة؟ \n
بدون المراقبة، أنت تعمل بشكل أعمى. معها، ترى كل حركة في تطبيقك. ونعم، هذا لا ينطبق فقط على الخدمات المصغرة بلغة Go أو Java. يمكن ويجب "مراقبة" تطبيق PHP المتجانس أيضًا.
\n\nالتتبع في PHP: التتبع الموزع باستخدام OpenTelemetry
\n\nالتتبع (Tracing) هو قصة طلب واحد. ترى كيف يمر الطلب عبر تطبيقك، وما هي الدوال التي يتم استدعاؤها، وما هي واجهات API الخارجية التي يتم الوصول إليها، وكم من الوقت يستغرق كل خطوة. في PHP، يتم استخدام معيار OpenTelemetry لهذا الغرض.
\n\nتثبيت OpenTelemetry لـ PHP
\n\nأولاً، سنقوم بتثبيت الحزم اللازمة عبر Composer:
\n\ncomposer require open-telemetry/opentelemetry\ncomposer require open-telemetry/transport-grpc\ncomposer require open-telemetry/exporter-otlp\n\n\nالآن، سنقوم بإعداد أداة التتبع الأساسية. لننشئ ملف tracing.php:
// tracing.php\nuse OpenTelemetry\\API\\Globals;\nuse OpenTelemetry\\SDK\\Trace\\TracerProvider;\nuse OpenTelemetry\\SDK\\Trace\\SpanProcessor\\BatchSpanProcessor;\nuse OpenTelemetry\\SDK\\Trace\\Exporter\\ConsoleSpanExporter;\n\nrequire 'vendor/autoload.php';\n\n// إنشاء مصدر (حتى الآن إلى وحدة التحكم)\n$exporter = new ConsoleSpanExporter();\n$processor = new BatchSpanProcessor($exporter);\n$tracerProvider = new TracerProvider($processor);\n\n// تسجيل أداة التتبع العالمية\nGlobals::setTracerProvider($tracerProvider);\n\n// الحصول على أداة التتبع باسم تطبيقك\n$tracer = Globals::tracerProvider()->getTracer('my-php-app');\n\n\nإنشاء سبانات (spans) في الكود الفعلي
\n\nلنفترض أن لديك وحدة تحكم تعالج طلبًا. سنقوم بتغليف العمليات الرئيسية في سبانات:
\n\n// OrderController.php\nclass OrderController {\n public function createOrder(array $data) {\n $tracer = Globals::tracerProvider()->getTracer('order-service');\n \n // السبان الرئيسي — الطلب بأكمله\n $span = $tracer->spanBuilder('POST /orders')->startSpan();\n $span->setAttribute('order.id', $data['id'] ?? 'unknown');\n \n try {\n // سبان للتحقق من المستخدم\n $userSpan = $tracer->spanBuilder('validate.user')->startSpan();\n $user = $this->validateUser($data['user_id']);\n $userSpan->end();\n \n // سبان للحفظ في قاعدة البيانات\n $dbSpan = $tracer->spanBuilder('save.order')->startSpan();\n $order = $this->saveOrder($data);\n $dbSpan->end();\n \n // سبان لإرسال البريد الإلكتروني\n $emailSpan = $tracer->spanBuilder('send.email')