Sử dụng Log4Net trong C#

I/ Log4net là gì?

- Log4net là một công cụ giúp người lập trình ghi lại những thông tin trong lúc chạy ứng dụng. Nó chính là một phiên bản chuyển thể từ log4j và vẫn tiếp tục được phát triển kể từ năm 2001. Trong trường hợp ứng dụng của bạn có lỗi mà vẫn không tìm được nguyên nhân, log4net có thể là vị cứu tinh để giúp bạn xác định nơi gây lỗi. Ngoài ra, Log4net còn có thể thay đổi trạng thái log lúc chương trình chạy mà không cần ngừng chương trình. Bên cạnh đó, khi sử dụng log4net sẽ không ảnh hưởng đáng kể đến performance của ứng dụng, log4net còn được thiết kế với tính flexibility rất cao, chúng ta có thể mở rộng và thêm thắt những thứ mình muốn vào thư viện log4net, chẳng hạn như cách thức log, định dạng log, …

(Các bạn có thể download source code sample ở đây)

II/ Tại sao lại sử dụng log4net – lợi ích của log4net

- Như tôi nói ở trên, có những trường hợp nếu không có log4net bạn sẽ không thể nào giải quyết được. Giả sử một ngày đẹp trời bạn kí được hợp đồng béo bở làm phần mềm cho một khách hàng lớn và khó tính. Vì là một công ty lớn nên security của họ rất cao. Khi deploy chương trình cho người ta, bạn phải hẹn trước và phải qua nhiều cửa kiểm tra nghiêm ngặt. Những máy chỉ được cài đặt chương trình bạn viết cho họ và không được cài bất cứ cái gì khác. Như vậy khi sử dụng, nếu chương trình của bạn có lỗi thì làm sao để tìm nguyên nhân? Cùng lắm thì bên khách hàng sẽ chụp màn hình lỗi hoặc email đại khái cho bạn, và với những thông tin chung chung như vậy sẽ rất khó để bạn khắc phục. Ngoài ra bạn không thể cài VS.NET 2005 lên máy khách hàng hoặc tới tận nơi để debug. Nhưng nếu có sử dụng log4net, thông tin về quá trình chạy sẽ được ghi lại trên file hoặc thậm chí email cho bạn. Khi đó bạn sẽ dễ dàng tìm hiểu giải quyết vấn đề trên, và nhanh hay chậm tùy thuộc vào bạn thêm những đoạn log cụ thể và chính xác như thế nào trong code.

- Thêm một ví dụ nữa mà tôi đã từng gặp phải, đó là một project liên quan đến Webservice. Nhóm tôi phải làm một webservice để đọc thông tin trên server và trả kết quả về phía chương trình desktop. Quá trình đọc và tính toán dữ liệu trên server khá phức tạp và qua rất nhiều bước và hầu như không thể debug được. (thực ra là có thể debug được bằng cách sử dụng remote debugger, nhưng sau này tôi mới biết). Nhờ vào log4net, tôi ghi lại những bước tính toán, giá trị các biến trong một lần gọi hàm webservice và từ đó đã fix được khá nhiều bug khó.
Dù bạn là một người kĩ tính đến cỡ nào, bạn giỏi lập trình đến mức nào thì vẫn có thể có những lúc chương trình tung những exception mà bạn không ngờ đến. Sử dụng log4net có thể giúp bạn ghi lại những lần bị lỗi như vậy và từ đó bạn sẽ có cách để fix bug. Hơn nữa cách sử dụng rất dễ và nhanh gọn lẹ thì tại sao ta lại không sử dụng chứ nhị :bbpcuoi5:

III/ Sử dụng như thế nào?

- Trong bài viết này, tôi sẽ giới thiệu cách sử dụng log4net cho một window application và sẽ nói đến cách config cho log4net ghi thông tin log ra file bằng một file App.config. Thực ra đối với web application thì cách sử dụng hoàn toàn tương tự. Chỉ có một số trường hợp file log của bạn không sinh ra được vì không đủ quyền. Như các bạn biết thì Web application chạy dưới 1 process bằng quyền của user ASPNET trong Windows, dó đó nếu user này không đủ quyền ghi file vào folder web của bạn thì file log tương ứng cũng có thể không được tạo ra. Nếu bạn áp dụng log4net cho trang web của mình, và thuê 1 host ở VN để đưa code lên nhưng file log không sinh ra, bạn có thể gọi điện hỗ trợ dịch vụ và nhờ họ thêm permisson cho user ASPNET quyền ghi file vào folder web của bạn.

1/ Bước 1: Hãy download version mới nhất của log4net từ website apache. và add reference vào project của bạn. Khi tôi viết bài này thì version mới nhất của log4net là 1.2.10.

Log4net

2/ Bước 2: Thêm dòng dưới đây vào file AssemblyInfo.cs (Trong folder Property của project)

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log4netSample.exe.config", Watch = true)] //For log4net 1.2.10.0
- Đây là bước mà tôi thường quên nhất :bbpcuoi3:. Thêm đoạn code này vào file assemblyInfo sẽ giúp log4net biết tìm những thông tin cấu hình của nó ở file App.config. Ở đây các bạn thấy là ConfigFile=Log4netSample.exe.config trong khi file config của chúng ta là App.config. Nguyên nhân là do file config của window application sẽ tự động build thành tên_assembly.config. Vì chương trình của tôi khi build ra sẽ là Log4netSample.exe nên tôi sẽ chọn giá trị là Log4netSample.exe.config cho config file. Đối với Web application bạn sẽ set là Web.config vì file config cho web app sẽ không bị đổi tên.

- Trong web application, thay vì để dòng lệnh config log4net trong Assembly info, ta sẽ để nó trong event Application_Start()

3/Bước 3: Nếu project của bạn chưa có file App.config thì bạn hãy thêm vào file App.config. Đây là file cấu hình cho ứng dụng của bạn. Sau đó bạn thêm những cấu hình dưới đây file file App.config.
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

</configSections>

<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Log4netSampleLog.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />

</layout>

</appender>

<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />

</root>

</log4net>



Giải thích nội dung file cấu hình:

-Trong file cấu hình này, tôi sử dụng RollingFileAppender. Có rất nhiều loại Appender được xây dựng sẵn trong thư viện log4net. Mỗi loại sẽ có công dụng ghi nội dung log vào một nơi khác nhau. Trong đó RollingFileAppender là được sử dụng nhiều nhất và cũng dễ sử dụng nhất :D. Tôi sẽ giải thích những gì tôi nghĩ là khó hiểu nhất :bbpskien:

<file value="Log4netSampleLog.txt">

  • Thông tin log của chúng ta sẽ được ghi vào file Log4netSampleLog.txt, file này sẽ nằm ở thư mục chạy của ứng dụng, cùng cấp với file exe và file .config của chúng ta. Nếu muốn nó lưu file vào chỗ khác chúng ta có thể hardcode đường dẫn ở đây.
<maxsizerollbackups value="10" />

  • Dữ liệu log sẽ được ghi vào file, vì ta đang sử dụng là RollingFileAppender, nên khi kích thước file vượt quá một mức nào đó thì nó sẽ đổi tên file cũ và ghi vào file mới. Tổng số lượng file tối đa sẽ là 10 và những file cũ nhất sẽ bị xóa nếu số lượng file vượt quá 10.

<maximumfilesize value="1MB">

  • Kích thước file log tối đa sẽ là 1MB.

Layout:
  • Đây là phần khá thú vị, những text log mà chúng ta ghi ra sẽ kèm thêm một số thông tin theo như phần định dạng trong layout như ngày tháng, threadId, className, ... Các bạn có thể tùy biến phần layout này để được log output dễ nhìn nhất.




<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />
<layout>



Level:
  • Level mặc định sẽ là Debug cho mọi nơi có sử dụng log trong chương trình của bạn. Nghĩa là nếu bạn khai báo như hình, thì mọi chỗ bạn log đều được ghi xuống file vì level DEBUG là level thấp nhất, nhưng nếu chỗ này bạn để là ERROR thì chỉ có những log với level cao hơn hoặc bằng ERROR mới được ghi xuống file. Khi deploy chương trình cho khách hàng, thường thì chúng ta sẽ để level default là ERROR, khi sử dụng có lỗi ta sẽ yêu cầu khách hàng sử lại thành DEBUG nếu cần thiết.

<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />

</root>



- Thông thường người ta sử dụng full name của class (kèm theo đầy đủ namespace) để dùng như loggerName. Cách dùng này rất hợp lý vì chúng ta sẽ biết đoạn log của mình sinh ra từ class nào. Nếu chúng ta không set trong file config, các logger sẽ thừa hưởng level từ cấp trên nó và level cao nhât là root như trong hình. Ví dụ bạn có 2 lớp như sau : MyApp.Service.AMyApp.Service.A.B thì khi đó sẽ có 2 loggerName tương ứng với 2 name space trên và loggger thứ 2 sẽ thừa hưởng level như logger1. Bạn nên tham khảo thêm phần này ở Logger hierarchy. Có khi chương trình của bạn có sử dụng một library nào đó mà library này lại có sử dụng log4net, khi đó bạn sẽ có nhu cầu tắt log4net cho library đó và đây chính là nơi bạn cần chỉnh sửa. (NHibernate là 1 ví dụ về library có sử dụng log4net)



4/Bước 4:

- a) bạn thêm namespace log4net cho những nơi nào cần sử dụng log4net.
- b) Sau đó thêm đoạn code dưới đây trong lớp nào có sử dụng log4net


private static readonly ILog _logger = LogManager.GetLogger(typeof(TênLớpCủaBạn).Name);

Hoặc bạn có thể sử dụng cách sau đây nếu thích tổng quát

private static readonly ILog logger = LogManager.GetLogger(

System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);


5/Bước 5
: Trong code của bạn, nơi nào cần log bạn sẽ thêm đoạn code sau đây:


_logger.Debug("Muahahaha");

Hoặc

_logger.Error("Muahahaha");

- Thật ra để tăng tối đa tốc độ, nhóm tác giả khuyên chúng ta nên khai báo một biến boolean để kiểm tra xem có cần log hay không, nếu có thì mới gọi hàm log.

bool isLogEnabled = _logger.IsDebugEnabled;

- Và trong code:

if (isLogEnabled)
{

_logger.Debug("Muaahahaha");

}


- Các bạn thấy tôi có sử dụng _logger.Debug và _logger.Error, như vậy trong trường hợp nào thì sử dụng .Debug, trường hợp nào sử dụng .Error. Theo tôi thì khi nào cần ghi lại những thông tin sẽ giúp chúng ta phát hiện lỗi nếu có thì chúng ta dùng .Debug, những nơi chúng ta try catch Exception thì chúng ta log Error và thông tin log sẽ là StrackTrace của cái Exception đó.

try
{

//Make some error here

}
catch(Exception ex)
{

_logger.Errror(ex);// Right
_logger.Errror(ex.Message);// Wrong. Because most time, the ex.Message is useless.

}

- Ngoài Debug và Error, logger còn có các level khác được xếp theo thứ tự độ ưu tiên. Tùy vào bạn chính config như thế nào mà những đoạn log của bạn có hiện ra hay không.


IV/ Log4net còn có thể làm gì?


- Ngoài khả năng ghi những đoạn log vào file, log4net còn có thể ghi những thông tin log đó vào database, ra console màn hình, email cho chúng ta, thậm chí net send :D. Ngoài ra, với tính mở rất cao, log4net còn cho phép người sử dụng kế thừa mở rộng và thêm thắt. Đối với cá nhân tôi, sử dụng log4net với FileAppender là quá đủ, hiếm khi tôi cần phải viết thêm. Nhưng ai mà biết được sau này sẽ gặp chuyện gì :bbpnodo:. Nếu các bạn muốn tìm hiểu thêm về log4net, hãy lên trang web http://logging.apache.org/log4net và nhớ chia sẽ với tôi những gì bạn biết được :bbpchao:


V/ Khi nào tôi nên dùng log4net?


Ngay sau khi đọc bài này :bbpbtay:

- Hi vọng sau khi đọc bài viết này bạn có thể áp dụng log4net nếu chưa từng sử dụng. Bạn sẽ thấy rằng dùng log4net rất dễ và rất có ích khi ta áp dụng ngay từ những dòng code đầu tiên. Một số người bạn của tôi thường đợi đến lúc viết xong mới bắt đầu thêm log4net khi có yêu cầu, tôi thấy như thế không nên. Theo tôi ta nên tập thói quen sử dụng log4net đúng lúc đúng chỗ và tự giác :bbpsdieu2: cũng giống như đánh răng và tắm rửa mỗi ngày vậy. Thực ra chúng ta có thể không tắm vài ngày, không đánh răng cũng được nếu ở một mình vì chẳng ảnh hưởng đến ai và chẳng ai biết, nhưng đến một lúc nào đó chúng ta sẽ thấy được lợi ích của việc tự giác. :bbptthan:



Tài liệu tham khảo:
http://logging.apache.org/log4net
http://www.codeproject.com/KB/aspnet/log4net.aspx

Posted in Labels: , |

4 comments:

  1. nin9 Says:

    Bài viết rõ ràng và hữu ích ghê, thank anh Thoại :D

  2. Anonymous Says:

    Bạn cho mình hỏi tại sao khi khai báo log phải dùng static only. Khi mình test, 2 người truy cập vào 1 trang thì khi xem IP bị sai.
    Tình huống đó là : người thứ nhất vào trang nào đó, người thứ 2 vào, người thứ nhất tiếp tục vào trang khác. Khi kiểm tra IP thì IP của người thứ nhất bị thay đổi thành IP của người thứ 2(khi truy cập vào sau người thứ 2).
    Mình đang tìm cách khắc phục nhưng chưa được

  3. Nguyễn Thoại Says:

    Khai báo là readonly vì ko muốn logger bị thay đổi trong quá trình chạy của ứng dụng. Tùy mục đích mà bạn có thể khai báo là static hay không.

    Trong trường hợp kiểm tra IP của bạn, mình nghĩ không nên để là static. Vì khi để là static nó sẽ mang scope của toàn app, nên trạng thái của user sau có thể bị đè lên user vào trước.

    Theo mình suy đoán (đoán thôi nhe :D) , trong ASP.NET mỗi user vào trang web thì IIS sẽ tạo ra một session riêng nên nếu bạn chỉ khai báo là private readonly ... thì sẽ ghi log được từng IP độc lập.

    Mong kết quả từ bạn.

  4. Nam Says:

    Cám ơn Thoại Nguyễn vì đã dành công sức truyền thụ lại kiến thức cho mọi người.

    Ở DDV có làm seminar ôn lại kiến thức về log4net, trong đó có lấy bài viết này của em làm recommended reading đó. Hehehehe.

rss
 

About Me

Place I've live
Near Bossley Park, Sydney, NSW, Australia
Place I've work
  • Freelancer (from 06/2010 to present)
  • Harvey Nash (from 05/2008 to 06/2010)
  • DataDesign Vietnam (10/2005 to 04/2008)
Place I've studied
  • University of Natural Science (Bachelor of Science HoChiMinh City Vietnam From 2001 to 2005)
  • Le Hong Phong High School (HoChiMinh City Vietnam From 1997 to 2000)