بايثون بعد الأساسيات 5: شرح logging في Python لتسجيل أحداث البرنامج والأخطاء

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

هنا تأتي مكتبة logging المدمجة مع Python. بدل أن تضع عشرات أوامر الطباعة داخل المشروع، يمكنك تسجيل الأحداث المهمة بمستويات واضحة، ثم عرضها في الطرفية أو حفظها داخل ملف للرجوع إليها لاحقًا.

شرح logging في Python لتسجيل أحداث البرنامج والأخطاء
{alertInfo} الفكرة ببساطة: استخدم print() عندما تريد عرض نتيجة عادية للمستخدم، واستخدم logging عندما تريد تسجيل ما يحدث داخل البرنامج لمتابعة الحالة أو تشخيص مشكلة أو حفظ سجل للأخطاء.

{getToc} $title={محتوى المقال}

ما هي مكتبة logging في Python؟

logging هي مكتبة قياسية تأتي مع Python، لذلك لا تحتاج إلى تثبيتها عبر pip. مهمتها تسجيل رسائل منظمة تصف أحداث البرنامج أثناء تشغيله، مثل بدء مهمة، نجاح قراءة ملف، ظهور إدخال غير مناسب، أو حدوث خطأ.

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

هذا مهم خصوصًا بعد أن بدأت في بناء مشاريع منظمة، مثل مشروع CSV أو أداة سطر أوامر CLI. في هذه المرحلة لم يعد السؤال فقط: “هل يعمل البرنامج؟” بل: “ماذا حدث داخله عندما لم يعمل كما توقعت؟”

الفرق بين print وlogging

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

لا يعني هذا أنك يجب أن تحذف print() من كل مشروع. البرامج التي تتعامل مع المستخدم في الطرفية تحتاج رسائل واضحة مثل “تم الحفظ بنجاح”. أما logging فيعمل كدفتر ملاحظات تقني للمشروع والمطور.

مستويات الرسائل في logging

تستخدم logging مستويات مختلفة لتوضح مدى أهمية الحدث. الترتيب التالي يساعدك في اختيار المستوى المناسب:

المستوىمتى تستخدمه؟مثال
DEBUGتفاصيل دقيقة تساعدك أثناء التطوير والتشخيص.عدد الصفوف التي قرأها البرنامج من ملف CSV.
INFOحدث طبيعي مهم أثناء سير البرنامج.تم حفظ التقرير بنجاح.
WARNINGحدث غير مثالي، لكن البرنامج ما زال قادرًا على الاستمرار.الملف غير موجود، لذلك سيتم إنشاء ملف جديد.
ERRORفشل حدث محدد ويحتاج إلى مراجعة.تعذر قراءة البيانات بسبب تنسيق غير صالح.
CRITICALمشكلة كبيرة قد تمنع البرنامج من العمل بشكل أساسي.تعذر بدء التطبيق لأن ملف الإعدادات الرئيسي تالف.
مستويات logging في Python من DEBUG إلى CRITICAL

أول مثال: تسجيل رسالة بسيطة

ابدأ باستيراد المكتبة، ثم استخدم basicConfig() لتحديد أقل مستوى تريد إظهاره. في المثال التالي سنعرض رسائل INFO وما فوقها:

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(levelname)s - %(message)s"
)

logging.debug("هذه رسالة تفصيلية للتشخيص")
logging.info("تم تشغيل البرنامج بنجاح")
logging.warning("لم يتم العثور على صورة المستخدم")

لن تظهر رسالة DEBUG هنا، لأننا حددنا المستوى INFO. لكن رسالتي INFO وWARNING ستظهران.

INFO - تم تشغيل البرنامج بنجاح
WARNING - لم يتم العثور على صورة المستخدم

جرّب تغيير level=logging.INFO إلى level=logging.DEBUG ثم شغّل الكود مرة أخرى. ستظهر الرسالة التفصيلية أيضًا.

إضافة الوقت إلى السجل

عندما تتكرر عمليات البرنامج، تصبح معرفة وقت الحدث مهمة. يمكنك إضافة التاريخ والوقت إلى شكل السجل باستخدام %(asctime)s:

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
)

logging.info("بدأت عملية إنشاء التقرير")
logging.info("انتهت عملية إنشاء التقرير")

قد يكون الناتج بهذا الشكل:

2026-07-02 20:15:03 | INFO | بدأت عملية إنشاء التقرير
2026-07-02 20:15:04 | INFO | انتهت عملية إنشاء التقرير

الوقت الظاهر يعتمد على وقت جهازك أو بيئة التشغيل التي يعمل عليها البرنامج.

كيف تحفظ السجلات داخل ملف؟

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

import logging

logging.basicConfig(
    filename="app.log",
    encoding="utf-8",
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s"
)

logging.info("بدأ البرنامج")
logging.warning("تم استخدام قيمة افتراضية")
logging.error("تعذر حفظ التقرير")

بعد تشغيل الملف، سيظهر بجانبه ملف جديد باسم app.log. بشكل افتراضي، يضيف Python السجلات الجديدة إلى نهاية الملف بدل حذف السجل السابق.

تسجيل رسائل Python في الشاشة وملف log
{alertWarning} ملاحظة مهمة: لا تضع basicConfig() في ملفات كثيرة داخل المشروع. الأفضل أن تضبط إعدادات logging مرة واحدة عند بداية تشغيل التطبيق، ثم تستخدم التسجيل في بقية الملفات.

استخدام logger باسم الملف

في المشروع الصغير يمكن استعمال logging.info() مباشرة. لكن عندما يصبح المشروع من عدة ملفات، من الأفضل إنشاء logger باسم كل ملف. الطريقة الشائعة هي استخدام __name__:

import logging

logger = logging.getLogger(__name__)

logger.info("تمت قراءة ملف البيانات")
logger.warning("بعض الصفوف تحتوي على قيم ناقصة")

وعند ضبط التنسيق، يمكنك إظهار اسم logger أيضًا:

format="%(asctime)s | %(name)s | %(levelname)s | %(message)s"

هذا يصبح مفيدًا عندما تريد معرفة أي جزء من المشروع سجل الرسالة: ملف قراءة البيانات، أو ملف الحسابات، أو ملف واجهة سطر الأوامر.

تسجيل الأخطاء مع try و except

تعلمت سابقًا استخدام try وexcept حتى لا يتوقف البرنامج فجأة. الآن يمكنك جعل التعامل مع الخطأ أكثر فائدة عبر تسجيله أيضًا.

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

import json
import logging
from pathlib import Path

logging.basicConfig(
    filename="app.log",
    encoding="utf-8",
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s"
)

logger = logging.getLogger(__name__)
file_path = Path("data.json")

try:
    content = file_path.read_text(encoding="utf-8")
    data = json.loads(content)
    logger.info("تمت قراءة البيانات بنجاح")
    print(data)

except FileNotFoundError:
    logger.warning("ملف data.json غير موجود")
    print("لم يتم العثور على ملف البيانات.")

except json.JSONDecodeError:
    logger.exception("محتوى ملف JSON غير صالح")
    print("محتوى ملف البيانات غير صحيح.")

الدالة logger.exception() تستخدم داخل except عندما تريد تسجيل رسالة الخطأ مع تفاصيل الاستثناء. هذا مفيد للتشخيص، لكنه لا يعني أن تعرض تلك التفاصيل التقنية كاملة للمستخدم النهائي.

استخدام logger exception مع try except في Python

مشروع صغير: سجل عمليات برنامج مهام

لنطبق الفكرة في مثال قريب من المشاريع الواقعية. البرنامج التالي يضيف مهمة إلى ملف نصي، ثم يسجل نجاح العملية أو فشلها في ملف logs/app.log.

هيكل المشروع

task_manager/
│
├── main.py
├── tasks.txt
└── logs/
    └── app.log

ملف main.py

import logging
from pathlib import Path

BASE_DIR = Path(__file__).parent
LOGS_DIR = BASE_DIR / "logs"
TASKS_FILE = BASE_DIR / "tasks.txt"

LOGS_DIR.mkdir(exist_ok=True)

logging.basicConfig(
    filename=LOGS_DIR / "app.log",
    encoding="utf-8",
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s"
)

logger = logging.getLogger(__name__)

task = input("اكتب المهمة الجديدة: ").strip()

if not task:
    logger.warning("حاول المستخدم إضافة مهمة فارغة")
    print("لا يمكن إضافة مهمة فارغة.")
else:
    try:
        with TASKS_FILE.open("a", encoding="utf-8") as file:
            file.write(task + "\n")

        logger.info("تمت إضافة مهمة جديدة")
        print("تمت إضافة المهمة بنجاح.")

    except OSError:
        logger.exception("فشلت عملية حفظ المهمة")
        print("تعذر حفظ المهمة. حاول مرة أخرى.")

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

تنظيم ملفات السجلات logging داخل مشروع Python

أخطاء شائعة عند استخدام logging

1. توقع ظهور رسائل DEBUG دون تغيير المستوى

المستوى الافتراضي لا يعرض رسائل DEBUG. إذا كنت تحتاجها أثناء التشخيص، اضبط level=logging.DEBUG.

2. استدعاء basicConfig أكثر من مرة دون تنظيم

في أغلب المشاريع، اضبط الإعدادات عند بداية البرنامج فقط. ثم أنشئ loggers في الملفات الأخرى باستخدام getLogger(__name__).

3. استخدام logging بدل الاستثناءات

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

4. تسجيل بيانات حساسة

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

5. جعل السجل مليئًا برسائل غير مفيدة

لا تسجل كل سطر من البرنامج. سجل القرارات والعمليات المهمة: بداية مهمة، نجاح عملية، تحذير يستحق المراجعة، أو خطأ يحتاج تشخيصًا.

متى تستخدم logging في مشاريعك؟

  • عند بناء أداة سطر أوامر CLI تحتاج إلى تتبع الأوامر أو الأخطاء.
  • عند قراءة ملفات CSV أو JSON وتريد معرفة سبب فشل عملية القراءة أو الحفظ.
  • عند إنشاء تقارير أو ملفات تلقائيًا وتريد حفظ تاريخ العمليات.
  • عند وجود أكثر من ملف داخل المشروع وتحتاج معرفة مصدر كل رسالة.
  • عند تشغيل برنامج متكرر أو طويل لا تكون موجودًا أمامه طوال الوقت.

روابط داخلية مفيدة من بايثون العرب

الخلاصة

  • print() مناسب لعرض نتائج عادية للمستخدم، بينما logging مناسب لتسجيل أحداث البرنامج وتشخيص المشكلات.
  • استخدم مستويات الرسائل لتوضيح أهمية الحدث: DEBUG وINFO وWARNING وERROR وCRITICAL.
  • يمكنك حفظ السجلات داخل ملف .log ومراجعته عند حدوث مشكلة لاحقًا.
  • استخدم logger.exception() داخل except عندما تريد تسجيل تفاصيل الاستثناء.
  • اضبط إعدادات التسجيل مرة واحدة عند بداية المشروع، وتجنب كتابة بيانات حساسة في ملفات السجل.
{alertSuccess} خطوتك التالية: افتح مشروعًا صغيرًا كتبته سابقًا، وأضف سجلًا واحدًا لبدء البرنامج، وسجلًا لنجاح عملية أساسية، وسجلًا للأخطاء داخل except. بهذه الخطوة يتحول مشروعك من مثال تعليمي إلى برنامج أسهل في المتابعة والصيانة.

مصادر خارجية رسمية للتوسع

أسئلة شائعة

هل أحتاج إلى تثبيت logging باستخدام pip؟

لا. مكتبة logging جزء من مكتبة Python القياسية، لذلك يكفي أن تكتب import logging.

هل أستبدل print بالكامل بـ logging؟

لا. استخدم print() للرسائل والنتائج التي يجب أن يراها مستخدم البرنامج مباشرة. واستخدم logging لتسجيل أحداث التشغيل والتفاصيل التقنية والأخطاء.

أين أضع basicConfig في المشروع؟

ضعه عادةً في الملف الذي يبدأ تشغيل التطبيق، مثل main.py. لا تكرر الإعدادات في كل ملف، ثم استخدم getLogger(__name__) داخل الملفات الأخرى.

هل يمكن أن أحفظ السجلات في ملف وعرضها في الطرفية معًا؟

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

هل logger.exception مختلف عن logger.error؟

نعم. داخل كتلة except، تستخدم logger.exception() عندما تريد تسجيل الرسالة مع تفاصيل الاستثناء. أما logger.error() فيسجل رسالة خطأ فقط ما لم تمرر له معلومات إضافية.

إرسال تعليق

أحدث أقدم