Nine MVP's Blog

15/03/2012

Application Design : Logging 1

Filed under: C#, Core System — Tags: , — Nine MVP @ 2:58 am

ตอนที่2
https://nine69.wordpress.com/2012/04/21/application-design-logging-2/

หายไปนาน กลับมากับหัวข้อที่ว่าด้วยเรื่องของการซับพอทโปรแกรมและระบบที่เรากำลังจะสร้างกัน เพราะคงน้อยมากที่นักพัฒนาหลังจากเขียนโปรแกรมเสร็จแล้ว จะหายไปไม่ต้องสนใจโปรแกรมของตนอีกเลย หลังจากมีผู้ใช้งานเริ่มใช้งานระบบนั้น ๆ  เราเรียกว่าการซัพพอทหลังการพัฒนาระบบ ไม่ว่าจะเป็น bug, human error, system failed, system down, system maintenance เมื่อเกิดขึ้นแล้ว ปัญหาจะวิ่งกลับมายังผู้พัฒนาหรือบุคคลที่ต้องเป็นแพะ (admin support) หากไม่ได้ออกแบบส่วนนี้ไว้หรือทำได้ไม่ดีพอ  เราจะได้เห็นฝ่าย IT เจ้าของระบบนั้นๆ นั่งทำงานคิ้วขมวดทั้งวันทั้งคืนเป็นแน่

 

ปัญหาหากโปรแกรมขาดการเก็บ Log 

ในระบบที่มีการใช้งานจากผู้ใช้ในระบบจำนวนมาก หลากหลายฝ่าย หลายตำแหน่ง ระดับการทำงานแตกต่างกัน และมีการเข้าใช้งานโปรแกรมที่เราได้พัฒนาไว้  บ่อยครั้งที่เกิดการทำงานที่ผิดพลาดไม่ว่าจะเกิดจากตัวระบบเอง หรือเกิดจากผู้ใช้งาน  ซึ่งหากเราไม่ได้ทำการเก็บบันทึกข้อมูลของปัญหาที่เกิดขึ้นไว้แล้ว  ยากที่จะทำการตรวจสอบและแก้ไขให้สะดวกและรวดเร็วได้

เนื่องจากต้องไปหาสาเหตุจากต้นตอของปัญหา ไม่ว่าจะเกิดจากผู้ใช้หรือระบบ, หน้าจอไหน, ข้อมูลใด, กลุ่มคลาสหรือเมดธอดอะไร ข้อมูลเหล่านี้มีความจำเป็นในการตรวจสอบ ซึ่งจะช่วยให้ผู้พัฒนาทำการทดสอบระบบด้วยกรณีเดียวกันได้เพื่อให้ทราบถึงปัญหา   ซึ่งโปรแกรมที่เราๆใช้กันอยู่ไม่ว่าจะเป็น Windows 7, Office, หรืออื่น ๆ ต่างก็มีการบันทึก log การทำงานทุกอย่างเพื่อให้ผู้ใช้งานสามารถเข้าไปดูเพื่อวิเคราะห์และแก้ไขปัญหานั่นเอง

สำหรับนักพัฒนาหน้าใหม่ อาจจะไม่ได้ดักจับ error ไว้ในโปรแกรมเลย หรือไม่ก็อาจจะใช้ MessageBox.Show(); พวกข้อความที่ error บอกผู้ใช้ระบบไปตรงๆ       ซึ่งผู้ใช้งานระบบคงไม่เข้าใจว่าเกิดอะไรขึ้น  ก็ต้อง print screen ส่งมาบอกผู้พัฒนาด้วยตัวเอง และบอกว่าทำอะไรไป ทำหน้าไหน ใส่ข้อมูลอะไร กดอะไรไป  

ถ้าเราเป็นผู้ใช้งานเองจะรุ้สึกยังไงกับโปรแกรมนี้? ยุ่งยาก มีปัญหา ไม่มีความน่าเชื่อถือ แถมยังต้องมานั่งอธิบายโปรแกรมเมอร์ โดนซักถามเหมือนทำความผิด   เจอผุ้ใช้แบบไม่สนใจไม่แคร์บอกไม่ขอใช้งานระบบ ตีกลับมาก็คงมีเคืองกันอีก ดูไม่เป็น professional เอาเสียเลย

ดังนั้นผู้พัฒนาอย่างเราๆ จึงจำเป็นที่จะต้องออกแบบระบบการเก็บ log การทำงานของโปรแกรมให้รองรับปัญหาที่จะเกิดขึ้นด้วย  

 

เราควรเก็บ Log อะไรบ้าง?

การบันทึก log นั้น อยู่ที่วัตถุประสงค์ของแต่ระบบที่ได้ออกแบบและตกลงกันไว้ แต่วัตถุประสงค์หลัก ๆ ของการเก็บ log นั้นมีอยู่ 2 ส่วนคือ

1. System Support เช่น การบันทึก Error, Information, System Status เป็นต้น

2. Audit Support กรณีที่่ต้องคอยให้ข้อมูลเพื่อการตรวจสอบการทำงานของผุ้ใช้ หรือตัวระบบเอง เช่นไม่ว่าจะ login, logout, access page, access service, approved, commit task เป็นต้น

โดยข้อมุลที่ควรจะถูกจัดเก็บอาจจะมีข้อมูลคร่าว ๆ ดังนี้

  1. Id (auto gen id) อาจจะเป็น bigint, long, guid เป็นต้น
  2. DateTime : วันที่และเวลาที่ทำการบันทึก log (ใช้เวลาที่ error จริง ๆ ใน Application)
  3. LogLevel : อ่านด้านล่าง
  4. Priority : อ่านด้านล่าง
  5. Title : หัวข้อที่จะบันทึก
  6. Application : กรณีมีใช้งานสถานที่เก็บ log รวมกันเช่น windows event log, database table เป็นต้น
  7. Module : ใช้บ่งบอกว่าเป็นโมดูลการทำงานส่วนไหนภายในโปรแกรม เช่น Member Register เป็นต้น
  8. Action : ใช้บ่งบอกว่าเป็นการทำงานอะไร เช่น Create New Register เป็นต้น
  9. Data : อาจจะเป็นข้อมูลที่ต้องเอาไว้ใช้ตรวจสอบ หรืออ้างอิงถึงเช่น Id ของ register user หรืออาจจะเป็น OrderNumber
  10. Message : เป็น message ของ error ที่เกิดขึ้น
  11. Trace : เป็น StackTrace ของ error ที่เกิดขึ้น
  12. SupportNo : โปรแกรมอาจจะมี troubleshooting document link แนบไว้ให้กรณีที่มีคำแนะนำให้ผู้ support ระบบ
  13. Host : อาจจะเป็น computer name, ip address ของ server นั้น ๆ ที่ Application ติดตั้งอยู่
  14. ClientIPAddress : เป็น ip address จริงของ user ที่เข้าใช้งาน application
  15. UserId : อาจจะเป็น username, user id, domain account ของผู้ใช้ที่ทำการ login ในตอนนั้น

Log Level: ซึ่งนิยมใช้งานกันดังนี้

  1. Fatal\Critical : เป็นความผิดพลาดของระบบที่เกิดขึ้นเอง เช่น OS เกิดปัญหา, executable file corrupt, Hardware ระบบเสียหาย
  2. Error : การบันทึกเมื่อระบบเกิดปัญหาขึ้นเช่น Exception ในโปรแกรม
  3. Warning : การบันทึกเพื่อเตือนว่าอาจจะมีการทำงานผิดพลาดเกิดขึ้นหลังจากนี้
  4. Audit : การบันทึกเพื่อตรวจสอบการทำงานของผุ้ใช้ต่าง ๆ
  5. Information : การบันทึกเก็บข้อมูลบางอย่างเพื่อใช้เป็นการอ้างอิง
  6. Debug : การบันทึกเพื่อใช้ในการตรวจสอบเขียนโปรแกรม
  7. Trace : บันทึกการทำงาน ณ จุดต่าง ๆ ของโปรแกรมตั้งแต่ต้นจนจบ

Priority: ระดับความสำคัญในการแก้ปัญหา

  1. High: เป็นระดับความสำคัญสูงสุด ซึ่งต้องต้องรีบตรวจสอบหรือแก้ไขปัญหาในทันที เช่น ไม่สามารถบันทึกข้อมูลลงในระบบได้ ทำให้ user ไม่สามารถทำงานต่อไปได้
  2. Medium: เป็นปัญหาที่มีความสำคัญ แต่ระบบหลักยังคงทำงานได้ เพียงแต่อาจจะไม่สมบูรณ์ในบางโมดูล เช่น feed ข่าวจากเว็บมาแสดงไม่ได้ เป็นต้น
  3. Low: เป็นปัญหาที่กระทบต่อการทำงานของผู้ใช้ และควรจะแก้ไขใน released ต่อไปเช่น เกิด exception ใน loop แต่เรา try ข้ามไปและทำงานต่อได้ถูกต้อง เป็นต้น

เราสามารถบันทึก Log ต่าง ๆ เก็บไว้ที่ไหนได้บ้าง

  • File การบันทุึกเก็บลงไฟล์นั้น

มีข้อดี

  • สามารถสร้าง method ในการเขียนไฟล์ได้เลย
  • บันทึกข้อมูลได้รวดเร็ว

มีข้อเสีย

  • เรื่องการกำหนดขนาดไฟล์ไม่ให้ใหญ่มาก และการจัดเก็บไฟล์ให้เป็นระบบ
  • มีโอกาส file corrupt และ read/write locked
  • รวมไปถึงการเข้ามาอ่าน log file ทั้งเรื่องรูปแบบของไฟล์ สถานที่เก็บไฟล์
  • Database การบันทึกลง table ใน database

มีข้อดี

  • ในด้านการจัดการ โดยสามารถลดการกระจัดกระจายของ log โดยรวมไว้ที่เดียว
  • สามารถเข้าถึงและอ่าน log ได้ง่าย

ข้อเสีย

  • จะกินเนื้อในการเก็บข้อมูลจำนวนมาก
  • มี cost ที่เพิ่มขึ้นเช่น CPU time, Network bandwidth ของ DB Server
  • Windows Event Log

ข้อดี

  • เก็บไว้ในที่เป็นมาตรฐานของ OS
  • สามารถเรียกดูได้โดย remote event viewer หรือผ่านหน้าเครื่องตรงๆ

ข้อเสีย

  • มีผลต่อประสิทธิภาพของ OS
  • มีพื้นที่จำกัดในการเก็บบันทึก

และยังมีที่เก็บอีกมากมายแล้วแต่ความต้องการไม่ว่าจะเป็น Email, ยิง TCP, ส่งไปเข้า MSMQ เป็นต้น ซึ่งก็แล้วแต่ว่าเราจะเลือกสถานที่จัดเก็บเพื่อความสะดวกและเหมาะสม

 

รู้จักกับ Error ที่เกิดขึ้นในการเขียนโปรแกรม (Exception)

โค้ดจำนวนมากผู้พัฒนาได้เขียนออกไป กรณีหากเกิดการทำงานที่ผิดพลาดขึ้น ในตอน Run time ระบบจะทำการโยน (Throw) ชุดคำสั่งมีการทำงานที่ผิดพลาดกลับมายังโปรแกรมในรูปของ Exception ซึ่งอาจจะทำให้ระบบแฮ้งค้าง เกิดไดอะล็อกเตือน ไปจนหยุดการทำงานของโปรแกรม 

กรณีที่เราไม่ต้องการให้โปรแกรมหยุดการทำงาน และตรวจจับปัญหาของชุดคำสั่งได้นั้น แต่ละภาษาก็จะมีชุดคำสั่งในการดักจับ Error ที่เรียกว่า Try…Catch Block  ซึ่งเขียนได้ในรูปนี้

Code 1:
  1. Person person1 = null;
  2. try
  3. {
  4.     //person1 = new Person();
  5.     person1.FullName = "call null object";
  6.     
  7. }
  8. catch (Exception ex)
  9. {
  10.     MessageBox.Show(ex.ToString());
  11. }
  12. finally
  13. {
  14.     person1 = null;
  15. }

 

จาก code ตัวอย่างด้านบนจะเห็นได้ว่า

(line8-11) มีการ catch error ลง Exception Class เมื่อเกิด error ขึ้นใน try block ด้านบน (line 2-7)

ทำให้โปรแกรมเข้าไปทำงานต่อบล็อกของ catch พร้อมได้รายละเอียดของ error เพื่อนำไปจัดการปัญหาที่เกิดขึ้นต่อไป ในตัวอย่างแสดงแค่แสดง messagebox เท่านั้น

เมื่อทำการ  Watch ex object ดูก็จะเห็นข้อมูลดังนี้

Image 1: image 

Exception Class เป็นเบสคลาสของ exception class อื่นๆ ซึ่งพบบ่อยว่ามักใช้ในการดักจับ error ทุกประเภทไม่ว่าจะ IO , Network , Permission , COM ซึ่งค่อนข้างใช้งานได้กว้างขวาง โดยโครงสร้างของคลาสจะมี property ของข้อมูลพื้นฐาน ให้ใช้งานดังนี้

Property Name

Description

Data จะบอกข้อมูลของ Data ที่เกี่ยวข้องกับ Error นั้น
HelpLink เป็น link ไปยัง document เพื่อช่วยอธิบายปัญหา หาก exception นั้นมีใส่ไว้
HResult เป็น number ที่กำหนดให้ error นั้น
InnerException เป็น exception ที่เป็นสาเหตุให้เกิด exception นี้
Message ข้อความของ error
Source ชื่อของโปรแกรมที่ error
StackTrace เป็นข้อมูลที่เรียงลำดับการ call จาก Main Method ไปจนถึง line number ที่เกิด error
TargetSite ชื่อ Main Method ที่โยน Exception

ซึ่งข้อที่ควรสนใจคือ Exception Class ไม่ควรใช้งานเป็นคลาสหลัก เพราะเป็นเบสคลาสซึ่งจะทำให้เสียข้อมูลในส่วนของ exception ที่ควรจะได้ไม่ครบถ้วนของปัญหาที่เกิดขึ้น เช่น SqlException ที่จะมี Number property ของ Database แจ้งออกมาด้วยเป็นต้น แต่ถ้าคิดไม่ออกจริง ๆ ว่า try..catch block นี้จะเกิด exception ตัวไหนบ้างก็รอง catch สุดท้ายไว้ด้วย Exception Class ก็ได้ครับ

Exception Class ได้ถูกกำหนดให้เป็น Based class ซึ่งถูกนำไปใช้โดยแยกออกตามส่วนของระบบดังนี้

  1. SystemException Class  เป็นคลาสได้ที่กำหนดไว้แล้วใน Common Language Runtime Class ซึ่งจะใช้เป็น Base Class อีกครั้งสำหรับสร้าง exception class ที่แยกย่อยออกไปตามการทำงานเช่น NullReferenceException, ArithmaticException, IOException, SqlException เป็นต้น
  2. ApplicationException Class  เป็นคลาสที่อนุญาตให้ผู้พัฒนานำไปใช้เป็น base class สำหรับใช้สร้าง Exception class ที่จะใช้โปรแกรมนั้น เช่น InvalidBusinessRuleException เป็นต้น

    ลองดูโค้ดชุดนี้ที่มีการสร้าง Exception ต่างๆ ในแต่ละกรณีตัวอย่าง

    Code 2:
    1. try
    2. {
    3.     //Case 1: NullReferenceException
    4.     Person person1 = null;
    5.     person1.FullName = "call null object";
    6.  
    7.     //Case 2: ArithmeticException
    8.     int i = 5;
    9.     int x = 0;
    10.     var res = i / x;
    11.  
    12.     //Case 3: ApplicationException
    13.     throw new ApplicationException("My Error");
    14.  
    15. }
    16. catch (NullReferenceException ex) //Case1
    17. {
    18.     MessageBox.Show(ex.ToString());
    19. }
    20. catch (ArithmeticException ex) //Case2
    21. {
    22.     MessageBox.Show(ex.ToString());
    23. }
    24. catch (ApplicationException ex)  //Case3
    25. {
    26.     MessageBox.Show(ex.ToString());
    27. }
    28. catch (SystemException ex) //Case1, Case2
    29. {
    30.     MessageBox.Show(ex.ToString());
    31. }
    32. catch (Exception ex) //Case1, Case2, Case3
    33. {
    34.     MessageBox.Show(ex.ToString());
    35. }

Line 5:  จะเกิด error เนื่องจาก person1 ยังไม่ได้ทำการกำหนดค่าเริ่มต้น new Person(); ซึ่งจะวิ่งไปที่ Line 16: ซึ่งดักด้วย NullReferenceException  กรณีที่อ้างอิง object ที่เป็น null

Line 10: จะเกิด error เนื่องจากเป็นการหารด้วย 0  ซึ่งจะวิ่งไปทำงานที่ Line 20: ซึ่งจับด้วย ArithmeticException กลุ่มคณิต

Line 13: จะเกิด error เนื่องจากเป็นการสร้าง ApplicationException แล้ว throw ให้โปรแกรมเกิด error  จะวิ่งไปทำงานที่ Line 24: คือตรงตัว class

ส่วน Line 28:  หากลบโค้ดตั้งแต่ Line 16 – 27 ออก  Line 5 และ 10  จะวิ่งมาทำงานที่นี่เพราะเป็น base class ที่สืบสอดมาจาก Exception Class ใช้งานในกลุ่มของ CLR Exception ทั้งหมด

 

สำหรับ .NET App เราสามารถบันทึก Log ด้วยอะไรได้บ้าง?

Custom Log

โดยเป็นการเขียนโค้ดขึ้นมาเอง โดยอาจจะมี static method เอาไว้ใช้งานโดย ให้บันทึกลง File, ยิงเข้า StoreProcedure ลง Table, ส่ง Email เป็นต้น ซึ่งต้องเขียนจัดการเองทั้งหมด ซึ่งหากเขียนไว้ใช้เองก็จะพอดีกับงาน  แต่ค่อนข้างไม่ยืดหยุ่นแล้วมีข้อจำกัด รวมไปถึงมีความเสี่ยงในการจัดการของตัว Log ที่เขียนขึ้นเอง

3rd Party Library

การใช้กลุ่ม logging open source ถือว่าน่าสนใจมากกว่าเมื่อเปรียบเทียบข้อดีข้อเสียแล้ว  เพราะ library เหล่านี้ถูกพัฒนาขึ้นมาและใช้งานจากกลุ่มนั้น ๆ มีการพัฒนาและแก้ไขปรับปรุงโค้ดต่อเนื่อง รวมไปถึงความสามารถที่ช่วยลดการเกิดปัญหาเกี่ยวกับตัว Log เองเช่น การทำ file rolling, file size limit, various target source, multiple target source, Alternate Source,  write buffer, etc.  ผมขอแนะนำที่น่าสนใจ

1. Enterprise Library 5.0: Logging Block จาก Microsoft เอง ก็น่าสนใจตัวนึง มีการพัฒนาต่อเนื่อง และมี Document/Lab ให้เอาไปทดลองทำกันได้

2. Log4Net  เป็นการพัฒนาต่อยอดมาจาก Log4J มีการใช้งานกันอย่างกว้างขวาง แต่ก็ไม่เห็นมี update version มาซักระยะแล้ว

3. NLog  เป็นตัวที่จะนำมาแนะนำในบทความตอนต่อไปครับ

     

ส่งท้าย

ในตอนนี้พยายามชี้ให้เห็นถึงปัญหาของการซัพพอทระบบหรือโปรแกรม  ที่เรากำลังจะส่งต่อไปให้ผุ้ใช้งานและผุ้ดูแลระบบ  ให้เข้าใจถึงความสำคัญว่าทำไมเราต้องเก็บ log ข้อมูลเอาไว้   ทั้งได้แนะนำข้อมูล log เบื้องต้นและการจัดการ exception ที่เกิดขึ้นใน .NET Application

ในตอนต่อไปจะแนะนำการใช้งาน NLog และแนะนำการเก็บบันทึกข้อมูลจาก Application ที่แตกต่างกันครับ

 


 

Chalermpon Areepong Nine (นาย)

Microsoft MVP Thailand ASP.NET

email : nine_biz-talk.net at hotmail dot com

3 Comments »

  1. NLog รอเลยกะลังอยากได้มาใช้อยู่ ขอตัวอย่างเลยนะ อิอิ

    Comment by Ixus Getbackers — 15/03/2012 @ 2:58 pm

    • รอต่อไป หลัง MVC Lab จะเอาขึ้นให้ หึหึ

      Comment by Nine MVP ASP.NET — 19/03/2012 @ 3:52 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: