الحصول على أقصى استفادة من ملفات سجل PHP: دليل عملي

نشرت: 2022-03-11

يمكن القول بحق أن السجلات هي واحدة من أكثر الأدوات التي يتم التقليل من شأنها وعدم الاستفادة منها في التخلص من مطور php المستقل. على الرغم من وفرة المعلومات التي يمكنهم تقديمها ، فليس من غير المألوف أن تكون السجلات هي آخر مكان يبحث فيه المطور عند محاولة حل مشكلة ما.

في الحقيقة ، يجب أن تكون ملفات سجل PHP في كثير من الحالات هي المكان الأول للبحث عن أدلة عند حدوث مشاكل. في كثير من الأحيان ، يمكن للمعلومات التي تحتويها أن تقلل بشكل كبير من مقدار الوقت الذي تقضيه في نتف شعرك في محاولة تعقب الأخطاء الشائكة.

ولكن ربما الأهم من ذلك ، مع القليل من الإبداع والتدبر ، يمكن الاستفادة من ملفات السجلات الخاصة بك لتكون بمثابة مصدر قيم لمعلومات الاستخدام والتحليلات. يمكن أن يساعد الاستخدام الإبداعي لملفات السجل في الإجابة عن أسئلة مثل: ما المستعرضات التي يتم استخدامها بشكل شائع لزيارة موقعي؟ ما هو متوسط ​​وقت الاستجابة من الخادم الخاص بي؟ ما هي النسبة المئوية للطلبات إلى جذر الموقع؟ كيف تغير الاستخدام منذ نشرنا آخر التحديثات؟ والكثير الكثير.

ملفات سجل PHP

توفر هذه المقالة عددًا من النصائح حول كيفية تكوين ملفات السجل الخاصة بك ، بالإضافة إلى كيفية معالجة المعلومات التي تحتوي عليها ، من أجل تعظيم الفائدة التي تقدمها.

على الرغم من أن هذه المقالة تركز تقنيًا على التسجيل لمطوري PHP ، إلا أن الكثير من المعلومات المقدمة هنا حيادية من الناحية التكنولوجية إلى حد ما وذات صلة باللغات الأخرى وأكوام التكنولوجيا أيضًا.

ملاحظة: تفترض هذه المقالة معرفة أساسية بصدفة Unix. بالنسبة لأولئك الذين يفتقرون إلى هذه المعرفة ، يتم توفير ملحق يقدم بعض الأوامر اللازمة للوصول إلى ملفات السجل وقراءتها على نظام Unix.

مشروع نموذج ملف سجل PHP الخاص بنا

كمثال لمشروع لأغراض المناقشة في هذه المقالة ، سنأخذ Symfony Standard كمشروع عمل وسنقوم بإعداده على Debian 7 Wheezy باستخدام rsyslogd و nginx و PHP-FPM .

 composer create-project symfony/framework-standard-edition my "2.6.*"

هذا يعطينا بسرعة مشروع اختبار عملي مع واجهة مستخدم لطيفة.

تلميحات حول تكوين ملفات السجل الخاصة بك

فيما يلي بعض المؤشرات حول كيفية تكوين ملفات السجل للمساعدة في تعظيم قيمتها.

تكوين سجل الخطأ

تمثل سجلات الأخطاء أبسط أشكال التسجيل ؛ على سبيل المثال ، الحصول على معلومات وتفاصيل إضافية عند حدوث المشاكل. لذلك ، في عالم مثالي ، قد ترغب في عدم وجود أخطاء وأن تكون سجلات الأخطاء فارغة. ولكن عند حدوث مشكلات (كما يحدث دائمًا) ، يجب أن تكون سجلات الأخطاء إحدى أولى نقاط التوقف التي تقوم بها في مسار التصحيح.

عادةً ما يكون تكوين سجلات الأخطاء أمرًا سهلاً للغاية.

لسبب واحد ، يمكن تسجيل جميع رسائل الخطأ والأعطال في سجل الأخطاء بنفس التنسيق تمامًا الذي سيتم تقديمه به إلى المستخدم. مع بعض التكوين البسيط ، لن يحتاج المستخدم النهائي أبدًا إلى رؤية آثار الأخطاء القبيحة على موقعك ، بينما سيظل devops قادرًا على مراقبة النظام ومراجعة رسائل الخطأ هذه بكل تفاصيلها الدموية. فيما يلي كيفية إعداد هذا النوع من تسجيل الدخول إلى PHP:

 log_errors = On error_reporting = E_ALL error_log = /path/to/my/error/log

هناك سطرين آخرين من المهم تضمينهما في ملف سجل لموقع مباشر ، لمنع المستويات الدموية من تفاصيل الخطأ من الظهور للمستخدمين ، وهما:

 display_errors = Off display_startup_errors = Off

تكوين سجل النظام ( syslog )

هناك العديد من التطبيقات المتوافقة بشكل عام syslog في عالم مفتوح المصدر ، بما في ذلك:

  • sysklogd syslogd غالبًا ما يتم مشاهدتهما على أنظمة عائلة BSD و CentOS و Mac OS X وغيرها
  • syslog-ng - افتراضي لإصدارات Gentoo و SuSE الحديثة
  • rsyslogd - يستخدم على نطاق واسع في عائلات أنظمة التشغيل Debian و Fedora

(ملاحظة: في هذه المقالة ، rsyslogd لأمثلة لدينا.)

يعد تكوين سجل النظام الأساسي مناسبًا بشكل عام لالتقاط رسائل السجل الخاصة بك في ملف سجل على مستوى النظام (عادةً /var/log/syslog ؛ قد يكون أيضًا /var/log/messages أو /var/log/system.log اعتمادًا على التوزيعات. الذي تستخدمه).

يوفر سجل النظام العديد من مرافق السجل ، ثمانية منها (من LOG_LOCAL0 إلى LOG_LOCAL7 ) محجوزة للمشاريع التي ينشرها المستخدم. هنا ، على سبيل المثال ، كيفية إعداد LOG_LOCAL0 للكتابة إلى 4 ملفات سجل منفصلة ، بناءً على مستوى التسجيل (على سبيل المثال ، خطأ ، تحذير ، معلومات ، تصحيح أخطاء):

 # /etc/rsyslog.d/my.conf local0.err /var/log/my/err.log local0.warning /var/log/my/warning.log local0.info -/var/log/my/info.log local0.debug -/var/log/my/debug.log

الآن ، عندما تكتب رسالة سجل إلى منشأة LOG_LOCAL0 ، ستنتقل رسائل الخطأ إلى /var/log/my/err.log ، وستنتقل رسائل التحذير إلى /var/log/my/warning.log وما إلى ذلك. لاحظ ، مع ذلك ، أن عفريت سجل النظام يقوم بتصفية الرسائل لكل ملف بناءً على قاعدة "هذا المستوى وأعلى". لذلك ، في المثال أعلاه ، ستظهر جميع رسائل الخطأ في جميع الملفات الأربعة التي تم تكوينها ، وستظهر رسائل التحذير في جميع الملفات باستثناء سجل الأخطاء ، وستظهر رسائل المعلومات في سجلات المعلومات وتصحيح الأخطاء ، وستنتقل رسائل التصحيح فقط إلى debug.log .

ملاحظة مهمة إضافية ؛ تشير العلامات - الموجودة قبل ملفات مستوى المعلومات وتصحيح الأخطاء في مثال ملف التكوين أعلاه إلى أن عمليات الكتابة إلى هذه الملفات يجب أن تتم بشكل غير متزامن (نظرًا لأن هذه العمليات غير محظورة). عادةً ما يكون هذا جيدًا (وحتى موصى به في معظم المواقف) للمعلومات وسجلات تصحيح الأخطاء ، ولكن من الأفضل أن تكون عمليات الكتابة في سجل الأخطاء (والأغلب على الأرجح سجل التحذير أيضًا) متزامنة.

لإغلاق مستوى أقل أهمية من التسجيل (على سبيل المثال ، على خادم إنتاج) ، يمكنك ببساطة إعادة توجيه الرسائل ذات الصلة إلى /dev/null (أي إلى أي مكان آخر):

 local0.debug /dev/null # -/var/log/my/debug.log

أحد التخصيصات المحددة المفيدة ، خاصة لدعم بعض تحليل ملف سجل PHP الذي سنناقشه لاحقًا في هذه المقالة ، هو استخدام علامة التبويب كحرف محدد في رسائل السجل. يمكن القيام بذلك بسهولة عن طريق إضافة الملف التالي في /etc/rsyslog.d :

 # /etc/rsyslog.d/fixtab.conf $EscapeControlCharactersOnReceive off

وأخيرًا ، لا تنس إعادة تشغيل البرنامج الخفي لسجل النظام بعد إجراء أي تغييرات في التكوين حتى تصبح سارية المفعول:

 service rsyslog restart

تكوين سجل الخادم

على عكس سجلات التطبيق وسجلات الأخطاء التي يمكنك الكتابة إليها ، تتم كتابة سجلات الخادم بشكل حصري بواسطة شياطين الخادم المقابلة (مثل خادم الويب وخادم قاعدة البيانات وما إلى ذلك) عند كل طلب. "التحكم" الوحيد الذي لديك على هذه السجلات هو إلى الحد الذي يسمح لك الخادم بتكوين وظيفة التسجيل الخاصة به. على الرغم من أنه يمكن أن يكون هناك الكثير من التدقيق في هذه الملفات ، إلا أنها غالبًا ما تكون الطريقة الوحيدة للحصول على فكرة واضحة عما يجري "تحت الغطاء" مع الخادم الخاص بك.

دعنا ننشر تطبيق مثال Symfony القياسي على بيئة nginx مع خلفية تخزين MySQL. إليك تهيئة مضيف nginx التي سنستخدمها:

 server { server_name my.log-sandbox; root /var/www/my/web; location / { # try to serve file directly, fallback to app.php try_files $uri /app.php$is_args$args; } # DEV # This rule should only be placed on your development environment # In production, don't include this and don't deploy app_dev.php or config.php location ~ ^/(app_dev|config)\.php(/|$) { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTPS off; } # PROD location ~ ^/app\.php(/|$) { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTPS off; # Prevents URIs that include the front controller. This will 404: # http://domain.tld/app.php/some-path # Remove the internal directive to allow URIs like this internal; } error_log /var/log/nginx/my_error.log; access_log /var/log/nginx/my_access.log; }

فيما يتعلق بالتوجيهين الأخيرين أعلاه: يمثل access_log سجل الطلبات العام ، بينما يمثل error_log الأخطاء ، وكما هو الحال مع سجلات أخطاء التطبيق ، فإن الأمر يستحق إعداد مراقبة إضافية لتنبيهك بالمشكلات حتى تتمكن من الرد بسرعة.

ملاحظة: هذا ملف تكوين nginx مُبسط عن قصد ويتم توفيره لأغراض المثال فقط. لا يولي أي اهتمام للأمان والأداء ولا يجب استخدامه كما هو في أي بيئة "حقيقية".

هذا ما نحصل عليه في /var/log/nginx/my_access.log بعد كتابة http://my.log-sandbox/app_dev.php/ في المتصفح والضغط على Enter .

 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /app_dev.php/ HTTP/1.1" 200 6715 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/body.css HTTP/1.1" 200 6657 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/structure.css HTTP/1.1" 200 1191 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/css/demo.css HTTP/1.1" 200 2204 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-quick-tour.gif HTTP/1.1" 200 4770 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-demo.gif HTTP/1.1" 200 4053 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-configure.gif HTTP/1.1" 200 3530 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /favicon.ico HTTP/1.1" 200 6518 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36" 192.168.56.1 - - [26/Apr/2015:16:13:30 +0300] "GET /app_dev.php/_wdt/e50d73 HTTP/1.1" 200 13265 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"

يوضح هذا أنه لعرض صفحة واحدة ، يقوم المتصفح في الواقع بإجراء 9 مكالمات HTTP. ومع ذلك ، فإن 7 من هذه الطلبات عبارة عن طلبات لمحتوى ثابت ، وهي بسيطة وخفيفة الوزن. ومع ذلك ، لا يزالون يأخذون موارد الشبكة وهذا ما يمكن تحسينه باستخدام تقنيات تصغير وتقنيات مختلفة.

بينما ستتم مناقشة هذه التحسينات في مقال آخر ، ما يهم هنا هو أنه يمكننا تسجيل الطلبات إلى محتويات ثابتة بشكل منفصل باستخدام توجيه location آخر لها:

 location ~ \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js)$ { access_log /var/log/nginx/my_access-static.log; }

تذكر أن location nginx يقوم بتنفيذ مطابقة بسيطة للتعبير العادي ، لذا يمكنك تضمين العديد من امتدادات المحتويات الثابتة التي تتوقع إرسالها على موقعك.

لا يختلف تحليل مثل هذه السجلات عن تحليل سجلات التطبيق.

سجلات أخرى تستحق الذكر

هناك سجلين آخرين في PHP جديران بالذكر هما سجل تصحيح الأخطاء وسجل تخزين البيانات.

سجل التصحيح

شيء آخر ملائم حول سجلات nginx هو سجل التصحيح. يمكننا تشغيله عن طريق استبدال سطر error_log بما يلي (يتطلب تثبيت وحدة تصحيح أخطاء nginx):

 error_log /var/log/nginx/my_error.log debug;

ينطبق نفس الإعداد على Apache أو أي خادم ويب آخر تستخدمه.

وبالمناسبة ، لا ترتبط سجلات تصحيح الأخطاء بسجلات الأخطاء ، على الرغم من تكوينها في توجيه error_log .

على الرغم من أن سجل التصحيح يمكن أن يكون مطولًا بالفعل (طلب nginx واحد ، على سبيل المثال ، ينتج 127 كيلو بايت من بيانات السجل!) ، إلا أنه يمكن أن يكون مفيدًا للغاية. قد يكون الخوض في ملف السجل مرهقًا ومملًا ، ولكنه غالبًا ما يوفر أدلة ومعلومات تساعد بشكل كبير في تسريع عملية تصحيح الأخطاء.

على وجه الخصوص ، يمكن أن يساعد سجل التصحيح حقًا في تصحيح أخطاء تكوينات nginx ، خاصة الأجزاء الأكثر تعقيدًا ، مثل مطابقة location وإعادة rewrite السلاسل.

بالطبع ، يجب عدم تمكين سجلات تصحيح الأخطاء في بيئة الإنتاج مطلقًا. يعني مقدار المساحة التي يستخدمونها أيضًا وكمية المعلومات التي يخزنونها الكثير من تحميل الإدخال / الإخراج على الخادم الخاص بك ، مما قد يؤدي إلى تدهور أداء النظام بالكامل بشكل كبير.

سجلات تخزين البيانات

نوع آخر من سجلات الخادم (مفيد لتصحيح الأخطاء) هو سجلات تخزين البيانات. في MySQL ، يمكنك تشغيلها عن طريق إضافة الأسطر التالية:

 [mysqld] general_log = 1 general_log_file = /var/log/mysql/query.log

تحتوي هذه السجلات ببساطة على قائمة من الاستعلامات التي يديرها النظام أثناء تقديم طلبات قاعدة البيانات بترتيب زمني ، والتي يمكن أن تكون مفيدة لاحتياجات التصحيح والتتبع المختلفة. ومع ذلك ، لا ينبغي أن تظل ممكّنة على أنظمة الإنتاج ، حيث إنها ستولد حمل إدخال / إخراج إضافي غير ضروري ، مما يؤثر على الأداء.

الكتابة إلى ملفات السجل الخاصة بك

توفر PHP نفسها وظائف لفتح ملفات السجل والكتابة إليها وإغلاقها ( openlog() و syslog() و closelog() على التوالي).

هناك أيضًا العديد من مكتبات التسجيل لمطوري PHP ، مثل Monolog (شائعة بين مستخدمي Symfony و Laravel) ، بالإضافة إلى العديد من التطبيقات الخاصة بإطار العمل ، مثل إمكانات التسجيل المدمجة في CakePHP. بشكل عام ، لا تقتصر مكتبات مثل Monolog على التفاف استدعاءات syslog() فحسب ، بل تسمح أيضًا باستخدام وظائف وأدوات أخرى للواجهة الخلفية.

فيما يلي مثال بسيط على كيفية الكتابة في السجل:

 <?php openlog(uniqid(), LOG_ODELAY, LOG_LOCAL0); syslog(LOG_INFO, 'It works!');

openlog هنا لفتح مدونة:

  • يقوم بتهيئة PHP لإرفاق معرف فريد مسبقًا لكل رسالة من رسائل سجل النظام خلال عمر البرنامج النصي
  • يعيّنه لتأخير فتح اتصال سجل النظام حتى يتم إجراء أول استدعاء syslog()
  • يعيّن LOG_LOCAL0 كأداة التسجيل الافتراضية

إليك الشكل الذي ستبدو عليه محتويات ملف السجل بعد تشغيل الكود أعلاه:

 # cat /var/log/my/info.log Mar 2 00:23:29 log-sandbox 54f39161a2e55: It works!

تعظيم قيمة ملفات سجل PHP الخاصة بك

الآن بعد أن أصبحنا جميعًا جيدًا فيما يتعلق بالنظرية والأساسيات ، دعنا نرى مقدار ما يمكننا الحصول عليه من السجلات التي تُجري أقل عدد ممكن من التغييرات على نموذج مشروع Symfony القياسي.

أولاً ، لنقم بإنشاء السكربتات src/log-begin.php (لفتح سجلاتنا وتكوينها بشكل صحيح) و src/log-end.php (لتسجيل المعلومات حول الإكمال الناجح). لاحظ أنه من أجل التبسيط ، سنقوم فقط بكتابة جميع الرسائل في سجل المعلومات.

 # src/log-begin.php <?php define('START_TIME', microtime(true)); openlog(uniqid(), LOG_ODELAY, LOG_LOCAL0); syslog(LOG_INFO, 'BEGIN'); syslog(LOG_INFO, "URI\t{$_SERVER['REQUEST_URI']}"); $browserHash = substr(md5($_SERVER['HTTP_USER_AGENT']), 0, 7); syslog(LOG_INFO, "CLIENT\t{$_SERVER['REMOTE_ADDR']}\t{$browserHash}"); <br /> # src/log-end.php <?php syslog(LOG_INFO, "DISPATCH TIME\t" . round(microtime(true) - START_TIME, 2)); syslog(LOG_INFO, 'END');

ودعنا نطلب هذه البرامج النصية في app.php :

 <?php require_once(dirname(__DIR__) . '/src/log-begin.php'); syslog(LOG_INFO, "MODE\tPROD"); # original app.php contents require_once(dirname(__DIR__) . '/src/log-end.php');

بالنسبة لبيئة التطوير ، نريد أن نطلب هذه البرامج النصية في app_dev.php أيضًا. سيكون رمز القيام بذلك هو نفسه كما هو مذكور أعلاه ، باستثناء أننا سنقوم بتعيين MODE على DEV بدلاً من PROD .

نريد أيضًا تتبع وحدات التحكم التي يتم استدعاؤها ، لذلك دعونا نضيف سطرًا آخر في Acme\DemoBundle\EventListener\ControllerListener ، مباشرة في بداية طريقة ControllerListener::onKernelController() :

 syslog(LOG_INFO, "CONTROLLER\t" . get_class($event->getController()[0]));

لاحظ أن إجمالي هذه التغييرات لا يتجاوز 15 سطرًا إضافيًا من التعليمات البرمجية ، ولكن يمكن أن تنتج مجتمعة ثروة من المعلومات.

تحليل البيانات في ملفات الدخول الخاصة بك

بالنسبة للمبتدئين ، دعنا نرى عدد طلبات HTTP المطلوبة لخدمة كل تحميل صفحة.

فيما يلي المعلومات الموجودة في السجلات لطلب واحد ، بناءً على الطريقة التي قمنا بتهيئة التسجيل لدينا:

 Mar 3 12:04:20 log-sandbox 54f58724b1ccc: BEGIN Mar 3 12:04:20 log-sandbox 54f58724b1ccc: URI /app_dev.php/ Mar 3 12:04:20 log-sandbox 54f58724b1ccc: CLIENT 192.168.56.1 1b101cd Mar 3 12:04:20 log-sandbox 54f58724b1ccc: MODE DEV Mar 3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLER Acme\DemoBundle\Controller\WelcomeController Mar 3 12:04:25 log-sandbox 54f58724b1ccc: DISPATCH TIME 4.51 Mar 3 12:04:25 log-sandbox 54f58724b1ccc: END Mar 3 12:04:25 log-sandbox 54f5872967dea: BEGIN Mar 3 12:04:25 log-sandbox 54f5872967dea: URI /app_dev.php/_wdt/59b8b6 Mar 3 12:04:25 log-sandbox 54f5872967dea: CLIENT 192.168.56.1 1b101cd Mar 3 12:04:25 log-sandbox 54f5872967dea: MODE DEV Mar 3 12:04:28 log-sandbox 54f5872967dea: CONTROLLER Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController Mar 3 12:04:29 log-sandbox 54f5872967dea: DISPATCH TIME 4.17 Mar 3 12:04:29 log-sandbox 54f5872967dea: END

نحن نعلم الآن أن كل تحميل صفحة يتم تقديمه فعليًا مع طلبي HTTP.

في الواقع هناك نقطتان جدير بالذكر هنا. أولاً ، الطلبان لكل تحميل صفحة مخصصان لاستخدام Symfony في وضع dev (وهو ما قمت به خلال هذه المقالة). يمكنك تحديد استدعاءات وضع dev بالبحث عن /app-dev.php/ URL chunks. ثانيًا ، لنفترض أن كل تحميل صفحة يتم تقديمه مع طلبين لاحقين لتطبيق Symfony. كما رأينا سابقًا في سجلات الوصول إلى nginx ، يوجد بالفعل المزيد من استدعاءات HTTP ، بعضها مخصص للمحتوى الثابت.

حسنًا ، دعنا الآن نتصفح قليلاً على الموقع التجريبي (لبناء البيانات في ملفات السجل) ودعنا نرى ما يمكننا تعلمه أيضًا من هذه السجلات.

كم عدد الطلبات التي تم تقديمها إجمالاً منذ بداية ملف السجل؟

 # grep -c BEGIN info.log 10

هل فشل أي منهم (هل تم إغلاق النص دون الوصول إلى النهاية)؟

 # grep -c END info.log 10

نرى أن عدد سجلات BEGIN و END متطابق ، لذلك يخبرنا هذا أن جميع المكالمات كانت ناجحة. (إذا لم يكتمل نص PHP بنجاح ، فلن يصل إلى تنفيذ البرنامج النصي src/log-end.php .)

ما هي النسبة المئوية للطلبات إلى جذر الموقع؟

 # `grep -cE "\s/app_dev.php/$" info.log` 2

يخبرنا هذا أنه تم تحميل صفحتين من جذر الموقع. نظرًا لأننا علمنا سابقًا أن (أ) هناك طلبان للتطبيق لكل تحميل صفحة و (ب) كان هناك ما مجموعه 10 طلبات HTTP ، كانت النسبة المئوية للطلبات إلى جذر الموقع 40٪ (أي 2x2 / 10).

ما فئة وحدة التحكم المسؤولة عن خدمة الطلبات إلى جذر الموقع؟

 # grep -E "\s/$|\s/app_dev.php/$" info.log | head -n1 Mar 3 12:04:20 log-sandbox 54f58724b1ccc: URI /app_dev.php/ # grep 54f58724b1ccc info.log | grep CONTROLLER Mar 3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLER Acme\DemoBundle\Controller\WelcomeController

استخدمنا هنا المعرف الفريد للطلب للتحقق من جميع رسائل السجل المتعلقة بهذا الطلب الفردي. وبالتالي تمكنا من تحديد أن فئة وحدة التحكم المسؤولة عن خدمة الطلبات إلى جذر الموقع هي Acme\DemoBundle\Controller\WelcomeController .

أي من العملاء الذين لديهم عناوين IP للشبكة الفرعية 192.168.0.0/16 قاموا بالوصول إلى الموقع؟

 # grep CLIENT info.log | cut -d":" -f4 | cut -f2 | sort | uniq 192.168.56.1

كما هو متوقع في حالة الاختبار البسيطة هذه ، تمكن الكمبيوتر المضيف فقط من الوصول إلى الموقع. هذا بالطبع مثال بسيط للغاية ، ولكن من الواضح أن القدرة التي يوضحها (القدرة على تحليل مصادر حركة المرور إلى موقعك) قوية ومهمة للغاية.

ما مقدار حركة المرور إلى موقعي من FireFox؟

بعد أن 1b101cd بمثابة تجزئة وكيل مستخدم Firefox الخاص بي ، يمكنني الإجابة على هذا السؤال على النحو التالي:

 # grep -c 1b101cd info.log 8 # grep -c CLIENT info.log 10

الإجابة: 80٪ (أي 8/10)

ما هي النسبة المئوية للطلبات التي أسفرت عن استجابة بطيئة؟

لأغراض هذا المثال ، سنعرّف "بطيء" على أنها تستغرق أكثر من 5 ثوانٍ لتقديم إجابة. وفقا لذلك:

 # grep "DISPATCH TIME" info.log | grep -cE "\s[0-9]{2,}\.|\s[5-9]\." 2

الإجابة: 20٪ (أي 2/10)

هل قام أي شخص بتزويد معلمات GET؟

 # grep URI info.log | grep \?

لا ، يستخدم معيار Symfony روابط عناوين URL فقط ، لذلك يخبرنا هذا أيضًا هنا أنه لم يحاول أحد اختراق الموقع.

هذه ليست سوى عدد قليل من الأمثلة البدائية نسبيًا للطرق التي يمكن من خلالها الاستفادة من ملفات السجلات بشكل إبداعي لإنتاج معلومات استخدام قيمة وحتى تحليلات أساسية.

أشياء أخرى يجب وضعها في الاعتبار

الحفاظ على الأشياء آمنة

تنبيه آخر يتعلق بالأمان. قد تعتقد أن طلبات التسجيل فكرة جيدة ، وهي كذلك بالفعل في معظم الحالات. ومع ذلك ، من المهم توخي الحذر الشديد بشأن إزالة أي معلومات يحتمل أن تكون حساسة قبل تخزينها في السجل.

القتال ملف الدخول سخام

نظرًا لأن ملفات السجل هي ملفات نصية تقوم دائمًا بإلحاق المعلومات بها ، فإنها تتزايد باستمرار. نظرًا لأن هذه مشكلة معروفة جيدًا ، فهناك بعض الأساليب القياسية للتحكم في نمو ملف السجل.

الأسهل هو تدوير السجلات . السجلات المتناوبة تعني:

  • استبدال السجل بشكل دوري بملف فارغ جديد لمزيد من الكتابة
  • تخزين الملف القديم للتاريخ
  • إزالة الملفات التي "قديمة" بشكل كافٍ لإخلاء مساحة على القرص
  • التأكد من أن التطبيق يمكنه الكتابة إلى وحدة السجلات عند حدوث تغييرات في الملف

الحل الأكثر شيوعًا لهذا هو logrotate ، والذي يتم شحنه مسبقًا مع معظم التوزيعات * nix. دعنا نرى ملف تكوين بسيط لتدوير سجلاتنا:

 /var/log/my/debug.log /var/log/my/info.log /var/log/my/warning.log /var/log/my/error.log { rotate 7 daily missingok notifempty delaycompress compress sharedscripts postrotate invoke-rc.d rsyslog rotate > /dev/null endscript }

طريقة أخرى أكثر تقدمًا هي جعل rsyslogd نفسه يكتب الرسائل في ملفات ، يتم إنشاؤها ديناميكيًا بناءً على التاريخ والوقت الحاليين. قد لا يزال هذا يتطلب حلاً مخصصًا لإزالة الملفات القديمة ، ولكنه يتيح للمطورين إدارة الأطر الزمنية لكل ملف سجل بدقة. على سبيل المثال لدينا:

 $template DynaLocal0Err, "/var/log/my/error-%$NOW%-%$HOUR%.log" $template DynaLocal0Info, "/var/log/my/info-%$NOW%-%$HOUR%.log" $template DynaLocal0Warning, "/var/log/my/warning-%$NOW%-%$HOUR%.log" $template DynaLocal0Debug, "/var/log/my/debug-%$NOW%-%$HOUR%.log" local1.err -?DynaLocal0Err local1.info -?DynaLocal0Info local1.warning -?DynaLocal0Warning local1.debug -?DynaLocal0Debug

بهذه الطريقة ، سيقوم rsyslog بإنشاء ملف سجل فردي كل ساعة ، ولن تكون هناك حاجة لتدويرهم وإعادة تشغيل البرنامج الخفي. إليك كيفية إزالة ملفات السجل التي مضى عليها أكثر من 5 أيام لإنجاز هذا الحل:

 find /var/log/my/ -mtime +5 -print0 | xargs -0 rm

السجلات عن بعد

مع نمو المشروع ، فإن تحليل المعلومات من السجلات يصبح أكثر وأكثر جوعًا للموارد. هذا لا يعني فقط إنشاء تحميل إضافي للخادم ؛ هذا يعني أيضًا إنشاء ذروة تحميل على وحدة المعالجة المركزية ومحركات الأقراص في الأوقات التي تقوم فيها بتحليل السجلات ، مما قد يؤدي إلى انخفاض وقت استجابة الخادم للمستخدمين (أو في أسوأ الحالات يمكن أن يؤدي إلى تعطيل الموقع).

لحل هذه المشكلة ، ضع في اعتبارك إنشاء خادم تسجيل مركزي . كل ما تحتاجه لهذا هو صندوق آخر به منفذ UDP 514 (افتراضي) مفتوح. لجعل rsyslogd يستمع إلى الاتصالات ، أضف السطر التالي إلى ملف التكوين الخاص به:

 $UDPServerRun 514

بعد ذلك ، يكون إعداد العميل سهلاً مثل:

 *.* @HOSTNAME:514

(حيث HOSTNAME هو اسم المضيف لخادم التسجيل عن بعد).

خاتمة

بينما أوضحت هذه المقالة بعض الطرق الإبداعية التي يمكن لملفات السجل من خلالها تقديم معلومات أكثر قيمة مما قد تتخيله سابقًا ، فمن المهم التأكيد على أننا خدشنا فقط سطح ما هو ممكن. إن مدى ونطاق وشكل ما يمكنك تسجيله لا حدود له تقريبًا. هذا يعني أنه - إذا كانت هناك بيانات استخدام أو تحليلات تريد استخراجها من سجلاتك - فأنت تحتاج ببساطة إلى تسجيلها بطريقة تجعل من السهل تحليلها وتحليلها لاحقًا. علاوة على ذلك ، يمكن إجراء هذا التحليل غالبًا باستخدام أدوات سطر أوامر Linux القياسية مثل grep أو sed أو awk .

في الواقع ، تعد ملفات سجل PHP من أقوى الأدوات التي يمكن أن تكون ذات فائدة هائلة.

موارد

كود على جيثب: https://github.com/isanosyan/toptal-blog-logs-post-example


ملحق: قراءة ملفات السجل ومعالجتها في غلاف Unix

فيما يلي مقدمة موجزة عن بعض أدوات سطر الأوامر * nix الأكثر شيوعًا والتي سترغب في التعرف عليها لقراءة ملفات السجل ومعالجتها.

  • ربما يكون cat هو أبسط واحد. يقوم بطباعة الملف بأكمله إلى تيار الإخراج. على سبيل المثال ، سيطبع الأمر التالي logfile1 إلى وحدة التحكم:

     cat logfile1
  • > حرف يسمح للمستخدم بإعادة توجيه الإخراج ، على سبيل المثال إلى ملف آخر. يفتح الدفق الهدف في وضع الكتابة (مما يعني مسح محتويات الهدف). إليك كيفية استبدال محتويات tmpfile بمحتويات logfile1 :

     cat logfile1 > tmpfile
  • >> يعيد توجيه الإخراج ويفتح دفق الهدف في وضع الإلحاق. سيتم الاحتفاظ بالمحتويات الحالية للملف الهدف ، وستتم إضافة أسطر جديدة إلى الأسفل. سيؤدي هذا إلى logfile1 محتويات ملف tmpfile :

     cat logfile1 >> tmpfile
  • grep يقوم بتصفية الملف من خلال بعض الأنماط ويطبع الأسطر المطابقة فقط. سوف يقوم الأمر أدناه بطباعة سطور logfile1 التي تحتوي على رسالة Bingo فقط:

     grep Bingo logfile1
  • cut محتويات مطبوعات عمود واحد (حسب الرقم الذي يبدأ من 1). عمليات البحث الافتراضية عن أحرف الجدولة كمحددات بين العمود. على سبيل المثال ، إذا كان لديك ملف مليء بالطوابع الزمنية بتنسيق YYYY-MM-DD HH:MM:SS ، فسيتيح لك ذلك طباعة السنوات فقط:

     cut -d"-" -f1 logfile1
  • يعرض head الأسطر الأولى فقط من الملف

  • يعرض tail فقط الأسطر الأخيرة من الملف

  • sort يفرز الأسطر في الإخراج

  • uniq يقوم بتصفية الأسطر المكررة

  • يحسب wc الكلمات (أو الأسطر عند استخدامها مع العلم -l )

  • | (على سبيل المثال ، رمز "الأنبوب") يوفر إخراجًا من أحد الأوامر كمدخلات إلى التالي. الأنبوب مناسب جدًا للجمع بين الأوامر. على سبيل المثال ، إليك كيفية العثور على أشهر 2014 التي تحدث ضمن مجموعة من الطوابع الزمنية:

     grep -E "^2014" logfile1 | cut -d"-" -f2 | sort | uniq

نقوم هنا أولاً بمطابقة الأسطر مع التعبير العادي "يبدأ بـ 2014" ، ثم نقطع الشهور. أخيرًا ، نستخدم مزيجًا من sort uniq لطباعة التكرارات مرة واحدة فقط.