FA-TOOLS — Header Component

آموزش logging در پایتون: ثبت لاگ حرفه‌ای پروژه

خلاصه این مقاله:

در این راهنما یاد می‌گیرید که چطور سیستم لاگ‌نویسی پروژه‌های پایتون خود را از حالت سنتی (print) به ساختار استاندارد و حرفه‌ای تبدیل کنید. با سطوح مختلف لاگ، مدیریت همزمان خروجی‌ها (فایل و کنسول)، چرخشی کردن فایل‌های لاگ برای جلوگیری از پر شدن دیسک و فرمت‌بندی استاندارد پیام‌ها به‌صورت گام‌به‌گام و با کدهای کاملاً کاربردی آشنا خواهید شد.

۱. چرا print برای پروژه‌های واقعی مناسب نیست؟

آموزش logging در پایتون: ثبت لاگ حرفه‌ای پروژه — تصویر 1

استفاده از دستور print برای ردیابی خطاها در کدهای بزرگ مانند رانندگی در شب بدون چراغ جلو است؛ شاید کار کند، اما به محض بروز اولین مشکل بزرگ، متوقف خواهید شد. تابع print امکان جداسازی سطح اهمیت خطاها را ندارد، نمی‌تواند پیام‌ها را به فایل‌های مجزا هدایت کند و در محیط پروداکشن کارایی سیستم را به شدت کاهش می‌دهد.

در پروژه‌های واقعی و تجاری، نیاز داریم بدانیم خطا در چه ثانیه‌ای، در کدام خط از کدام فایل و با چه درجه‌ای از اهمیت رخ داده است. ماژول بومی logging در پایتون تمام این ابزارها را بدون نیاز به نصب کتابخانه‌های جانبی در اختیار ما قرار می‌دهد تا بتوانیم جریان اجرای برنامه را به طور دقیق رصد کنیم.

۲. سطوح مختلف لاگ‌نویسی (Log Levels) و کاربرد آن‌ها

آموزش logging در پایتون: ثبت لاگ حرفه‌ای پروژه — تصویر 2

سطوح لاگ‌نویسی به ما کمک می‌کنند تا پیام‌های خود را بر اساس درجه اهمیت دسته‌بندی کنیم. این کار به برنامه‌نویس و تیم دونده پروژه اجازه می‌دهد تا در زمان بروز خطا، فقط پیام‌های بحرانی را فیلتر کرده و سریع‌تر به مشکل اصلی برسند.

سطح لاگ (Level) کاربرد عملی و زمان استفاده
DEBUG اطلاعات بسیار جزئی برای برنامه‌نویس در زمان عیب‌یابی کدهایی مثل مقادیر متغیرها.
INFO تایید عملکرد درست بخش‌های مختلف برنامه (مانند اتصال موفق به پایگاه داده).
WARNING هشدارهایی درباره اتفاقات غیرمنتظره که مانع کار برنامه نمی‌شوند ولی نیاز به بررسی دارند.
ERROR وقوع خطای جدی در برنامه که باعث شده یکی از عملیات‌ها با شکست مواجه شود.
CRITICAL خطای بسیار حیاتی که کل سیستم را متوقف کرده و برنامه دیگر قادر به ادامه کار نیست.

۳. شروع سریع با ابزار basicConfig

آموزش logging در پایتون: ثبت لاگ حرفه‌ای پروژه — تصویر 3

ساده‌ترین راه برای شروع کار با سیستم ثبت لاگ پایتون، استفاده از متد basicConfig است. با این متد می‌توانید به سرعت مشخص کنید که لاگ‌ها در چه فایلی ذخیره شوند و فرمت نمایش آن‌ها چگونه باشد.

import logging

# تنظیمات پایه سیستم لاگ
logging.basicConfig(
    filename='app.log',
    filemode='w',
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

# ثبت چند پیام نمونه
logging.debug("این یک پیام دیباگ است")
logging.info("یک رویداد عادی در برنامه رخ داده است")
logging.warning("هشدار: حافظه موقت در حال پر شدن است")
logging.error("خطا در اتصال به سرور")

در کد بالا، پارامتر level=logging.DEBUG مشخص می‌کند که تمام پیام‌های هم‌رده دیباگ و بالاتر از آن ثبت شوند. پارامتر format نیز ساختار ذخیره‌سازی پیام‌ها را تعیین می‌کند که شامل زمان دقیق، نام لاگر، سطح لاگ و متن اصلی پیام است.

۴. معماری پیشرفته سیستم Logging در پایتون

آموزش logging در پایتون: ثبت لاگ حرفه‌ای پروژه — تصویر 4

برای پروژه‌های بزرگ، متد basicConfig کافی نیست. معماری استاندارد لاگ در پایتون بر پایه چهار مفهوم اصلی بنا شده است که هر کدام وظیفه مشخصی بر عهده دارند:

  • Loggers (لاگرها): نقطه ورود برنامه برای ارسال پیام‌ها. ما معمولاً برای هر ماژول یک لاگر اختصاصی با نام همان ماژول می‌سازیم.
  • Handlers (هندلرها): تعیین می‌کنند که پیام‌ها به کجا فرستاده شوند؛ مثلاً چاپ روی صفحه نمایش، نوشتن در فایل یا حتی ارسال به یک ایمیل یا سرور مرکزی.
  • Formatters (فرمت‌دهنده‌ها): ساختار نهایی و ظاهر متنی پیام خروجی را مشخص می‌کنند.
  • Filters (فیلترها): فیلترینگ دقیق‌تر پیام‌ها بر اساس معیارهایی فراتر از سطح لاگ ساده.

نکته فنی بسیار مهم:

به طور پیش‌فرض، لاگرها پیام‌های خود را به لاگر والد (Root Logger) ارسال می‌کنند. اگر هندلرهای متعددی تعریف کنید و گزینه propagate را روی False تنظیم نکنید، ممکن است پیام‌های تکراری در خروجی‌های مختلف شما چاپ شود.

۵. پیاده‌سازی عملی: لاگ همزمان در کنسول و فایل

آموزش logging در پایتون: ثبت لاگ حرفه‌ای پروژه — تصویر 5

در یک سناریوی واقعی، ما می‌خواهیم خطاهای بحرانی (Error) را در یک فایل دائمی ذخیره کنیم و در عین حال، تمام رویدادها (مانند Info و Debug) را در کنسول سیستم مشاهده کنیم تا هنگام توسعه متوجه روند کارکرد برنامه بشویم.

کد زیر یک الگوی آماده و ساختاریافته برای این هدف است که می‌توانید در بخش‌های مختلف برنامه خود کپی کنید. برای دسترسی به تمپلیت‌های مشابه کدهای پایتونی، می‌توانید از بخش تکه‌کدهای پایتون در سایت ما استفاده کنید:

import logging

def setup_custom_logger(name):
    # ۱. ایجاد یک لاگر اختصاصی
    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG) # پذیرش تمامی سطوح لاگ از منبع

    # ۲. ایجاد فرمت‌های متفاوت برای فایل و کنسول
    file_formatter = logging.Formatter('%(asctime)s - %(name)s - [%(levelname)s] - %(message)s')
    console_formatter = logging.Formatter('%(name)s: %(message)s')

    # ۳. تعریف هندلر مربوط به ذخیره در فایل (فقط خطاهای Error به بالا)
    file_handler = logging.FileHandler('errors.log', encoding='utf-8')
    file_handler.setLevel(logging.ERROR)
    file_handler.setFormatter(file_formatter)

    # ۴. تعریف هندلر مربوط به نمایش در کنسول (تمامی پیام‌ها)
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.DEBUG)
    console_handler.setFormatter(console_formatter)

    # ۵. اتصال هندلرها به لاگر اصلی
    logger.addHandler(file_handler)
    logger.addHandler(console_handler)

    return logger

# استفاده عملی از لاگر ساخته شده
logger = setup_custom_logger("PaymentModule")
logger.info("ماژول پرداخت با موفقیت لود شد.")
try:
    result = 10 / 0
except ZeroDivisionError:
    logger.error("تقسیم بر صفر رخ داده است!", exc_info=True)

یکی از ویژگی‌های بسیار مهم در قطعه کد بالا استفاده از پارامتر exc_info=True در زمان ثبت خطا است. این کار باعث می‌شود کل ساختار خطا (Traceback) در فایل لاگ ثبت شود که برای اشکال‌زدایی کدهای پیچیده بسیار حیاتی است.

۶. نکات حرفه‌ای برای محیط پروداکشن (تولید)

هنگامی که پروژه شما وارد دنیای واقعی می‌شود و کاربران زیادی از آن استفاده می‌کنند، رفتار سیستم لاگ‌نویسی باید بهینه‌تر شود تا از مشکلاتی مثل پر شدن هارددیسک یا افت سرعت سرور جلوگیری شود.

استفاده از RotatingFileHandler

اگر لاگ‌های خود را در یک فایل معمولی ذخیره کنید، حجم آن به مرور زمان به چند گیگابایت می‌رسد و باز کردن آن عملاً غیرممکن می‌شود. با استفاده از این قابلیت، حجم فایل‌های لاگ را محدود می‌کنید تا به محض رسیدن به حجم مشخص، فایل قدیمی آرشیو شده و فایل جدیدی ساخته شود:

from logging.handlers import RotatingFileHandler
import logging

# ایجاد هندلر چرخشی با حداکثر حجم ۵ مگابایت و نگهداری حداکثر ۳ فایل قدیمی
rotating_handler = RotatingFileHandler(
    'app_rotating.log', 
    maxBytes=5*1024*1024, 
    backupCount=3,
    encoding='utf-8'
)

ثبت لاگ‌ها به صورت ساختاریافته (JSON Logging)

در سیستم‌های مانیتورینگ مدرن مانند ELK (Elasticsearch, Logstash, Kibana) تحلیل متن‌های ساده کار مشکلی است. تبدیل خروجی لاگ‌ها به فرمت JSON به شما کمک می‌کند تا به راحتی فیلترهای پیشرفته بر روی داده‌های مانیتورینگ خود اعمال کنید.

۷. اشتباهات متداول در لاگ‌نویسی پایتون

برنامه‌نویسان زیادی حتی با وجود سال‌ها تجربه، در نوشتن اصولی لاگ‌ها دچار اشتباهات تکراری می‌شوند. در ادامه سه مورد از بدترین عادت‌ها را بررسی می‌کنیم:

  • فرمت‌بندی رشته‌ها با f-string قبل از ارسال: نوشتن خط کدی مثل logging.info(f"کاربر {user} وارد شد") اشتباه است؛ زیرا رشته‌ها حتی اگر سطح لاگ فعال نباشد هم پردازش می‌شوند که باعث اتلاف منابع خواهد شد. شیوه درست استفاده از ساختار استاندارد لاگ است: logging.info("کاربر %s وارد شد", user).
  • بی‌توجهی به مدیریت استثناها (Exceptions): نوشتن لاگ خطا بدون جزئیات سیستم و صرفاً با یک متن دلخواه، پیدا کردن ریشه خطا را عملاً ناممکن می‌سازد. همواره از logger.exception() در بلاک‌های catch استفاده کنید.
  • ترکیب نکردن لاگ‌نویسی کتابخانه‌های ثالث: کتابخانه‌هایی مثل Request یا SQLAlchemy لاگ‌های خود را دارند. عدم پیکربندی درست باعث پر شدن خروجی شما از پیام‌های بی‌اهمیت این کتابخانه‌ها می‌شود.

۸. عیب‌یابی سریع مشکلات Logging

در این بخش به بررسی رایج‌ترین مشکلاتی که توسعه‌دهندگان هنگام کار با این ماژول با آن‌ها روبرو می‌شوند، می‌پردازیم:

مشکل اول: هیچ پیامی در کنسول یا فایل لاگ چاپ نمی‌شود.

راه‌حل: مطمئن شوید که سطح اهمیت پیام ارسالی شما پایین‌تر از حد مجاز تعریف شده در لاگر یا هندلر نباشد. به صورت پیش‌فرض، سطح پایه پایتون بر روی WARNING تنظیم شده است؛ پس پیام‌های DEBUG و INFO چاپ نخواهند شد مگر اینکه سطح پیش‌فرض را به صورت دستی تغییر دهید.

مشکل دوم: پیام‌ها به صورت دوگانه یا تکراری در کنسول چاپ می‌شوند.

راه‌حل: این مشکل معمولاً به دلیل انتشار مجدد پیام از لاگر فرزند به والد رخ می‌دهد. برای رفع آن، ویژگی انتشار پیام را در لاگر اختصاصی خود غیرفعال کنید: logger.propagate = False.

مشکل سوم: فونت‌های فارسی در فایل‌های ذخیره شده به صورت ناخوانا یا علامت سوال دیده می‌شوند.

راه‌حل: در هنگام تعریف هندلر فایل، حتماً مقدار آرگومان فرمت یونیکد را به صورت صریح بر روی encoding='utf-8' تنظیم کنید.

۹. پرسش‌های متداول

آیا استفاده زیاد از logging سرعت اجرای کدهای پایتون را کم می‌کند؟

بله، عملیات نوشتن روی دیسک (I/O) یکی از کندترین کارها در برنامه نویسی است. به همین دلیل در کدهای پروداکشن باید لاگ‌های غیرضروری دیباگ را خاموش کنید و در صورت نیاز شدید به عملکرد بالا، از کتابخانه‌های لاگ‌نویسی غیرهمزمان (Async Logging) استفاده نمایید.

تفاوت بین logging.error و logging.exception چیست؟

متد exception دقیقاً مانند error عمل می‌کند، با این تفاوت جدی که اطلاعات کامل خطا و نقطه شکست کد (StackTrace) را نیز به صورت خودکار به لاگ پیوست می‌کند. معمولاً توصیه می‌شود متد exception را فقط در بلاک‌های except قرار دهید.

چطور می‌توان برای پروژه‌های بزرگ کل تنظیمات لاگ را در یک فایل جداگانه ذخیره کرد؟

بهترین راهکار استفاده از متد dictConfig در پایتون است. با این روش می‌توانید کل تنظیمات را به صورت ساختار یافته در یک فایل YAML یا JSON بنویسید و در زمان بالا آمدن پروژه، آن فایل را در بخش پیکربندی برنامه لود کنید تا کد اصلی شما شلوغ نشود.

آیا برای کار با لاگ در برنامه‌های تحت وب مانند جنگو یا فلسک باید کار متفاوتی انجام دهم؟

فریم‌ورک‌های بزرگی مثل جنگو بر پایه سیستم استاندارد لاگ پایتون طراحی شده‌اند. شما فقط کافیست متغیر LOGGING را در فایل تنظیمات پروژه خود تغییر دهید تا تمام ویژگی‌های بررسی شده در این آموزش روی وب‌سایت شما اعمال شود.

برای دسترسی به ابزارهای برنامه‌نویسی و کدهای آماده در سایر زبان‌ها، می‌توانید از صفحات اختصاصی ما نظیر بخش مجموعه ابزارها و تکه‌کدها بازدید کنید.

Table of Contents

آخرین نوشته‌ها

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *