آموزش کتابخانه Microsoft Enterprise Library 5.0 - قسمت پنجم
پنج شنبه 16 آذر 1391 3:13 PM
بلاک لاگ دارای مفاهیم و اصطلاحاتی می باشد که در عین سادگی بسیار مهم هستند و بدون یادگیری این مفاهیم امکان استفاده مؤثر از این بلاک وجود ندارد. در حقیقت پیچیدگی و نکته های این بلاک بیشتر در هنگام تصمیم گیری و کار با ابزار پیکربندی می باشد و نه هنگام کد نویسی. بنابراین توصیه می شود که این مقاله را با دقت و در زمان مناسب مطالعه نمایید. بر خلاف مقالات پیشین، روند یادگیری مفاهیم بلاک لاگ از آخر به اول می باشد. بنابراین توصیه می شود ابتدا مقاله را با دقت مطالعه نموده و سپس به سراغ مثال ها بروید و در نهایت برای اطمینان از درک صحیح مفاهیم مجددا مقاله را مطالعه کنید.
به طور کلی اصطلاح لاگ نمودن (Logging) برای ثبت و ذخیره نمودن رخداد های به وجود آمده در یک برنامه استفاده می شود. این رخداد ها می توانند ورود یا خروج یک کاربر به سیستم، ارسال یک پیامک، محتوای خطای به وجود آمده در نرم افزار، یک هشدار امنیتی و بسیاری موارد دیگر باشند.
یکی از مهمترین قسمت های پروژه های متوسط و بزرگ، قسمت مربوط به لاگ نمودن اطلاعات می باشد. بدون لاگ نمودن رخداد ها، شما هرگز متوجه اتفاقات درون برنامه نخواهید شد. و همچنین متوجه نخواهید شد که آیا تمامی قسمت های سیستم در حالت عملکرد صحیح قرار دارند یا خیر.
البته در محل توسعه نرم افزار یعنی جایی که نرم افزار در حال تولید می باشد، با استفاده از ابزار های برنامه نویسی و تست می توان عملکرد بسیاری از قسمت ها را کنترل کرد ولی وقتی نرم افزار به محل استفاده نهایی یعنی نزد کاربر نهایی ارسال شد، دیگر این لاگ ها هستند که اوضاع و احوال برنامه را به شما گزارش می دهند.
فرض کنید که وب سایتی نوشته اید که شبانه روز در حال ارائه خدمات به کاربران می باشد. اگر این وب سایت در ساعاتی خاص از نیمه شب عملکرد صحیحی نداشته باشد، چگونه باید از این مسئله آگاه شوید؟ و چگونه باید از دلیل به وجود آمدن این مشکل مطلع شوید؟
مثال دیگر این است که بار ها مشاهده کرده اید که بسیاری از شرکت های بزرگ ناگهان اعلام کرده اند که سرور های آن ها در تاریخی مشخص مورد حمله سایبری واقع شده اند و هکر ها تا چه میزان توانسته اند در سیستم نفوذ کنند و بسیاری جزئیات دیگر. آیا این اطلاعات بدون بررسی لاگ های سیستم بدست آمده اند؟
و آخرین مثال این است که فرض کنید برنامه ای تحت ویندوز نوشته اید که در برخی رایانه ها عملکرد صحیح دارد و در برخی دیگر خیر! چگونه باید پی به علت به وجود آمدن این مشکل و قسمت آسیب پذیر برنامه ببرید؟
صد ها مثال دیگر می توان برای اهمیت وجود قسمت لاگ در برنامه زد و به واقع باید گفت که تنها برنامه هایی نیاز به قسمت لاگ ندارند که به طور کل نیازی به پشتیبانی ندارند!
قبل از اینکه به سراغ بلاک لاگ (Logging Application block) در مجموعه Enterprise Library برویم بهتر است ابتدا نیاز های متداول در مورد لاگ نمودن اطلاعات را بررسی کنید.
بلاک لاگ در مجموعه Enterprise Library یکی از قدرتمندترین بلاک ها می باشد به طوریکه با چند خط پیکربندی و چند خط کد می توانیم اطلاعات بسیار مفیدی را در محل های مختلف لاگ نماییم.
یک لاگ در سیستم عامل ویندوز به طور استاندارد دارای عناصری است که به طور پیشفرض تعدادی از آن ها نمایش داده می شوند و ما می توانیم با توجه به نیاز خود این عناصر را از خروجی لاگ حذف نموده یا عناصر دیگر را اضافه کنیم.
تصویر زیر یک لاگ از قسمت Windows Event Log را نشان می دهد (تصویر شماره 1).
تذکر:
برای نمایش لاگ های موجود در Windows Event Log باید به مسیر زیر رفته و پنجره Event Viewer را اجرا کنید.
در قسمت زیر عناصر متداول موجود در یک لاگ را ملاحظه می کنید.
خوب اکنون زمان آن فرا رسیده است که عملکرد بلاک لاگ را در کاربرد مشاهده کنیم.
ابتدا یک پروژه از نوع ویندوزی ایجاد نموده و اسمبلی های زیر را به آن اضافه نمایید.
تذکر:
اسمبلی ها را حتما از محل نصب کتابخانه Enterprise Library به برنامه اضافه کنید. برای بنده اسمبلی ها در مسیر زیر قرار دارند.
سپس یک فایل پیکربندی (App.config) به برنامه اضافه کنید و آن را با استفاده از ویرایشگر Enterprise Library باز نمایید (روی فایل پیکربندی کلیک راست نموده و گزینه Edit enterprise Library V5 Configuration را انتخاب کنید).
از منوی Blocks گزینه Add Logging Settings را انتخاب کنید (تصویر شماره 2).
پس از انتخاب گزینه Add Logging Settings تنظیماتی مشابه شکل زیر را در ویراشگر ملاحظه می کنید. قسمت تنظیمات بلاک لاگ از 5 بخش مهم تشکلیل شده است که در شکل زیر این 5 بخش را متمایز نموده ایم(این تصویر را به خاطر داشته باشید - تصویر شماره 3).
با استفاده از این ویرایشگر می توانیم تمامی تنظیمات مورد نظر خود را انجام دهیم ولی خالی از لطف نیست که نگاهی به تغییرات انجام شده در فایل پیکربندی در خارج از ویرایشگر بیندازیم (تصویر شماره 4).
خوب، اکنون زمان بررسی این 5 قسمت معروف فرا رسیده است.
قسمت Categories (دسته بندی ها) و Special Categories (دسته بندی های ویژه) با عبارت Trace Source شناخته می شوند. برای اینکه یک عملیات لاگ را انجام دهیم باید ابتدا مشخص کنیم که این لاگ متعلق به کدام دسته بندی (ها) می باشد. دسته بندی (یا طبقه بندی) نمودن لاگ ها باعث این می شود که در آینده در صورت نیاز بتوانیم فقط لاگ های ذخیره شده متعلق به دسته بندی خاصی را بازیابی کنیم (مثلا لاگ های متعلق به دسته بندی خطاهای امنیتی).
هر لاگ می تواند متعلق به 1 دسته بندی (یا بیشتر) باشد. به طور مثال یک لاگ می تواند متعلق به دسته بندی های خطاهای امنیتی و لاگ های مربوط به مدیر سیستم باشد. نام گذاری دسته بندی ها بنا به سلیقه و نظر ما می باشد.
اگر به شکل 3 دقت کنید، ملاحظه می کنید که در قسمت Categories یک دسته بندی به طور پیشفرض به نام General به وجود آمده است. اگر هنگام کدنویسی زمانی که قصد نوشتن فرمان لاگ را داریم، مشخص نکنیم که این لاگ به چه دسته بندی (هایی) تعلق دارد، به طور پیشفرض برنامه لاگ از دسته بندی General استفاده می کند.
خوب، تا اینجای کار متوجه شدیم که قبل از این که قصد انجام عملیات لاگ را داشته باشیم باید حداقل یک دسته بندی برای آن ایجاد کرده باشیم.
اکنون دسته بندی General را در ویرایشگر بسط می دهیم تا محتویات آن را بررسی کنیم (تصویر شماره 5).
همانطور که در شکل بالا ملاحظه می کنید، یک دسته بندی از 4 قسمت تشکیل شده است:
قبل از اینکه به ادامه بحث بپردازیم بهتر است که با یک مثال ساده نحوه انجام عمل لاگ را ملاحظه کنید. ابتدا فضاهای نامی زیر را به برنامه اضافه کنید.
اکنون به قطعه کد زیر دقت کنید.
ابتدا یک شیء از کلاس LogWriterبا استفاده از مکانیزمی که در مقالات قبل شرح دادیم، ایجاد نموده ایم. سپس با استفاده از متد IsLoggingEnabled بررسی نموده ایم که قابلیت لاگ فعال می باشد یا خیر. البته به یاد داشته باشید که اگر قابلیت لاگ در فایل پیکربندی غیر فعال شده باشد (در آینده بیشتر در این مورد بحث خواهیم کرد)، در هر صورت عملیات لاگ انجام نخواهد شد ولی به هر حال از لحاظ برنامه نویسی و منطقی بهتر است که قبل از اجرای دستور لاگ، فعال بودن این قابلیت را با استفاده از متد IsLoggingEnabled چک کنیم.
سپس یک شیء از نوع کلاس LogEntry ایجاد نموده و اطلاعات لاگ را به آن اضافه کرده ایم. توجه داشته باشید که ما در مثال بالا فقط خصوصیات Priority، Severity، Title، Message و Categories را مقدار دهی نموده ایم و در نتیجه سایر خصوصیات دارای مقادیر پیشفرض خود هستند.
نکته مهم در اینجا خصوصیت Categories می باشد. همانطور که قبلا هم ذکر شد، هر Log می تواند متعلق به یک یا چند دسته بندی باشد و به همین دلیل خصوصیت Categories یک لیست یا آرایه از نام ها را قبول می کند (در حقیقت یک ICollection<T>).
در نهایت متد Write از کلاس LogWriter را فراخوانی شده و محتویات لاگ را در EventLog ویندوز دخیره می شود. اگر هم اکنون به Event Viewer ویندوز مراجعه کنید، باید محتویات این لاگ را مشابه شکلی که در ابتدای مقاله نشان دادیم، مشاهده کنید.
همانطور که ملاحظه می کنید کدنویسی برای انجام عملیات لاگ بسیار ساده می باشد و در حقیقت قسمت اعظم کار در زمان پیکربندی انجام می شود. اکنون که به طور عملی با دستورات لاگ آشنا شدید، اجاره بدهید به معرفی سایر قسمت های پیکربندی بلاک لاگ بپردازیم.
در شکل 3 این قسمت را با شماره 2 مشخص کرده ایم. این قسمت به طور پیشفرض و هنگام ایجاد، شامل 3 دسته بندی ویژه به نام های All Events، Unprocessed Category، Logging Errors & Warnings می باشد. این دسته بندی ها هم مشابه دسته بندی های معمولی هستند با این تفاوت که برای منظور های خاص طراحی شده اند و نمی توان به طور مستقیم در هنگام کد نویسی آن ها را مورد استفاده قرار داد.
قبل از اینکه به معرفی این قسمت ها بپردازیم، این سه قسمت را در ویرایشگر بسط می دهیم و در نتیجه شکل زیر پدیدار می شود(شکل شماره 6).
اکنون به معرفی این قسمت ها می پردازیم.
در شکل 3 بخش مربوط به فیلتر ها را با شماره 3 مشخصی کرده ایم. بلاک لاگ این امکان را به مدیران سیستم داده است که عملکرد بلاک لاگ را بر اساس دسته بندی ها و اولویت ها و یا اینکه به طور کل غیر فعال کنند و این عمل از طریق قسمت فیلتر ها امکان پذیر است.
در حقیقت وقتی دستور انجام لاگ صادر می شود، دسته بندی مربوطه، ابتدا محتویات لاگ را برای قسمت فیلتر ها ارسال می کند و در صورتی که در این قسمت از انجام عمل لاگ جلوگیری به عمل نیاید، محتویات لاگ برای Litener های مربوطه ارسال می شود. به همین دلیل بود که قبلا هم اشاره کردیم که اگر حتی فعال بودن قسمت لاگ از طریق متد IsLoggingEnabled چک نشود باز هم پس از صدور دستور لاگ، ممکن است این عمل انجام نگردد (البته به خاطر داشته باشید که متد IsLoggingEnabled چک می کند که آیا به طور کل لاگ در سیستم فعال است یا خیر).
همانطور که در تصویر 3 ملاحظه می کنید قسمت Log Filters به طور پیشفرض خالی می باشد و شما باید فیلتر های مورد نظر خود را اضافه کنید. اکنون به معرفی انواع فیلتر ها می پردازیم.
1. فیلتر بر اساس دسته بندی (Category Filter): برای اضافه کردن قسمت فیلتر بر اساس دسته بندی باید مطابق شکل زیر (تصویر شماره 7) بر روی علامت "+" کلیک نمایید. اکنون چهار گزینه برای انتخاب پدیدار می شوند که می توانید گزینه Add Category Filter را انتخاب کنید.
اکنون قسمت Category Filter مشابه زیر برای شما ایجاد شده است که به بررسی قسمت های مختلف آن می پردازیم (تصویر شماره 8).
2. فیلتر بر اساس اولویت (Priority Filter): برای اضافه نمودن این نوع فیلتر باید بر روی علامت "+" کنار Log Filters کلیک نموده و این بار گزینه Add Priority Filter را انتخاب کنید.
پس از اضافه نمودن فیلتر بر اساس اولویت شما با شکل زیر روبرو خواهید شد (تصویر شماره 9).
اگر به یاد داشته باشید هنگام معرفی کردن محتویات یک لاگ، خصوصیتی به نام Priority را معرفی کردیم که اولویت لاگ را با عددی مشخص می کرد. این عدد به طور پیشفرض 1- می باشد. در قسمت فیلتر بر اساس اولویت می توانیم دستورات لاگ را بر اساس مقدار این خصوصیت فیلتر نماییم. اگر مقدار خصوصیت Priority یک لاگ برابر 1- باشد، هیچگونه فیلتری به آن اعمال نمی شود. اما اگر مقدار دیگری به آن نسبت دهیم در صورتی که این مقدار در بازه ی کمترین و بیشترین فیلتر ما قرار داشته باشد، عملیات لاگ انجام شده و در غیر اینصورت از انجام آن ممانعت به عمل می آید. برای درک بهتر مسئله بخش های مختلف فیلتر اولویت را بررسی می کنیم.
به طور خلاصه لاگ هایی می توانند از این فیلتر عبور کنند که اولویت آن ها بین Minimum Priority و Maximum Priority باشد (به جز اولیت 1- که استثناء می باشد).
3. فیلتر فعال سازی لاگ (Logging Enabled Filter): دو فیلتر قبلی را که بررسی کردیم، متوجه شدیم که آن دو فیلتر بر اساس شرایطی عمل فیلتر را انجام می دهند. اما با استفاده از فیلتر فعال سازی لاگ می توانیم کل سیستم لاگ برنامه را فعال یا غیر فعال نماییم و وابسته به هیچ شرطی نیز نمی باشد.
برای اضافه نمودن این نوع فیلتر باید بر روی علامت "+" کنار Log Filters کلیک نموده و مانند شکل زیر گزینه Add Logging Enabled Filter را انتخاب کنید.
اکنون قسمت های مختلف فیلتر فعال سازی بلاگ را همانند شکل زیر ملاحظه می کنید.
بررسی قسمت های مختلف این فیلتر:
همانند سایر قسمت های کتابخانه Enterprise Library قسمت فیلتر ها نیز قابل توسعه می باشد و از طریق Add Custom Logging Filter می توان فیلتر های سفارشی نوشته شده را به برنامه اضافه کرد. این موضوع خارج از اهداف این مقاله می باشد.
در تصویر شماره 3 این قسمت را با عدد 3 مشخص نموده ایم. در مورد Listener ها قبلا بحث کرده ایم. Listener ها مسئول ذخیره سازی فیزیکی لاگ ها در یک رسانه می باشند. خوشبختانه با استفاده از بلاک لاگ امکان ذخیره شدن محتویات لاگ در رسانه های مختلف از قبیل فایل متنی، فایل XML، پایگاه داده SQL Server و MSMQ و WMI و Email و ... وجود دارد. و این قسمت هم قابل توسعه است و شما می توانید Listener های مورد نیاز خود را بنویسید.
در ادامه مقاله به معرفی چند Listener معروف می پردازیم و برای سایر Listener نیز منطق کار مشابه است و با صرف مقداری زمان می توانید پی به عملکرد آن ها ببرید.
Event Log Trace Listener: این Listener هنگام ایجاد بخش لاگ به طور پیشفرض به برنامه اضافه می شود و ما در این مقاله بار ها از آن استفاده نموده ایم. این Listener عمل لاگ نمودن در قسمت Event Log ویندوز را انجام می دهد. لازم به ذکر است برای عملکرد این Listener باید محیطی که برنامه در آن اجرا می شود مجوز های مورد نیاز جهت دسترسی به Event Log ویندوز را داشته باشد.
این قسمت را مطابق شکل زیر بسط می دهیم تا بخش های مختلف آن را بررسی کنیم (تصویر شماره 11).
معرفی قسمت های مختلف:
Flat File Trace Listener: برای اضافه کردن این قسمت کافیست که بر روی علامت "+" در سمت راست Logging Target Listeners کلیک نموده و گزینه Add Flat File Trace Listener را انتخاب کنید (تصویر شماره 12).
این Listener جهت ذخیره سازی لاگ در یک فایل متنی استفاده می گردد. اکنون آن را بسط داده و خصوصیات مختلف آن را بررسی می کنیم (تصویر شماره 13).
در قسمت زیر یک لاگ ذخیره شده در یک فایل متنی را ملاحظه می کنید (تصویر شماره 14).
XML Trace Listener: برای اضافه کردن این قسمت کافیست که بر روی علامت "+" در سمت راست Logging Target Listeners کلیک نموده و گزینه Add XML Trace Listener را انتخاب کنید.
همانطور که از نام این Listener قابل تشخیص است، وظیفه آن لاگ نمودن با فرمت XML است. اکنون این Listener را بسط می دهیم (تصویر شماره 15).
همانطور که ملاحظه می کنید این Listener خصوصیت جدیدی ندارد. شکل زیر یک قسمتی از یک نمونه لاگ را نمایش می دهد (تصویر شماره 16).
Email Trace Listener: برای اضافه کردن این قسمت کافیست که بر روی علامت "+" در سمت راست Logging Target Listeners کلیک نموده و گزینه Add Email Trace Listener را انتخاب کنید.
اگر این Listener را بسط دهیم با شکل زیر روبرو می شویم (تصویر شماره 17).
خوب، خصوصیاتی که مشاهده می کنید همان مواردی هستند که برای ارسال ایمیل مورد نیازند و توضیح خاصی در مورد آن نیاز نیست. در صورتی که نشانگر ماوس را بر روی هر عنوان قرار دهید یک Tooltip به عنوان راهنما نمایش داده می شود.
Database Trace Listener: برای اضافه کردن این قسمت کافیست که بر روی علامت "+" در سمت راست Logging Target Listeners کلیک نموده و گزینه Add Database Trace Listener را انتخاب کنید.
اگر این Listener را بسط دهیم با شکل زیر روبرو می شویم.
با استفاده از این Listener می توان لاگ ها را در پایگاه داده ذخیره کرد. ابتدا باید جداول و پرویسجر های مربوط به پایگاه داده را ایجاد کنیم. یک فایل به نام LoggingDatabase.sql در محلی که سورس فایل های Enterprise Library را ذخیره نموده اید وجود دارد که حاوی اسکریپت مورد نیاز جهت ساخت جداول و پرویسجر های مربوطه استفاده می شود. برای بنده این فایل در آدرس زیر قرار دارد (این فایل همراه سورس کامل این مقاله از لینک بالای صفحه قابل دریافت می باشد):
اسکریپت مربوطه دارای دو پروسیجر مهم به نام های Add Category و Write Log می باشد و به طور پیشفرض نیز در شکل بالا نمایش داده شده اند. در صورتی که بخواهید نام پروسیجر ها را در پایگاه داده تغییر دهید باید در این قسمت نیز این دو نام را تغییر دهید.
کاربرد سایر خصوصیات نیز کاملا مشهود می باشد. Database Instance Name، نام رشته اتصالی که باید در فایل پیکربندی ایجاد شود را نگهداری می کند.
در صورتی که علاقه مند به یادگیری عملکرد سایر Listener هستید، می توانید در اینترنت به دنبال منابع موجود بگردید.
خوب، آخرین مبحثی که قصد داریم در مورد آن صحبت کنیم، فرمت کننده ها می باشند. در تصویر شماره 3 این قسمت با عدد 5 مشخص کرده ایم.
Formatter ها همانطور که از نامشان مشخص می باشد جهت فرمت نمودن خروجی Listener ها جهت ذخیره سازی در محیط های مختلف استفاده می شوند (یعنی چینش و نحوه قرار گیری عناصر مختلف کنار هم مشخص می شود). همانطور که در شکل 3 مشخص شده است، هنگام ایجاد بلاک لاگ، یک فرمت کننده به نام Text Formatter به طور پیشفرض اضافه می شود. تاکنون تمامی Listener هایی که بررسی کردیم از این فرمت کننده جهت فرمت نمودن خروجی خود استفاده نموده اند.
یه طور کلی 3 نوع فرمت کننده در کتابخانه Enterprise Library 5 تعبیه شده است (و البته همچون قسمت های دیگر امکان نوشتن فرمت کننده های جدید نیز وجود دارد) و عبارتند از Text Formatter و XML Formatter و Binary Formatter.
Text Formatter: این فرمت کننده، پر استفاده ترین می باشد و جهت فرمت نمودن خروجی Listener هایی که استفاده می شود که خروجی آن ها از نوع متنی است. در شکل زیر فرمت کننده Text Formatter را بسط داده ایم (تصویر شماره 19).
همانطور که ملاحظه می کنید این فرمت کننده دارای خصوصیتی به نام Template می باشد. با استفاده از این خصیصه می توانید خروجی لاگ را جهت ذخیره سازی تغییر دهید. اگر روی دکمه سمت راست Template کلیک کنید پنجره Template Editor باز می شود و براحتی قادر خواهید بود که ساختار ذخیره سازی لاگ را تغییر دهید (تصویر شماره 20).
Binary Formatter: این فرمت کننده جهت فرمت نموده خروجی به شکل باینتری استفاده می شود و کار برد آن در WMI Trace Listener می باشد.
XML Formatter: این فرمت کننده در حقیقت نوع خاصی از فرمت کننده Text Formatter می باشد که به شکل درونی در XML Trace Listener استفاده می شود و به شکل آزاد در اختیار ما قرار ندارد.
برای اضافه نمودن Formatter های جدید کافیست که روی علامت "+" کنار عبارت Log Massage Formatter کلیک نمایید و گزینه ها مطابق شکل زیر مشخص می شوند (شکل شماره 21).
همانطور که قبلا بحث شد، Listener ها دارای خصوصیتی به نام Formatter Name هستند. این خصوصیت آن ها در حقیقت نام فرمت کننده مورد استفاده آن ها را مشخص می کند.
پس از اضافه نمودن فرمت کننده های مورد نظر خود، می توانید به سراغ Listener ها رفته و Listener های مورد نظر خود را ایجاد کنید و سپس فرمت کننده ها را به آن ها اضافه کنید. اکنون می توانید به سراغ دسته بندی ها بروید و Listener ها را به آن ها اضافه کنید.
اگر دقت کرده باشید در طول مقاله ما فقط خصوصیات از پیش تعریف شده ی کلاس LogEntry را مقدار دهی نموده ایم. این خصوصیات عبارت بودند از Title، Message، Priority و ... البته این خصوصیات به شکل جامعی تهیه شده اند و پاسخگوی اغلب نیاز های برنامه نویسان می باشند ولی ممکن است مواقعی پیش بیاید که نیاز داشته باشید اطلاعات دیگری را نیز همراه این خصوصیات لاگ کنید.
برای رفع این محدودیت در کلاس LogEntry خصوصیتی به نام ExtendedProperties وجود دارد.این خصوصیت یک Dictionary شامل زوج های مرتبی از نام ها و مقادیر دریافت می کند. برای استفاده از این خصوصیت باید اطلاعات مورد نظر خود را به شکل نام و مقدار بدان اضافه نماییم.
در مثال زیر ما دو خصوصیت جدید به نام extra1 و extra2 که شامل مقادیر value1 و value2 هستند را جهت لاگ کردن به این کلاس اضافه نموده ایم.
شکل زیر قسمتی از اطلاعات لاگ شده توسط قطعه کد بالا را با استفاده از XML Trace Listener را نمایش می دهد (شکل شماره 22).
و در نهایت شکل زیر به زیبایی فرآیند لاگ نمودن با استفاده از کتابخانه Microsoft Enterprise Library را نشان می دهد (شکل شماره 23).
مدیر تالار های: