تفاوت لاگ و print در قالب خروجی نیست، در این است که لاگ را میشود از بیرون خاموش و روشن کرد. کلیدش یک سطر است، در هر فایل، بدون هیچ تغییر دیگری:
log = logging.getLogger(__name__)
حالا نام لاگر همان نام ماژول است و سلسلهمراتب دارد. با logging.getLogger("payesh.sanjeh").setLevel(logging.DEBUG) فقط همان یک ماژول پرحرف میشود و بقیه برنامه در سطح قبلی میمانند. اگر همهجا print نوشته باشید این کار ممکن نیست و تنها انتخابتان همه یا هیچ است.
خروجی نمونه با سطح INFO و قالب پیشفرضی که خودتان تعیین میکنید:
INFO __main__ ejra shoro shod, 4 istgahDEBUG payesh.sanjeh meghdar kham = -999.0WARNING __main__ istgah Astara meghdar nadarad
سطر دوم فقط به این دلیل چاپ شد که همان یک لاگر بالا برده شده بود؛ سطر همسطح آن در ماژول اصلی چاپ نشد.
سطح را رویداد تعیین میکند، نه اهمیت آن برای شما
پرسشی که سطح را مشخص میکند دو تاست: آیا کار تمام شد، و آیا کسی باید کاری بکند. هشدار یعنی برنامه با یک وضعیت غیرعادی کنار آمد و ادامه داد. خطا یعنی همان عملیات تمام نشد. اگر بین این دو ماندهاید، بپرسید آیا نتیجهای که کاربر گرفت کامل بود.
در سطح خطا حتما exc_info=True بدهید، وگرنه فقط پیام شما ثبت میشود و قابها از بین میروند؛ همان قابهایی که سطری که مهم است معمولاً سطر اول نیست درباره خواندنشان است. و هیچوقت پیام را با چسباندن رشته نسازید: log.info("%s satr khande shod", n) قالببندی را تا وقتی سطح روشن نباشد اصلا انجام نمیدهد.
چه چیزی نباید در لاگ باشد
رمز، توکن، شماره کارت و کد ملی هیچوقت. لاگ معمولا جایی میرود که دسترسی به آن از دسترسی به پایگاه داده آسانتر است و مدت بیشتری هم میماند. اگر لازم است بدانید کدام کاربر بود، شناسهاش را ثبت کنید و نه مشخصاتش.
و در مقابل، دو چیز تقریبا همیشه جا میمانند و هر دو ارزاناند: شناسهای که همه سطرهای یک درخواست را به هم وصل میکند، و مقدار ورودیای که تصمیم بر اساس آن گرفته شد. بدون اولی، در سروری که ده درخواست همزمان دارد سطرها در هم میروند و هیچکدام معنی ندارند: دو کار همزمان، و باگهایی که فقط از همین میآیند.
جایی که کار گیر میکند، سروری است که کسی لاگش را نمیخواند
در بسیاری از پروژههای کوچک، لاگ روی سرور در یک فایل انباشته میشود و تا روزی که دیسک پر شود کسی بازش نمیکند. مشکل ابزار نیست، این است که نوشتن لاگ بدون تصمیم درباره چرخش و نگهداری، فقط یک بمب ساعتی روی دیسک است. حداقل کاری که ارزشش را دارد یک بار تنظیم چرخش فایل بر اساس اندازه است، که در خود کتابخانه استاندارد هست و به هیچ سرویسی نیاز ندارد. و برای اینکه لاگ واقعا خوانده شود، همان روز اول یک دستور جستوجو برای خودتان بنویسید که فقط سطرهای هشدار و خطای امروز را بیرون بکشد.
ابزار، و سالی که این حرف درست است
در سال ۲۰۲۶ ماژول logging در کتابخانه استاندارد و رایگان است و جای print را میگیرد، با این تفاوت اصلی که سطحش را میشود از بیرون عوض کرد. برای چرخش فایل، logging.handlers.RotatingFileHandler در همان ماژول است و جای اسکریپت کرون برای پاک کردن فایل لاگ را میگیرد. اگر لاگ قرار است بهشکل ماشینخوان جمع شود، قالب JSON با یک قالببند سفارشی چند سطر است و هیچ بسته بیرونی نمیخواهد، که وقتی نصب وابستگی خودش یک مرحله است ارزش دارد.
پرسش بعدی این است که وقتی لاگ میگوید کجا شکسته و هنوز نمیدانید چرا، چطور همانجا بایستید و مقدارها را ببینید، که متوقف کردن برنامه، و نگاه کردن به دور و برش است. و در استقرار واقعی، همین سطرها باید جایی جمع شوند که بشود جستوجویشان کرد: چه نگه داریم، و پیدا کردن یک سطر میان میلیونها.