محتویات سایت
        برچسب های محبوب 








 
   آموزش کتابخانه Microsoft Enterprise Library 5.0 - قسمت پنجم
  در این مقاله به معرفی بلاک لاگ (Logging Application Block) در کتابخانه Microsoft Enterprise Library 5 می پردازیم
   C#
   ۱۹۲۶۹
   دریافت فایل ضمیمه
   مرتضی صحراگرد
   ۱۳۹۰/۴/۹
نسخه قابل چاپ نسخه قابل چاپ

این مقاله پنجمنین مقاله از سری آموزش های Microsoft Enterprise Library 5.0 می باشد. قبل از مطالعه این بخش، مطالعه مقالات قبلی توصیه می شود.

  1. آموزش کتابخانه Microsoft Enterprise Library 5.0 - قسمت اول
  2. آموزش کتابخانه Microsoft Enterprise Library 5.0 - قسمت دوم
  3. آموزش کتابخانه Microsoft Enterprise Library 5.0 - قسمت سوم
  4. آموزش کتابخانه Microsoft Enterprise Library 5.0 - قسمت چهارم

تذکر مهم:

بلاک لاگ دارای مفاهیم و اصطلاحاتی می باشد که در عین سادگی بسیار مهم هستند و بدون یادگیری این مفاهیم امکان استفاده مؤثر از این بلاک وجود ندارد. در حقیقت پیچیدگی و نکته های این بلاک بیشتر در هنگام تصمیم گیری و کار با ابزار پیکربندی می باشد و نه هنگام کد نویسی. بنابراین توصیه می شود که این مقاله را با دقت و در زمان مناسب مطالعه نمایید. بر خلاف مقالات پیشین، روند یادگیری مفاهیم بلاک لاگ از آخر به اول می باشد. بنابراین توصیه می شود ابتدا مقاله را با دقت مطالعه نموده و سپس به سراغ مثال ها بروید و در نهایت برای اطمینان از درک صحیح مفاهیم مجددا مقاله را مطالعه کنید.

مقدمه:

به طور کلی اصطلاح لاگ نمودن (Logging) برای ثبت و ذخیره نمودن رخداد های به وجود آمده در یک برنامه استفاده می شود. این رخداد ها می توانند ورود یا خروج یک کاربر به سیستم، ارسال یک پیامک، محتوای خطای به وجود آمده در نرم افزار، یک هشدار امنیتی و بسیاری موارد دیگر باشند.

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

البته در محل توسعه نرم افزار یعنی جایی که نرم افزار در حال تولید می باشد، با استفاده از ابزار های برنامه نویسی و تست می توان عملکرد بسیاری از قسمت ها را کنترل کرد ولی وقتی نرم افزار به محل استفاده نهایی یعنی نزد کاربر نهایی ارسال شد، دیگر این لاگ ها هستند که اوضاع و احوال برنامه را به شما گزارش می دهند.

فرض کنید که وب سایتی نوشته اید که شبانه روز در حال ارائه خدمات به کاربران می باشد. اگر این وب سایت در ساعاتی خاص از نیمه شب عملکرد صحیحی نداشته باشد، چگونه باید از این مسئله آگاه شوید؟ و چگونه باید از دلیل به وجود آمدن این مشکل مطلع شوید؟

مثال دیگر این است که بار ها مشاهده کرده اید که بسیاری از شرکت های بزرگ ناگهان اعلام کرده اند که سرور های آن ها در تاریخی مشخص مورد حمله سایبری واقع شده اند و هکر ها تا چه میزان توانسته اند در سیستم نفوذ کنند و بسیاری جزئیات دیگر. آیا این اطلاعات بدون بررسی لاگ های سیستم بدست آمده اند؟

و آخرین مثال این است که فرض کنید برنامه ای تحت ویندوز نوشته اید که در برخی رایانه ها عملکرد صحیح دارد و در برخی دیگر خیر! چگونه باید پی به علت به وجود آمدن این مشکل و قسمت آسیب پذیر برنامه ببرید؟

صد ها مثال دیگر می توان برای اهمیت وجود قسمت لاگ در برنامه زد و به واقع باید گفت که تنها برنامه هایی نیاز به قسمت لاگ ندارند که به طور کل نیازی به پشتیبانی ندارند!

قبل از اینکه به سراغ بلاک لاگ (Logging Application block) در مجموعه Enterprise Library برویم بهتر است ابتدا نیاز های متداول در مورد لاگ نمودن اطلاعات را بررسی کنید.

آغاز:

بلاک لاگ در مجموعه Enterprise Library یکی از قدرتمندترین بلاک ها می باشد به طوریکه با چند خط پیکربندی و چند خط کد می توانیم اطلاعات بسیار مفیدی را در محل های مختلف لاگ نماییم.

ویژگی ها و مزایای استفاده از بلاک لاگ:

  • امکان ذخیره نمودن لاگ ها در رسانه های مختلف از قبیل پایگاده داده، فایل XML، فایل متنی، MSMQ، WMI، Windows Event Log، ارسال محتوای لاگ از طریق ایمیل و غیره.
    خوشبختانه امکان توسعه این قابلیت ها و ذخیره سازی در سایر رسانه ها نیز امکان پذیر می باشد.
  • براحتی می توان از طریق فایل پیکربندی قسمت های مختلف مربوط به لاگ را فعال یا غیر فعال نمود.
  • بسیاری از اطلاعات بدون اینکه نیاز باشد برای آن ها کد بنویسیم به شکل خود کار می توانند به اطلاعات لاگ اضافه شوند.
  • براحتی و با حتی دو خط کد نویسی می توان اطلاعات را در محل های مختلف لاگ نمود.
  • و بسیاری موارد دیگر که در ادامه با آن ها آشنا خواهید شد.

عناصر سازنده یک لاگ:

یک لاگ در سیستم عامل ویندوز به طور استاندارد دارای عناصری است که به طور پیشفرض تعدادی از آن ها نمایش داده می شوند و ما می توانیم با توجه به نیاز خود این عناصر را از خروجی لاگ حذف نموده یا عناصر دیگر را اضافه کنیم.

تصویر زیر یک لاگ از قسمت Windows Event Log را نشان می دهد (تصویر شماره 1).



تذکر:

برای نمایش لاگ های موجود در Windows Event Log باید به مسیر زیر رفته و پنجره Event Viewer را اجرا کنید.

Control Panel --> All Control Panel Items --> Administrative Tools

در قسمت زیر عناصر متداول موجود در یک لاگ را ملاحظه می کنید.

  • Title: عنوانی است که برای لاگ در نظر گرفته ایم. به طور مثال می توانیم لاگ های مربوط به هشدار های امنیتی را با عنوان Security Warnings ذخیره کنیم.
  • Message: متن کامل پیامی است که قرار است در لاگ ذخیره شود. به طور مثال این پیام می تواند متن کامل شرح یک خطای به وجود آمده در برنامه باشد.
  • Categories: دسته بندی هایی می باشد که لاگ به آن ها تعلق دارد. در این باره بعدا بحث خواهیم نمود.
  • Priority: اولویت لاگ را مشخص می کند و مقدار پیشفرض آن 1- می باشد. در این باره بعدا بحث خواهیم نمود.
  • Severity: مقداری است از یک نوع داده Enumration به نام TraceEventType که حاوی مقادیری از قبیل Information، Warning، Error، Critical و ... می باشد. اینگونه خصوصیت ها بدین جهت استفاده می شوند که در آینده هنگام بازیابی اطلاعات بتوانید لاگ ها را با استفاده از آن ها فیلتر کنید. به طور مثال ممکن است در نظر داشته باشید که ابتدا لاگ هایی را بررسی کنید که خصوصیت Severity آن ها برابر Critical باشد. مقدار پیشفرض این خصوصیت برابر Information می باشد.
  • EventId: یک شناسه عددی است که می توانیم به لاگ ها نسبت دهیم.
  • ActivityId: یک شناسه از نوع GUID است که اگر قابلیت tracing در لاگ فعال باشد به طور اتوماتیک (یا توسط ما) تولید شده و به این خصوصیت نسبت داده می شود. اگر قابلیت tracing غیر فعال باشد، مثدار Guid.Empty برگردانده می شود. در این مقاله این خصوصیت را مورد بررسی قرار نمی دهیم.
  • AppDomainName: اگر توسط برنامه نویس مقداری به این خصوصیت نسبت داده نشده باشد به طور پیشفرض نام AppDomain ای که برنامه در آن اجرا شده است را نگهداری می کند.
  • MachineName: اگر توسط برنامه نویس مقداری به این خصوصیت نسبت داده نشده باشد به طور پیشفرض مقدار Environment.MachineName را نگهداری می کند.
  • ManagedThreadName: اگر توسط برنامه نویس مقداری به این خصوصیت نسبت داده نشده باشد به طور پیشفرض مقدار Thread.CurrentThread.Name را نگهداری می کند.
  • ProcessId: اگر توسط برنامه نویس مقداری به این خصوصیت نسبت داده نشده باشد به طور پیشفرض مقدار شناسه Win32 ProcessId که برنامه در آن اجر شده است را نگهداری می کند.
  • ProcessName: اگر توسط برنامه نویس مقداری به این خصوصیت نسبت داده نشده باشد به طور پیشفرض نام پروسسی که برنامه در آن اجر شده است را نگهداری می کند.
  • Win32ThreadId: اگر توسط برنامه نویس مقداری به این خصوصیت نسبت داده نشده باشد به طور پیشفرض مقدار شناسه Win32 thread id را نگهداری می کند.
  • TimeStamp: اگر توسط برنامه نویس مقداری به این خصوصیت نسبت داده نشده باشد به طور پیشفرض مقدار DateTime.UtcNow را نگهداری می کند.
  • ExtendedProperties: کاربرد این خصوصیت بسیار جالب می باشد. در صورتی که بخواهیم اطلاعاتی را ذخیره کنیم که جزو هیچ کدام از دسته بندی های بالا نباشد می توانیم این اطلاعات را به شکل مجموعه ای از نام ها و مقادیر ذخیره نماییم. در آینده استفاده از این خصوصیت را نیز ملاحظه خواهید نمود.

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

ابتدا یک پروژه از نوع ویندوزی ایجاد نموده و اسمبلی های زیر را به آن اضافه نمایید.

  • Microsoft.Practices.EnterpriseLibrary.Common.dll
  • Microsoft.Practices.ServiceLocation.dll
  • Microsoft.Practices.Unity.dll
  • Microsoft.Practices.Unity.Interception.dll
  • Microsoft.Practices.EnterpriseLibrary.Logging.dll
  • Microsoft.Practices.EnterpriseLibrary.Data.dll
  • Microsoft.Practices.EnterpriseLibrary.Logging.Database.dll

تذکر:

اسمبلی ها را حتما از محل نصب کتابخانه Enterprise Library به برنامه اضافه کنید. برای بنده اسمبلی ها در مسیر زیر قرار دارند.

C:\Program Files\Microsoft Enterprise Library 5.0\Bin

سپس یک فایل پیکربندی (App.config) به برنامه اضافه کنید و آن را با استفاده از ویرایشگر Enterprise Library باز نمایید (روی فایل پیکربندی کلیک راست نموده و گزینه Edit enterprise Library V5 Configuration را انتخاب کنید).

از منوی Blocks گزینه Add Logging Settings را انتخاب کنید (تصویر شماره 2).



پس از انتخاب گزینه Add Logging Settings تنظیماتی مشابه شکل زیر را در ویراشگر ملاحظه می کنید. قسمت تنظیمات بلاک لاگ از 5 بخش مهم تشکلیل شده است که در شکل زیر این 5 بخش را متمایز نموده ایم(این تصویر را به خاطر داشته باشید - تصویر شماره 3).



با استفاده از این ویرایشگر می توانیم تمامی تنظیمات مورد نظر خود را انجام دهیم ولی خالی از لطف نیست که نگاهی به تغییرات انجام شده در فایل پیکربندی در خارج از ویرایشگر بیندازیم (تصویر شماره 4).


خوب، اکنون زمان بررسی این 5 قسمت معروف فرا رسیده است.

دسته بندی ها (Categories):

قسمت Categories (دسته بندی ها) و Special Categories (دسته بندی های ویژه) با عبارت Trace Source شناخته می شوند. برای اینکه یک عملیات لاگ را انجام دهیم باید ابتدا مشخص کنیم که این لاگ متعلق به کدام دسته بندی (ها) می باشد. دسته بندی (یا طبقه بندی) نمودن لاگ ها باعث این می شود که در آینده در صورت نیاز بتوانیم فقط لاگ های ذخیره شده متعلق به دسته بندی خاصی را بازیابی کنیم (مثلا لاگ های متعلق به دسته بندی خطاهای امنیتی).

هر لاگ می تواند متعلق به 1 دسته بندی (یا بیشتر) باشد. به طور مثال یک لاگ می تواند متعلق به دسته بندی های خطاهای امنیتی و لاگ های مربوط به مدیر سیستم باشد. نام گذاری دسته بندی ها بنا به سلیقه و نظر ما می باشد.

اگر به شکل 3 دقت کنید، ملاحظه می کنید که در قسمت Categories یک دسته بندی به طور پیشفرض به نام General به وجود آمده است. اگر هنگام کدنویسی زمانی که قصد نوشتن فرمان لاگ را داریم، مشخص نکنیم که این لاگ به چه دسته بندی (هایی) تعلق دارد، به طور پیشفرض برنامه لاگ از دسته بندی General استفاده می کند.

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

اکنون دسته بندی General را در ویرایشگر بسط می دهیم تا محتویات آن را بررسی کنیم (تصویر شماره 5).




همانطور که در شکل بالا ملاحظه می کنید، یک دسته بندی از 4 قسمت تشکیل شده است:

  1. Name: در این قسمت نام دسته بندی وجود دارد که به دلخواه ما می باشد.
  2. Auto Flush: مقدار این خصوصیت به طور پیشفرض true می باشد. مفهوم آن این است که هر زمانی که دستور لاگی که مربوط به این دسته بندی باشد صادر شود، انجام عملیات لاگ در همان لحظه به شکل فیزیکی انجام می شود (مثلا در یک فایل XML ذخیره می شود). ولی اگر مقدار این عبارت را برابر false کنیم، هنگام صدور دستور لاگ، این عملیات در حافظه ذخیره شده ولی به شکل فیزیکی انجام نمی شود تا زمانی که متد FlushContextItems از کلاس LogWriter فراخوانی شود (در آینده با این کلاس و امکاناتش آشنا خواهید شد). هنگام فراخوانی متد FlushContextItems تمامی لاگ هایی که در حافظه ثبت شده اند ولی به شکل فیزیکی انجام نشده اند، به شکل فیزیکی انجام شده و از حافظه پاک می شوند.
  3. Listeners: در ابتدای مقاله ذکر کردیم که یکی از ویژگی های برتر بلاک لاگ امکان ذخیره نموده لاگ ها در محل های مختلف می باشد. Listener ها یا به عبارت کاملتر Logging Target Listeners مشخص کننده این مطلب هستند که لاگ باید در کجا ذخیره شود. در شکل 3 ما قسمت Logging Target Listeners را با شماره 4 مشخص نموده ایم. در مورد جزئیات Logging Target Listeners بعدا بحث خواهیم کرد.

    هر دسته بندی می تواند یک یا بیشتر Listener داشته باشد. هنگامی که بلاک لاگ را برای اولین بار به برنامه اضافه می کنیم یک Listener به شکل پیشفرض با نام Event Log Listener ایجاد شده و به دسته بندی General اضافه می شود. بنابراین اگر ما یک لاگ را با استفاده از دسته بندی General انجام دهیم این لاگ توسط Event Log Listener شنود شده و در Event Log سیستم عامل ویندوز ذخیره می گردد.

    یک دسته بندی می تواند به تعداد دلخواه Listener داشته باشد و در نتیجه هنگام صدور دستور لاگ متعلق به این دسته بندی، محتویات لاگ به این Listener ها جهت ذخیره شدن در محل های مختلف ارسال می شود.
  4. Minimum Severity: این خصوصیت میزان شدت و سختی دسته بندی را مشخص می کند. مقادیر مجاز برای این خصوصیت می تواند یکی از مقادیر All ، Off ، Critical ، Error ، Warning ، Information ، Verbose ، ActivityTracing باشد که البته به طور پیشفرض مقدار آن All است.

    در بند قبلی (بند 3)  Listener ها را به شکل مختصر معرفی کردیم. Listener ها دارای خصوصیتی به نام Severity Filter هستند که دقیقا در تعامل با خصوصیت Minimum Severity دسته بندی ها عمل می کند. اگر مقدار خصوصیت Minimum Severity مربوط به یک دسته بندی برابر All باشد، هنگامی که یک دستور لاگ صادر می شود، این دسته بندی دستور لاگ را به تمامی Listener هایی که هنگام پیکربندی مشخص نموده ایم ارسال می کند.

    اما اگر مقدار خصوصیت Minimum Severity مربوط به یک دسته بندی مخالف All باشد، دستور لاگ فقط برای Listener هایی ارسال می شود که حداقل سختی آنها (Severity Filter آن ها) برابر یا بالاتر از سختی این دسته بندی باشد.

    شاید اکنون از خود بپرسیدکه اگر قرار باشد ویژگی Severity Filter یک Listener کمتر از Minimum Severity یک دسته بندی باشد، اصلا چرا این Listener را به آن دسته بندی اضافه کرده ایم؟! چون در هر صورت می دانیم که درخواست عمل لاگ به این Listener ارسال نمی شود! دلیل این موضوع این است که ویژگی های بلاک لاگ (و سایر بلاک ها) از طریق فایل پیکربندی به راحتی قابل تغییر است و پس از تولید نرم افزار و ارائه شدن به محل استفاده، خود مدیر سیستم می تواند با توجه به نیاز و شرایط خود این تنظیمات را برای مدتی تغییر دهد. یعنی تعدادی از Listener را از کار بیندازد یا برعکس.

    فراموش نکنید که کتابخانه Enterprise Library به واقع با رویکرد استفاده در نرم افزار های Enterprise طراحی شده است.

قبل از اینکه به ادامه بحث بپردازیم بهتر است که با یک مثال ساده نحوه انجام عمل لاگ را ملاحظه کنید. ابتدا فضاهای نامی زیر را به برنامه اضافه کنید.

using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

اکنون به قطعه کد زیر دقت کنید.

LogWriter logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();

if (logWriter.IsLoggingEnabled())
{
    LogEntry logEntry = new LogEntry();
    logEntry.Title = "در این قسمت عنوان مربوط به لاگ قرار می گیرد";
    logEntry.Message = "در این قسمت متن کامل لاگ قرار می گیرد";
    logEntry.Categories = new List<string>() { "General" };
    logEntry.Priority = -1;
    logEntry.Severity = TraceEventType.Information;

    logWriter.Write(logEntry);
}

ابتدا یک شیء از کلاس LogWriterبا استفاده از مکانیزمی که در مقالات قبل شرح دادیم، ایجاد نموده ایم. سپس با استفاده از متد IsLoggingEnabled بررسی نموده ایم که قابلیت لاگ فعال می باشد یا خیر. البته به یاد داشته باشید که اگر قابلیت لاگ در فایل پیکربندی غیر فعال شده باشد (در آینده بیشتر در این مورد بحث خواهیم کرد)، در هر صورت عملیات لاگ انجام نخواهد شد ولی به هر حال از لحاظ برنامه نویسی و منطقی بهتر است که قبل از اجرای دستور لاگ، فعال بودن این قابلیت را با استفاده از متد IsLoggingEnabled چک کنیم.

سپس یک شیء از نوع کلاس LogEntry ایجاد نموده و اطلاعات لاگ را به آن اضافه کرده ایم. توجه داشته باشید که ما در مثال بالا فقط خصوصیات Priority، Severity، Title، Message و Categories را مقدار دهی نموده ایم و در نتیجه سایر خصوصیات دارای مقادیر پیشفرض خود هستند.

 نکته مهم در اینجا خصوصیت Categories می باشد. همانطور که قبلا هم ذکر شد، هر Log می تواند متعلق به یک یا چند دسته بندی باشد و به همین دلیل خصوصیت Categories یک لیست یا آرایه از نام ها را قبول می کند (در حقیقت یک ICollection<T>).

در نهایت متد Write از کلاس LogWriter را فراخوانی شده و محتویات لاگ را در EventLog ویندوز دخیره می شود. اگر هم اکنون به Event Viewer ویندوز مراجعه کنید، باید محتویات این لاگ را مشابه شکلی که در ابتدای مقاله نشان دادیم، مشاهده کنید.

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

دسته بندی های ویژه (Special Categories):

در شکل 3 این قسمت را با شماره 2 مشخص کرده ایم. این قسمت به طور پیشفرض و هنگام ایجاد، شامل 3 دسته بندی ویژه به نام های All Events، Unprocessed Category، Logging Errors & Warnings می باشد. این دسته بندی ها هم مشابه دسته بندی های معمولی هستند با این تفاوت که برای منظور های خاص طراحی شده اند و نمی توان به طور مستقیم در هنگام کد نویسی آن ها را مورد استفاده قرار داد.

قبل از اینکه به معرفی این قسمت ها بپردازیم، این سه قسمت را در ویرایشگر بسط می دهیم و در نتیجه شکل زیر پدیدار می شود(شکل شماره 6).



اکنون به معرفی این قسمت ها می پردازیم.

  1. All Events: اگر به شکل بالا دقت کنید، متوجه می شوید که در قسمت Listeners مربوط به این دسته بندی هیچ Listener ی وجود ندارد. یعنی این دسته بندی به طور پیشفرض هیچ کاری انجام نمی دهد تا اینکه شما در صورت نیاز، یک Listener به آن اضافه کنید. اما وظیفه این دسته بندی چیست؟ همانطور که مستحضر می باشید برای انجام عملیات لاگ به طور معمول باید هنگام کدنویسی، دسته بندی لاگ را مشخص کنیم تا آن دسته بندی با توجه به Listener هایی که دارد عملیات لاگ را انجام دهد. اما اگر به دسته بندی ویژه All Events یک Listener اضافه کنیم، به ازای تمامی دستورات لاگ های ما، متلعق به هر دسته بندی معمولی که باشند، این دسته بندی ویژه نیز عملیات لاگ را انجام می دهد و به همین دلیل است که نام آن را All Events نهاده اند.
  2. Unprocessed Category: خوب، با نگاهی به تصویر 3-1 براحتی متوجه می شوید که لیست Listener های این دسته بندی ویژه هم به طور پیشفرض خالی می باشد. اگر هنگام صدور فرمان لاگ در کدنویسی، این عملیات انجام نشود، محتویات لاگ برای این دسته بندی ارسال می شود و در صورتی که یک Listener به این دسته بندی اضافه کرده باشیم، عملیات لاگ توسط این دسته بندی ویژه، انجام می شود. ساده ترین دلیل آن می تواند این باشد که شما از نام یک دسته بندی در هنگام صدور فرمان لاگ استفاده کرده باشید که اصلا در تنظیمات فایل پیکربندی وجود نداشته باشد! حتما هم اکنون از خود می پرسید که چطور ممکن است که ما در کد از دسته بندی ای استفاده کرده باشیم که در فایل پیکربندی وجود ندارد؟! یک دلیل این می تواند باشد که مدیر سیستم در محل استفاده از نرم افزار، این دسته بندی را به هر دلیلی از فایل پیکربندی حذف نموده باشد.
  3. Logging Errors & Warnings: چه اتفاقی باید بیفتد اگر هنگام انجام عملیات لاگ یک خطا ایجاد شود. به طور مثال فرض کنید که عملیات ذخیره سازی لاگ بر روی پایگاه داده صادر شده است و به هر دلیلی پایگاه داده ما در دسترس نباشد! به یاد داشته باشید که بلاک لاگ به شکل یک ارزش افزوده به برنامه اضافه می شود و قرار است که بسیاری از مشکلات را حل کند و نه اینکه خود باری شود بر دوش برنامه!

    در صورتی که هنگام انجام عملیات لاگ، خطایی به وجود آید. محتوای لاگ به این دسته بندی ارسال می شود. این دسته بندی علاوه بر محتوای لاگ، محتوای خطای به وجود آمده را نیز لاگ می کند! تا بعدا مورد بررسی قرار گیرد. همانطور که در شکل 3-1 ملاحظه می کنید به طور پیشفرض یک Listener به آن اضافه شده است که همان Event Log Listener است و بنابراین محتویات این لاگ در Event Log ویندوز ذخیره می شود.

فیلتر ها (Log Filters):

در شکل 3 بخش مربوط به فیلتر ها را با شماره 3 مشخصی کرده ایم. بلاک لاگ این امکان را به مدیران سیستم داده است که عملکرد بلاک لاگ را بر اساس دسته بندی ها و اولویت ها و یا اینکه به طور کل غیر فعال کنند و این عمل از طریق قسمت فیلتر ها امکان پذیر است.

در حقیقت وقتی دستور انجام لاگ صادر می شود، دسته بندی مربوطه، ابتدا محتویات لاگ را برای قسمت فیلتر ها ارسال می کند و در صورتی که در این قسمت از انجام عمل لاگ جلوگیری به عمل نیاید، محتویات لاگ برای Litener های مربوطه ارسال می شود. به همین دلیل بود که قبلا هم اشاره کردیم که اگر حتی فعال بودن قسمت لاگ از طریق متد IsLoggingEnabled چک نشود باز هم پس از صدور دستور لاگ، ممکن است این عمل انجام نگردد (البته به خاطر داشته باشید که متد IsLoggingEnabled چک می کند که آیا به طور کل لاگ در سیستم فعال است یا خیر).

همانطور که در تصویر 3 ملاحظه می کنید قسمت Log Filters به طور پیشفرض خالی می باشد و شما باید فیلتر های مورد نظر خود را اضافه کنید. اکنون به معرفی انواع فیلتر ها می پردازیم.

 1. فیلتر بر اساس دسته بندی (Category Filter): برای اضافه کردن قسمت فیلتر بر اساس دسته بندی باید مطابق شکل زیر (تصویر شماره 7) بر روی علامت "+" کلیک نمایید. اکنون چهار گزینه برای انتخاب پدیدار می شوند که می توانید گزینه Add Category Filter را انتخاب کنید.



اکنون قسمت Category Filter مشابه زیر برای شما ایجاد شده است که به بررسی قسمت های مختلف آن می پردازیم (تصویر شماره 8).


  • Name: نام این فیلتر است که به دلخواه می باشد و شما می توانید نام مورد علاقه خود را انتخاب کنید.
  • Category: این قسمت به طور پیشفرض خالی می باشد. اگر بر روی علامت "+" در کنار این قسمت کلیک کنید، بخشی اضافه می شود که نام دسته بندی هایی که شما ایجاد نموده اید را نشان می دهد. با توجه به اینکه تاکنون ما فقط دسته بندی General را ایجاد نموده ایم، شما فقط این گزینه را می توانید انتخاب کنید. در حقیقت این قسمت مشخص می کند که فیلتر باید بر روی چه دسته بندی (هایی) اعمال شود.
  • Filter Mode: مقدار پیشفرض برای این خصوصیت AllowAllExceptDenied می باشد و مفهوم آن این است که به دسته بندی هایی که به این فیلتر اضافه نموده ایم، فیلتر اعمال می شود و پس از این اگر هر دستور لاگی مربوط به این دسته بندی (ها) صادر شود، عملیات متوقف شده و از انجام آن ممانعت به عمل می آید. ولی در مورد سایر دسته بندی ها هیچ مشکلی وجود ندارد.

    اگر مقدار این خصوصیت را به DenyAllExceptAllowed تغییر دهیم، دقیقا قضیه برعکس می شود. یعنی به تمام دسته بندی هایی که به این فیلتر اضافه ننموده ایم فیلتر اعمال می شود در حالیکه به دسته بندی هایی که به این فیلتر اضافه شده اند فیلتر اعمال نمی شود.
  • Type Name: این خصوصیت به شکل فقط خواندنی بوده و نام نوع فیلتر (در اینجا Category Filter) را نمایش می دهد.

 

2. فیلتر بر اساس اولویت (Priority Filter): برای اضافه نمودن این نوع فیلتر باید بر روی علامت "+" کنار Log Filters کلیک نموده و این بار گزینه Add Priority Filter را انتخاب کنید.

پس از اضافه نمودن فیلتر بر اساس اولویت شما با شکل زیر روبرو خواهید شد (تصویر شماره 9).


اگر به یاد داشته باشید هنگام  معرفی کردن محتویات یک لاگ، خصوصیتی به نام Priority را معرفی کردیم که اولویت لاگ را با عددی مشخص می کرد. این عدد به طور پیشفرض 1- می باشد. در قسمت فیلتر بر اساس اولویت می توانیم دستورات لاگ را بر اساس مقدار این خصوصیت فیلتر نماییم. اگر مقدار خصوصیت Priority یک لاگ برابر 1- باشد، هیچگونه فیلتری به آن اعمال نمی شود. اما اگر مقدار دیگری به آن نسبت دهیم در صورتی که این مقدار در بازه ی کمترین و بیشترین فیلتر ما قرار داشته باشد، عملیات لاگ انجام شده و در غیر اینصورت از انجام آن ممانعت به عمل می آید. برای درک بهتر مسئله بخش های مختلف فیلتر اولویت را بررسی می کنیم.

  • Name: نام این فیلتر است که به دلخواه می باشد و شما می توانید نام مورد علاقه خود را انتخاب کنید.
  • Maximum Priority: مقدار این خصوصیت به طور پیشفرض می باشد 2147483647 می باشد. در صورتی که مقدار اولویت لاگ کمتر یا مساوی این عدد باشد، عمل لاگ انجام می شود. این عدد بنا بر نیاز شما قابل تغییر می باشد.
  • Minimum Priority: مقدار این خصوصیت به طور پیشفرض مقدار آن 0 است. یعنی اگر دستور لاگی صادر شد که مقدار خصوصیت اولویت آن کمتر از 0 باشد، آن دستور فیلتر می شود و عمل لاگ انجام نمی شود (به یاد داشته باشید که عدد 1- استثناء است و لاگ هایی که اولویت آن ها 1- باشند هرگز توسط این فیلتر بلاک نمی شوند). این مقدار نیز بنا بر نیاز شما یا مدیر سیستم قابل تغییر می باشد.
  • Type Name: این خصوصیت به شکل فقط خواندنی بوده و نام نوع فیلتر (در اینجا Priority Filter) را نمایش می دهد.

به طور خلاصه لاگ هایی می توانند از این فیلتر عبور کنند که اولویت آن ها بین Minimum Priority و Maximum Priority باشد (به جز اولیت 1- که استثناء می باشد).

 

3. فیلتر فعال سازی لاگ (Logging Enabled Filter): دو فیلتر قبلی را که بررسی کردیم، متوجه شدیم که آن دو فیلتر بر اساس شرایطی عمل فیلتر را انجام می دهند. اما با استفاده از فیلتر فعال سازی لاگ می توانیم کل سیستم لاگ برنامه را فعال یا غیر فعال نماییم و وابسته به هیچ شرطی نیز نمی باشد.

برای اضافه نمودن این نوع فیلتر باید بر روی علامت "+" کنار Log Filters کلیک نموده و مانند شکل زیر گزینه Add Logging Enabled Filter را انتخاب کنید.

اکنون قسمت های مختلف فیلتر فعال سازی بلاگ را همانند شکل زیر ملاحظه می کنید.


بررسی قسمت های مختلف این فیلتر:

  • Name: نام این فیلتر است که اختیاری می باشد و شما می توانید نام مورد علاقه خود را انتخاب کنید.
  • All Logging Enabled: اگر مقدار این خصوصیت true باشد، بلاک لاگ در سیستم فعال است و در صورتی که مقدار آن را به false تغییر دهیم، کل بلاک لاگ در سیستم غیر فعال شده و هیچگونه لاگی انجام نمی شود.
  • Type Name: این خصوصیت به شکل فقط خواندنی بوده و نام نوع فیلتر (در اینجا LogEnabledFilter) را نمایش می دهد.

همانند سایر قسمت های کتابخانه Enterprise Library قسمت فیلتر ها نیز قابل توسعه می باشد و از طریق Add Custom Logging Filter می توان فیلتر های سفارشی نوشته شده را به برنامه اضافه کرد. این موضوع خارج از اهداف این مقاله می باشد.

قسمت Logging Target Listeners:

در تصویر شماره 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).


معرفی قسمت های مختلف:

  • Name: یک نام دلخواه برای این Listener می باشد که می توان آن را به دلخواه تغییر داد.
  • Formatter Name: نام فرمت کننده خروجی این Listener می باشد که در آینده در این مورد صحبت خواهیم نمود.
  • Log Name: اگر در مثال هایی که تاکنون زده ایم دقت کرده باشید همه لاگ های ما در قسمت Application در Event Log ویندوز ذخیره شده است. با استفاده از این خصوصیت می توانیم تعیین کنیم که به کدام قسمت Event Log ویندوز اضافه شود از جمله Application و System
  • Machine Name: نام دستگاهی می باشد که باید لاگ در آن نوشته شود. مقدار پیشفرض آن "." است که نشانگر دستگاهی است که در حال حاضر برنامه بر روی آن اجرا شده است.
  • Severity Filter: حداقل میزان شدت و سختی این Listener است. قبلا در مورد این قسمت بحث نموده ایم. اگر به یاد داشته باشید دسته بندی ها نیز دارای خصوصیتی به نام Minimum Severity هستند. در صورتی که حداقل سختی مقدار این Listener بزرگتر یا مساوی Minimum Severity دسته بندی مربوطه باشد، عمل لاگ انجام توسط این Listener انجام می شود. به طور پیشفرض مقدار این خصوصیت All می باشد و بنابراین همه ی لاگ ها بدون مقایسه شدت و سختی لاگ می شوند.
  • Source Name: خصوصیتی به نام Source در یک لاگ وجود دارد که می توانیم اینجا آن را تعیین کنیم. به طور پیشفرض مقدار این خصوصیت برابر Enterprise Library Logging می باشد.
  • Trace Output Options: این خصوصیت اختیاری می باشد و مربوط به Listener هایی است که خروجی آن ها متنی نیست و از نوع باینری است (مانند WMI).

 

Flat File Trace Listener: برای اضافه کردن این قسمت کافیست که بر روی علامت "+" در سمت راست Logging Target Listeners کلیک نموده و گزینه Add Flat File Trace Listener را انتخاب کنید (تصویر شماره 12).



این Listener جهت ذخیره سازی لاگ در یک فایل متنی استفاده می گردد. اکنون آن را بسط داده و خصوصیات مختلف آن را بررسی می کنیم (تصویر شماره 13).



  • Name: یک نام  دلخواه برای این Listener می باشد که می توان آن را به دلخواه تغییر داد.
  • File Name: آدرس فایل متنی است که قرار است لاگ در آن ذخیره شود. دقت داشته باشید که حتما یک آدرس ثابت به این قسمت بدهید.البته استفاده از متغیر های استاندارد ویندوز مانند "%TEMP%" و "%WINDIR%"  نیز مجاز می باشد. در صورتی که از از علامت ".\" برای آدرس دهی استفاده کنید، فایل مربوطه در کنار فایل اجرایی برنامه شما ذخیره می شود (به طور مثال ".\trace.log" ) .
  • Formatter Name: بعدا در این مورد بحث خواهیم نمود.
  • Message Footer: عبارتی است که در پایان ذخیره سازی هر لاگ نوشته می شود و باعث این می شود که لاگ های مختلف در یک فایل متنی به راحتی از دیگری قابل تمایز باشند.
  • Message Header: عبارتی است که در ابتدای ذخیره سازی هر لاگ نوشته می شود و باعث این می شود که لاگ های مختلف در یک فایل متنی به راحتی از دیگری قابل تمایز باشند.

در قسمت زیر یک لاگ ذخیره شده در یک فایل متنی را ملاحظه می کنید (تصویر شماره 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 را ذخیره نموده اید وجود دارد که حاوی اسکریپت مورد نیاز جهت ساخت جداول و پرویسجر های مربوطه استفاده می شود. برای بنده این فایل در آدرس زیر قرار دارد (این فایل همراه سورس کامل این مقاله از لینک بالای صفحه قابل دریافت می باشد):

C:\EntLib50Src\Blocks\Logging\Src\DatabaseTraceListener\Scripts

اسکریپت مربوطه دارای دو پروسیجر مهم به نام های Add Category و Write Log می باشد و به طور پیشفرض نیز در شکل بالا نمایش داده شده اند. در صورتی که بخواهید نام پروسیجر ها را در پایگاه داده تغییر دهید باید در این قسمت نیز این دو نام را تغییر دهید.

کاربرد سایر خصوصیات نیز کاملا مشهود می باشد. Database Instance Name، نام رشته اتصالی که باید در فایل پیکربندی ایجاد شود را نگهداری می کند.

در صورتی که علاقه مند به یادگیری عملکرد سایر Listener هستید، می توانید در اینترنت به دنبال منابع موجود بگردید.

معرفی فرمت کننده ها (Log Message Formatters):

خوب، آخرین مبحثی که قصد داریم در مورد آن صحبت کنیم، فرمت کننده ها می باشند. در تصویر شماره 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 ها را به آن ها اضافه کنید.

معرفی ویژگی Extended Properties:

اگر دقت کرده باشید در طول مقاله ما فقط خصوصیات از پیش تعریف شده ی کلاس LogEntry را مقدار دهی نموده ایم. این خصوصیات عبارت بودند از Title، Message، Priority و ... البته این خصوصیات به شکل جامعی تهیه شده اند و پاسخگوی اغلب نیاز های برنامه نویسان می باشند ولی ممکن است مواقعی پیش بیاید که نیاز داشته باشید اطلاعات دیگری را نیز همراه این خصوصیات لاگ کنید.

برای رفع این محدودیت در کلاس LogEntry خصوصیتی به نام ExtendedProperties وجود دارد.این خصوصیت یک Dictionary شامل زوج های مرتبی از نام ها و مقادیر دریافت می کند. برای استفاده از این خصوصیت باید اطلاعات مورد نظر خود را به شکل نام و مقدار بدان اضافه نماییم.

در مثال زیر ما دو خصوصیت جدید به نام extra1 و extra2 که شامل مقادیر value1 و value2 هستند را جهت لاگ کردن به این کلاس اضافه نموده ایم.

LogWriter logWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();

if (logWriter.IsLoggingEnabled())
{
    LogEntry logEntry = new LogEntry();
    logEntry.Title = "در این قسمت عنوان مربوط به لاگ قرار می گیرد";
    logEntry.Message = "در این قسمت متن کامل لاگ قرار می گیرد";
    logEntry.Categories = new List<string>() { "General" };
    logEntry.Priority = 11;
    logEntry.Severity = TraceEventType.Information;

    //Add extra data to log
    
Dictionary<string, object> dic = new Dictionary<string, object>();
    dic.Add(
"extra1", "value1");
    dic.Add(
"extra2", "value2");
    logEntry.ExtendedProperties = dic;

    logWriter.Write(logEntry);
}

شکل زیر قسمتی از اطلاعات لاگ شده توسط قطعه کد بالا را با استفاده از XML Trace Listener را نمایش می دهد (شکل شماره 22).



و در نهایت شکل زیر به زیبایی فرآیند لاگ نمودن با استفاده از کتابخانه Microsoft Enterprise Library را نشان می دهد (شکل شماره 23).



مثال های مختلف در مورد بلاک لاگ از طریق لینک بالای صفحه قابل دریافت می باشد.


 منابع :     30sharp.com

Microsoft Enterprise Library 5.0

Developer’s Guide to Microsoft Enterprise Library


برچسب های مرتبط