با عرض سلام و ادب خدمت همکاران عزیز. خوشحالم که در اینجا هستید.
احتمالا مجبور شدید که از فریمورکهای لاگ انداختن استفاده کنید. توی یک محصول واقعی، لاگ جز لاینفک محصول است، و بعنوان برنامهنویس حتما باید از آن استفاده کنید. شاید اصلا برای رسیدن به این فریضه خودتان دست بکار شده باشید و چنین امکانی را ایجاد کرده باشید (بدون استفاده از فریمورک). شاید هم تازه گرایش پیدا کردید که از فریمورک لاگ انداختن استفاده کنید، و حسابی بین کتابخانههایی که هستند سردرگم هستید! اگر به گزاره آخر بله گفتید، یعنی تازه میخواهید شروع کنید و بین انواع کتابخانهها سردرگم هستید، این مقاله برای شماست!
واقعا چه تفاوتی بین slf4j و log4j هست؟ logback چیه و کی از log4j2 استفاده کنیم؟ یا اصلا مگه خود JDK یک پکیج بنام java.util.logging ارائه نکرده؟ پس این بازیها چیه؟! در این مقاله بحث لاگ را تمام خواهیم کرد و به این سردرگمی فیصله خواهیم داد.
چرا باید از لاگ کردن استفاده کنیم؟ طبیعتا برای دیباگ کردن و پیبردن به وضعیت برنامه در هنگام اجرا و کشف مشکل و مانیتور کردن رفتار برنامه و کاربران. شاید دلایل دیگری هم داشته باشید، ولی من تقریبا برای محقق شدن چنین مسائلی به سراغ لاگ گرفتن از سیستم میروم. دلایل دیگری هم میتواند داشته باشد؟ صد البته! شما احتمالا هدفتون از این کار مشخص شده است که میخواهید این کار را انجام دهید، پس مسئلهی من در اینجا پرداختن به اهمیت لاگ نیست.
مسئله اینجا است که شما میخواهید "چیزی" را لاگ کنید (حال به هر هدفی!). عکس را نگاه کنید. پیغامی را میخواهید به یک آبجکتی که وظیفهی لاگ کردن دارد بفرستید و انتظار دارید آن آبجکت هم برای شما اون پیغام را "جایی" ذخیره کند که بعدها شما بتوانید به آن مراجعه کنید. این کلیت فرایندی است که میخواهیم انجام دهیم. حالا باید به تمام اجزای آن بپردازیم و آن را باز کنیم.
همانطور که در مقدمه اشاره شد، در JDK 1.4 یک پکیج built-in برای لاگ ارائه شد. اما واقعیت این است که این پکیج فریمورک مناسبی برای استفاده نبود، یا اجازه دهید بهتر بگویم، امکانات زیادی برای استفاده نداشت. به مرور زمان فریمورکهای دیگری وارد گود شدند که به مراتب بهتر و بهتر بودند. این پکیج مشکلات پرفورمنسی داشت، زیاد قابل انعطاف نبود و همانطور که اشاره کردم مردم به امکانات بیشتری نیاز داشتند.
این پکیج کلاسی بنام java.util.logger.Logger داشت که نقش همان آبجکت LOGGER در عکس را بازی میکند. در اصل این کلاس متدی بنام getLogger() دارد که بعنوان پارامتر اسم کلاس را میگیرد و initialize میشود. و خب حالا جزء بعدی، لاگ را چکار کند؟ نمایش بدهد یا در یک فایل بنویسد؟ پکیج logger اینجا مفهومی را مطرح میکند بنام handlers. بعبارتی در handler ما مشخص میکنیم که توی کنسول لاگ را نمایش دهد یا در فایل ذخیره کند. میتونید توی این لینک بیشتر درموردش بخونید. ما توی این مقاله کاری به آن نداریم.
خب وقتی چنین چیزی رخ میده توی جامعه نرمافزار آزاد (یعنی برای یک هدف مهم، ابزار مناسبی نباشد) چه میشود؟ مشخص است! برنامهنویسان شروع میکنند به توسعه کتابخانههای بهتر. در همین حین کتابخانهای بنام log4j توسعه داده شد که برای سالها متمادی عالی بود و مردم به کرات از آن استفاده میکردند.
در این کتابخانه هم مشابه همان پکیج JDK کلاسی بنام Logger هست که یک متد getLogger() دارد و دقیقا مشابه قبلی، به عنوان پارامتر اسم کلاس را میگیرد. در log4j بجای handlers ما appenders داریم. همان نقش را دارد کاملا. انتخابهای ما در کتابخانه log4j خیلی بیشتر است. در زیر آنها را لیست میکنیم:
Log4j Appenders:
همانطور که مشاهده میکنید امکان انتقال به دیتابیس یا حتا ایمیل کردن (SMTP) هم موجود میباشد. جزء دیگهای که از log4j میماند بحث Formatting است. اینکه لاگ به چه شکل و شمایلی باشد. که بعدا در مورد اینکه لاگ به چه فرمتهایی میتواند باشد صحبت خواهیم کرد. علیالحساب بگذریم!
خب، بنظر با log4j همه چیز عالی میاد، آیا قصهی فریمورکهای لاگ انداختن در اینجا به پایان میرسد؟ نه متاسفانه. اجازه دهید در مورد چالشی که پیش رو بود صحبت کنیم و بگوییم چطور آن را حل کردند.
فرض کنید در کدهایتان از java.util.logging استفاده کردید، حالا میخواهید آن را با log4j جابجا کنید؟ چکار باید کنید؟ باید تمام کدها را تغییر دهید، مصیبت بار است، چرا که اصلا ماهیت لاگ هم این است که تقریبا در هر متدی وجود دارد. برای حل چنین چالشی آمدند و Facade Library تعریف کردند. ۲ کتابخانه بعنوان facade library عرضه شد:
کتابخانه sla4j به مراتب مشهورتر و پراستفادهتر است. اما منظور ما از کتابخانههای facade چیست؟ کتابخانههای facade فقط اینترفیس هستند و فاقد implementation هستند. بعبارتی استانداری هستند که کتابخانههایی نظیر log4j آنها را پیادهسازی میکنند. چه مزیتی دارند؟ چالشی که مطرح شد را برطرف میکنند. بعبارتی ما در کدها طبق استاندارد sla4j کد میزنیم، و بواسطهی log4j پیادهسازی میکنیم. به این شکل هر زمان بخواهیم log4j را با java.util.logger جابجا کنیم، بدون تغییر میتوانیم این کار را انجام دهیم. چون شکل کد ما بر اساس sla4j میباشد.
پس تفاوت رو تونستید قائل بشید؟ apache commons و sla4j کتابخانههایی نیستند که در واقع عملیاتی انجام دهند. آنها صرفا اینترفیس هستند. ولی log4j و JDK logging کتابخانههایی هستند که این استانداردها رو پیادهسازی کردند (بعبارتی عملیاتی هستند). خب، تمام شد قصهی کتابخانهها؟ نه!
کتابخانهی log4j دیگه توسعه داده نمیشود. الان کتابخانهی جدیدتری هست بنام log4j2 که از هر نظر عملکرد بهتری نسبت به log4j دارد. کتابخانهی دیگری هم هست بنام logback. بطور کلی در این روزها ۲ کتابخانهی مطرح برای لاگ وجود دارد که هر دوی آنها بر پایهی sla4j api میباشند:
اما کدام؟!
اول از هر چیز، من برای کتابخانه facade از sla4j استفاده میکنم، خیلی محبوبیت و مقبولیت بیشتری دارد. و همه کتابخانههای مرسوم و محبوب از آن استفاده میکنند. ولی برای پیادهسازی چه؟
پیشنهاد میکنم که قید استفاده از log4j را بزنید. چرا که هم توسعه آن متوقف شده است و قدیمی است و هم گزینههای بهتر موجود است. بحث java.util.logging را هم که نمیکنم، با توجه به توضیحاتی که دادم این کتابخانه در انتخابهای من گزینهی آخر است. انتخابهای من میماند بین log4j2 و logback.
کتابخانهی log4j2 یک مقدار امکانات بیشتری نسبت به logback دارد، بعنوان مثال:
اما کتابخانهی logback از محبوبیت بیشتری برخوردار است و توسط همان تیمی توسعه داده میشود که sla4j را توسعه دادند. انتخاب من logback است.
خاطرتون هست دیگه؟ شما بواسطهی یک api واسط (یعنی همان sla4j) میتوانید هر زمانی که خواستید براحتی logback را با log4j2 تعویض کنید.
و اما بعد؟ خب حال چطور استفاده کنیم؟ با من همراه باشید تا در قسمت دوم میخواهم کتابخانهی logback را بشکافم و از آن در عمل استفاده کنم. در آن بین به مفاهیم زیادی از مبحث لاگ خواهم پرداخت.