مقدمة
يعتبر وحدة التسجيل (logging
) جزءًا من مكتبة بيثون القياسية وتوفر تتبعًا للأحداث التي تحدث أثناء تشغيل البرمجيات. يمكنك إضافة استدعاءات لتسجيل الحدث إلى كودك للإشارة إلى الأحداث التي قد حدثت.
تتيح وحدة التسجيل (logging
) كلاً من تسجيل العمليات التشخيصية التي تسجل الأحداث المتعلقة بعملية التطبيق، وكذلك تسجيل المراجعة التي تسجل أحداث معاملات المستخدم للتحليل. يُستخدم بشكل خاص لتسجيل الأحداث في ملف.
المتطلبات المسبقة
يجب أن يكون لديك بيثون 3 مثبتًا وبيئة برمجة مهيأة على جهاز الكمبيوتر الخاص بك أو الخادم. إذا لم يكن لديك بيئة برمجة مهيأة، يمكنك الرجوع إلى دليل التثبيت والإعداد لـ بيئة برمجة محلية أو لـ بيئة برمجة على خادمك مناسبة لنظام التشغيل الخاص بك (أوبونتو، سنتوس، ديبيان، إلخ.).
لماذا استخدام وحدة logging
تحتفظ وحدة logging
بسجل للأحداث التي تحدث داخل البرنامج، مما يجعل من الممكن رؤية الإخراج المتعلق بأي من الأحداث التي تحدث طوال وقت تشغيل قطعة من البرمجيات.
قد تكون أكثر توافقًا مع التحقق من حدوث الأحداث عن طريق استخدام بيان print()
في جميع أنحاء الكود الخاص بك. يقدم بيان print()
طريقة أساسية لتصحيح الأخطاء في الكود الخاص بك لحل المشاكل. بينما يمكن أن تتتبع بيانات print()
الموزعة في جميع أنحاء الكود تدفق التنفيذ والحالة الحالية لبرنامجك، يثبت أن هذا الحل أقل صيانة من استخدام وحدة logging
لأسباب عدة:
- يصبح من الصعب التمييز بين الإخراج لتصحيح الأخطاء والإخراج العادي للبرنامج لأن الاثنين مختلطين
- عند استخدام بيانات
print()
المتناثرة في جميع أنحاء الكود، لا يوجد طريقة فعالة لتعطيل تلك التي توفر إخراجًا لتصحيح الأخطاء - يصبح من الصعب إزالة جميع بيانات
print()
عند الانتهاء من عملية تصحيح الأخطاء - لا يوجد سجل سجل يحتوي على معلومات تشخيصية متاحة بسهولة
من الفكرة الجيدة العادة باستخدام وحدة logging
في كودك حيث أن هذا أكثر ملاءمة لتطبيقات تتجاوز النصوص البسيطة في Python ويوفر نهجًا مستدامًا لتصحيح الأخطاء.
لأن يمكن للسجلات أن تُظهر لك السلوك والأخطاء مع مرور الوقت، يمكنها أيضًا أن تعطيك صورة عامة أفضل عن ما يحدث في عملية تطوير التطبيق الخاص بك.
طباعة رسائل التصحيح إلى وحدة التحكم
معلومات: لمتابعة الأمثلة في هذا البرنامج التعليمي، قم بفتح وحدة Python التفاعلية على نظامك المحلي عن طريق تشغيل الأمر python3
. بعد ذلك يمكنك نسخ، لصق، أو تحرير الأمثلة عن طريق إضافتها بعد العلامة التفاعلية >>>
.
إذا كنت معتادًا على استخدام البيانات المطبوعة (print()
) لرؤية ما يحدث في برنامج ما، قد تكون معتادًا على رؤية برنامج يعرّف فئةً وينشئ كائنات تُولّد شيئًا مثل هذا:
الكود أعلاه يحتوي على طريقة __init__
لتحديد name
و price
لكائن من فئة Pizza
. بعد ذلك يحتوي على طريقتين، الأولى تسمى make()
لصنع البيتزا، والثانية تسمى eat()
لأكل البيتزا. تأخذ هاتان الطريقتان معلمة quantity
، التي تُبدأ بقيمة 1
.
الآن دعونا نشغل البرنامج:
سنتلقى الناتج التالي:
OutputPizza created: artichoke ($15)
Made 1 artichoke pizza(s)
Ate 1 pizza(s)
Pizza created: margherita ($12)
Made 2 margherita pizza(s)
Ate 1 pizza(s)
بينما تسمح العبارة print()
لنا برؤية أن الشفرة تعمل، يمكننا استخدام وحدة logging
بدلاً من ذلك.
لنقم بإزالة أو تعليق العبارات print()
في جميع أنحاء الشفرة، وإضافة import logging
إلى أعلى الملف:
تمتلك وحدة logging
مستوى افتراضي يساوي WARNING
، وهو مستوى يتبع DEBUG
. نظرًا لأننا سنستخدم وحدة logging
لتصحيح الأخطاء في هذا المثال، نحتاج إلى تعديل التكوين بحيث يعيد مستوى logging.DEBUG
المعلومات إلى وحدة التحكم بالنسبة لنا. يمكننا القيام بذلك عن طريق إضافة السطر التالي أسفل عبارة الاستيراد:
هذا المستوى من logging.DEBUG
يشير إلى قيمة صحيحة ثابتة نشير إليها في الشفرة أعلاه لتعيين عتبة. مستوى DEBUG
هو 10.
الآن، سنقوم بتبديل جميع العبارات print()
بعبارات logging.debug()
بدلاً من ذلك. على عكس logging.DEBUG
الذي هو ثابت، فإن logging.debug()
هو أسلوب من وحدة logging
. عند العمل بهذا الأسلوب، يمكننا الاستفادة من نفس النص المرسل إلى print()
، كما هو موضح في ما يلي:
في هذه النقطة، عند تشغيل البرنامج بالأمر python pizza.py
، سنتلقى هذا الإخراج:
OutputDEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)
تحتوي رسائل السجل على مستوى الخطورة DEBUG
بالإضافة إلى الكلمة root
مضمنة فيها، والتي تشير إلى مستوى وحدة Python الخاصة بك. يمكن استخدام وحدة logging
مع تسلسل هرمي من السجلات التي تحمل أسماءً مختلفة، بحيث يمكنك استخدام سجل مختلف لكل من وحداتك.
على سبيل المثال، يمكنك تعيين السجلات مساوية لسجلات مختلفة تحمل أسماء مختلفة ومخرجات مختلفة:
OutputDEBUG:module_1:Module 1 debugger
DEBUG:module_2:Module 2 debugger
الآن بعد أن فهمنا كيفية استخدام وحدة logging
لطباعة الرسائل إلى وحدة التحكم، دعونا ننتقل إلى استخدام وحدة logging
لطباعة الرسائل إلى ملف.
تسجيل الرسائل إلى ملف
الغرض الرئيسي من وحدة logging
هو تسجيل الرسائل إلى ملف بدلاً من وحدة التحكم. يوفر الاحتفاظ بملف الرسائل لديك بيانات مع الوقت يمكنك الرجوع إليها وقياسها بحيث يمكنك رؤية التغييرات التي يجب إجراؤها على كودك.
للبدء في تسجيل الرسائل إلى ملف، يمكننا تعديل طريقة logging.basicConfig()
لتضمين معلمة filename
. في هذه الحالة، دعونا نسمي اسم الملف test.log
:
الكود أعلاه هو نفسه كما كان في القسم السابق، باستثناء أننا أضفنا الآن اسم الملف للسجل ليتم طباعته. بمجرد تشغيل الكود بأمر python pizza.py
، يجب أن يكون لدينا ملف جديد في دليلنا يسمى test.log
.
لنفتح ملف test.log
باستخدام nano (أو محرر النص الذي تختاره):
عندما يتم فتح الملف، سنحصل على ما يلي:
DEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)
هذا مشابه لمخرجات الوحدة التحكم التي واجهناها في القسم السابق، ولكن الآن في ملف test.log
.
لنغلق الملف بالضغط على CTRL
+ x
وننتقل مرة أخرى إلى ملف pizza.py
لنقوم بتعديل الكود.
سنحتفظ بالجزء الأكبر من الكود بنفسه، ولكن سنعدل المعلمات في حالتي البيتزا، pizza_01
و pizza_02
:
مع هذه التغييرات، لنقم بتشغيل البرنامج مرة أخرى باستخدام الأمر python pizza.py
.
بمجرد تشغيل البرنامج، يمكننا فتح ملف test.log
مرة أخرى باستخدام nano:
عندما نراجع الملف، سنرى أن تمت إضافة عدة أسطر جديدة، وأن الأسطر السابقة من آخر مرة تم فيها تشغيل البرنامج تم الاحتفاظ بها:
DEBUG:root:Pizza created: artichoke ($15)
DEBUG:root:Made 1 artichoke pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: margherita ($12)
DEBUG:root:Made 2 margherita pizza(s)
DEBUG:root:Ate 1 pizza(s)
DEBUG:root:Pizza created: Sicilian ($18)
DEBUG:root:Made 5 Sicilian pizza(s)
DEBUG:root:Ate 4 pizza(s)
DEBUG:root:Pizza created: quattro formaggi ($16)
DEBUG:root:Made 2 quattro formaggi pizza(s)
DEBUG:root:Ate 2 pizza(s)
على الرغم من أن هذه المعلومات مفيدة بالتأكيد، يمكننا جعل السجل أكثر معلوماتية عن طريق إضافة سمات سجل السجل إضافية. بشكل رئيسي، نود إضافة طابع زمني قابل للقراءة من الإنسان يخبرنا متى تم إنشاء سجل السجل.
يمكننا إضافة ذلك السمة إلى معامل يسمى format
، مشيرين إليه كما هو موضح في الجدول بالسلسلة %(asctime)s
. بالإضافة إلى ذلك، للحفاظ على اسم مستوى التصحيح DEBUG
، سنحتاج إلى تضمين السلسلة %(levelname)s
وللحفاظ على الرسالة التي نطلب من المسجل طباعتها، سنضمن %(message)s
. سيتم فصل كل من هذه السمات بواسطة colon
، كما هو موضح في الكود المضاف:
عند تشغيل الكود أعلاه مع السمات المضافة باستخدام الأمر python pizza.py
، سنحصل على أسطر جديدة مُضافة إلى ملف test.log
الخاص بنا تتضمن الطابع الزمني القابل للقراءة بالإضافة إلى اسم المستوى DEBUG
والرسائل المرتبطة التي يتم تمريرها إلى المسجل كسلاسل.
DEBUG:root:Pizza created: Sicilian ($18)
DEBUG:root:Made 5 Sicilian pizza(s)
DEBUG:root:Ate 4 pizza(s)
DEBUG:root:Pizza created: quattro formaggi ($16)
DEBUG:root:Made 2 quattro formaggi pizza(s)
DEBUG:root:Ate 2 pizza(s)
2021-08-19 23:31:34,484:DEBUG:Pizza created: Sicilian ($18)
2021-08-19 23:31:34,484:DEBUG:Made 5 Sicilian pizza(s)
2021-08-19 23:31:34,484:DEBUG:Ate 4 pizza(s)
2021-08-19 23:31:34,484:DEBUG:Pizza created: quattro formaggi ($16)
2021-08-19 23:31:34,484:DEBUG:Made 2 quattro formaggi pizza(s)
2021-08-19 23:31:34,484:DEBUG:Ate 2 pizza(s)
بناءً على احتياجاتك، قد ترغب في الاستفادة من سمات سجل السجل الإضافية في الكود الخاص بك من أجل جعل سجلات ملفات برنامجك ذات صلة بك.
تسجيل الرسائل التصحيحية وغيرها في ملفات منفصلة يوفر لك فهمًا شاملاً لبرنامج Python الخاص بك مع مرور الوقت، مما يمنحك الفرصة لتحديد المشاكل وتعديل الكود بطريقة مستندة إلى العمل التاريخي الذي تم إجراؤه على البرنامج، بالإضافة إلى الأحداث والمعاملات التي تحدث.
جدول المستويات الخاص بالتسجيل
كمطوّر، يمكنك تعيين مستوى أهمية للحدث الذي يتم التقاطه في السجل بإضافة مستوى شدة. يُعرض مستويات الشدة في الجدول أدناه.
مستويات تسجيل الأحداث هي عبارة عن أعداد صحيحة (ثوابت)، وهي كلها بزيادات قدرها 10، بدءًا من NOTSET
الذي يبدأ السجل عند القيمة الرقمية 0.
يمكنك أيضًا تحديد مستويات مخصصة بالنسبة إلى المستويات المحددة مسبقًا. إذا قمت بتعريف مستوى بنفس القيمة الرقمية، فسوف تستبدل الاسم المرتبط بهذه القيمة.
يوضح الجدول التالي أسماء المستويات المختلفة، قيمها الرقمية، وظيفة الدالة التي يمكنك استدعاء المستوى من خلالها، وما هو استخدام هذا المستوى.
Level | Numeric Value | Function | Used to |
---|---|---|---|
CRITICAL |
50 | logging.critical() |
Show a serious error, the program may be unable to continue running |
ERROR |
40 | logging.error() |
Show a more serious problem |
WARNING |
30 | logging.warning() |
Indicate something unexpected happened, or could happen |
INFO |
20 | logging.info() |
Confirm that things are working as expected |
DEBUG |
10 | logging.debug() |
Diagnose problems, show detailed information |
يقوم وحدة logging
بتعيين المستوى الافتراضي عند WARNING
، لذا فإن WARNING
و ERROR
و CRITICAL
ستتم تسجيلها بشكل افتراضي. في المثال أعلاه، قمنا بتعديل التكوين لتضمين مستوى DEBUG
باستخدام الكود التالي:
يمكنك قراءة المزيد عن الأوامر والعمل مع مصحح الأخطاء من التوثيق الرسمي لـ logging
.
الاستنتاج
تعتبر عملية التصحيح خطوة مهمة في أي مشروع تطوير برمجيات. الوحدة النمطية logging
جزء من مكتبة Python القياسية، توفر تتبعًا للأحداث التي تحدث أثناء تشغيل البرمجيات، ويمكنها إخراج هذه الأحداث إلى ملف سجل منفصل للسماح لك بتتبع ما يحدث أثناء تشغيل كودك. هذا يوفر لك الفرصة لتصحيح كودك بناءً على فهم الأحداث المختلفة التي تحدث من تشغيل برنامجك بمرور الوقت.
Source:
https://www.digitalocean.com/community/tutorials/how-to-use-logging-in-python-3