Thứ Tư, 23 tháng 6, 2021

Tích hợp Log4j vào project Java Web để tối ưu việc ghi Log

Tích hợp Log4j vào project Java Web để tối ưu việc ghi Log

Trương Chí Hải

-          Mục đích: Bài viết nhằm mục đích hướng dẫn tích hợp thư viện Log4j vào project Java Web để cung cấp giải pháp ghi log tối ưu hơn trong việc tracking, fix bug và thu thập hành vi của người sử dụng.

 

-          Yêu cầu kiến thức cơ bản:

·         Nắm rõ những kiến thức cơ bản của lập trình hướng đối tượng bằng ngôn ngữ Java.

·         Nắm vững các khái niệm về lập trình web sử dụng J2EE hay JavaEE với các kiến thức về Servlet, JSP. (tham khảo tại địa chỉ http://www.kieutrongkhanh.net/search/label/Servlet%26JSP )

·         Hiểu và thực hiện deploy ứng dụng bằng server Tomcat rời cùng với việc cấu hình biến môi trường để tomcat có thể thực hiện (tham khảo tại địa chỉ http://www.kieutrongkhanh.net/2016/11/video-cau-hinh-trien-khai-tomcat-server.html )

 

-          Tool sử dụng:

·         IDE: Netbean 8.x

·         JDK: JDK 8 update 251

·         Library: log4j-1.2.17 (Download tại đây, sau đó giải nén và add hay copy file log4j-1.2.17.jar vào thư viện project)

 

I . Giới thiệu

-          Ghi log là việc lưu lại record của kết quả hoặc lỗi phát sinh khi chạy code. Chính nhờ việc ghi log này, chúng ta có một cái nhìn tổng quát hơn về sản phẩm của chúng ta, dễ dàng track lại lỗi phát sinh ở đâu, ở đoạn code nào để từ đó có phương án giải quyết, khắc phục nhanh nhất. Tính quan trọng của việc ghi log được thể hiện rõ nhất ở những hệ thống đang trong production, khi có lỗi xảy ra thì log chính là nơi đầu tiên ta sẽ tìm đến. Ở bài viết này, chúng ta sẽ làm quen với thư viện Log4j của Apache và tích hợp nó vào trong một project Login with Java Web đơn giản để ghi log.

 

II. Tích hợp Log4j vào project

1.       Tạo 1 project Java Web

 

 

2.       Add file log4j-1.2.17.jar vào trong thư viện của project (download tại đây và giải nén file zip)

 

3.       Sử dụng Log4j

-          Để sử dụng Log4j, phải theo các bước sau đây:

·         Add file thư viện vào project (đã thực hiện trong các bước trên)

·         Cấu hình Log4j với file properties

·         Tạo ContextListener để tự khởi chạy log4j với cấu hình file properties mỗi khi mở project

·         Ghi câu lệnh log để thực hiện log file

-          Để cấu hình cho việc ghi log với log4j chúng ta sẽ tạo một file với đuôi .properties và đặt trong WEB-INF, ở trong demo này file được tạo sẽ tên là log4j.properties, các bước tạo file sẽ như sau:

o   Tạo file trong thư mục WEB-INF, click phải chuột trên thư mục WEB-INF, chọn New, chọn Other….

o   Click chọn Empty File ở phần File Types

o   Đặt tên file tùy ý với phần mở rộng là properties. Ở ví dụ này chúng ta đặt tên là log4j.properties và nhấn Finish

o   File log4j.properties sẽ được tạo ra như hình bên dưới

-          Cấu trúc file Log4j có các thành phần chính như sau:

·         Logger: Ghi nhận thông tin nào sẽ được log.

·         Appender: Ghi nhận thông tin sẽ được log ở đâu.

·         Layout: Định dạng thông tin sẽ được log ra như thế nào.

-          Ngoài ra log còn có các cấp độ (log level), khi viết log, chúng ta nên dựa theo log level để phân loại và sử dụng. Độ ưu tiên của log level từ thấp đến cao như sau:

 

ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF

o   ALL: Là cấp độ thấp nhất, khi rootLogger được khai báo với level này thì mọi log level đều sẽ được ghi ra.

o   DEBUG: Các thông tin được log với mục đích dùng trong việc Debug.

o   INFO: Các thông tin được log nhằm hiển thị thông tin của một quá trình, một phương thức đang hoạt động của hệ thống hiện hành.

o   WARNING: Các thông tin được log là các cảnh báo về hoạt động bất thường trong hệ thống nhưng vẫn đảm bảo được tính ổn định trong chức năng.

o   ERROR: Các thông tin được log là các lỗi khi chạy trương trình trong hệ thống, khiến cho một hoặc nhiều chức năng hoạt động không chính xác.

o   FATAL: Các thông tin được log là các lỗi nghiêm trọng, có khả năng làm sập toàn bộ hệ thống hiện hành.

o   OFF: Là cấp độ cao nhất, khi rootLogger được khai báo với level này thì toàn bộ log bất kể level đều sẽ không được ghi ra.

 

-          Chúng ta thực hiện thiết lập file log4j.properties như hình sau:

Sau đây chúng ta tìm hiểu các nội dung chúng ta đã cấu hình ở trên:

·         rootLogger: Dùng để định nghĩa cấu hình chung cho tất cả đối tượng Logger trong project.

è Theo như hình trên, chúng ta khai báo rootLogger với log level là Debug, nghĩa là chỉ những log với level cao hơn hoặc bằng Debug mới được ghi ra, và việc ghi log sẽ được thực hiện ở Appender1 và Appender2.

·         Appender1: Chúng ta sẽ dùng để cấu hình việc ghi log trên Console với khai báo ConsoleAppender như trong hình.

·         Appender2: Chúng ta sẽ dùng để cấu hình việc ghi log vào file với khai báo FileAppender như trong hình.

·         PatternLayout: Dùng kết hợp với ConversionPattern để định dạng cấu trúc thông tin sẽ được ghi vào log.

·         ConversionPattern: Dùng để thiết đặt định dạng thông tin để ghi vào log. Tôi xin phép được giới thiệu rõ hơn với vị dụ ở hình trên, ta có định dạng: %-7p %d [%t] %c %x - %m%n

§  Kí hiệu % là tiền tố cho các kí tự định dạng nằm phía sau nó, một kí tự định dạng hoàn chỉnh sẽ như thế này: %p. Nếu kí tự định dạng cần in ra không có, log sẽ in ra một khoảng trắng.

§  %-7p: Trong đó kí tự “p” là để in ra cấp độ log hay log level, -7p nghĩa là in ra cấp độ log và trong trường hợp tên của cấp độ log ấy nhỏ hơn 7 kí tự thì sẽ tạo một khoảng trống nhỏ bên phải sao cho bao gồm cả tên và khoảng trống phải đủ 7 kí tự.

§  %d: Kí tự “d” dùng để in thời gian ghi log. Có thể điều chỉnh được định dạng ghi ra hoặc không điều chỉnh gì cả để in ra mặc định theo định dạng:

yyyy MM dd HH:mm:ss,SSS

§  [%t]: “t” báo hiệu log sẽ in tên thread xử lý việc ghi log này theo định dạng:

[tên-thread-xử-lý-ghi-log]

§  %c: Kí tự “c” dùng để in ra Category name hay còn gọi là Logger name đã xử lý việc ghi log này.

§  %x: Kí tự “x” dung để in ra NDC (nested diagnostic context) có liên hệ với thread đã xử lý việc ghi log này. Nếu không tìm thấy sẽ in ra một khoảng trống.

§  ‘-‘ :  In một dấu “-“ tại vị trí cố định vào log.

§  %m: Dùng để in ra log message.

§  %n: Báo hiệu kết thúc một dòng, xuống dòng mới.

Sau đây là một ví dụ cho thông tin được ghi vào log với định dạng như trên:

è Quý vị có nhu cầu tìm hiển thêm về ý nghĩa và cách định dạng cấu trúc thông tin để ghi log có thể tham khảo tại đây:

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html

·         Khi ghi log vào file ở Appender2, chúng ta có thể cấu hình sao cho việc ghi log có thể theo dạng động hoặc tĩnh với khai báo File. Theo như trong hình, chúng ta đã fix cứng đường dẫn nơi log file sẽ được ghi ra và tên của file log (C:/Users/DELL/Documents/NetBeansLogs/Logfile.log)

 

-          Tiếp theo sau đây, chúng ta sẽ cấu hình context-param trong context Scope cho file log4j.properties trong tập tin web deployment descriptor (web.xml) để có thể sử dụng như một biến toàn cục để các resource trong ứng dụng web có thể reference tới và sử dụng trong quá trình thực thi ứng dụng.

o   Chúng ta cấu hình param có tên là log4j-config-location chỉ tới đường dẫn file này trong ứng dụng web như hình bên dưới

-          Tiếp theo, chúng ta sẽ tạo ContextListener và thiết lập cấu hình để mỗi khi project deploy vào trong container thì các thiết lập đặt trong file log4j.properties cũng sẽ được auto cấu hình cho log4j.

o   Chúng ta thực hiện tạo Context Listener, bằng cách new File, chọn Web trong categories, rồi chọn Web Application Listener trong File Types

o   Chúng ta đặt tên class (ở đây chúng ta có thể đặt ContextListener), đặt tên package và chọn Context Listener trong ô Interfaces to implement. Click nút Finish

o   File ContextListener được tạo ra sẽ hiển thị như hình bên dưới

o   Chúng ta thực hiện cấu hình nội dung file ContextListener như sau:

§  Annotation @WebListener được đặt trên khai báo class nhằm mục đích thông báo cho servlet container đăng ký class này là 1 listener (dành cho Servlet 3.0). Nếu quí vị đang sử dụng servlet 2.5 (không sử dụng được @WebListener), sẽ phải add thêm vào web.xml như sau:

§  Các nội dung chúng ta đã cấu hình trong hình trên thể hiện các flow xử lý khi ứng dụng được deploy vào container như sau (code được thể hiện ở phương thức contextInitialized):

·         Trước tiên, chúng ta sẽ lấy context hiện hành của ứng dụng.

·         Sau đó, chúng ta lấy ra vị trí của file log4j.properties thông qua context theo param-name “log4j-config-location” mà chúng ta đã cấu hình trong web.xml.

·         Tiếp theo, chúng ta sẽ tạo đường dẫn hoàn chỉnh đến vị trí của file log4j.properties và truyền vào phương thức configure() của lớp PropertyConfigurator trong thư viện của log4j.

·         Các bước trên, chúng ta đã hoàn tất quá trình cấu hình cho log4j với file log4j.properties.

 

-          Tiếp theo, chúng ta sẽ vận dụng việc ghi log với chức năng Login thực hiện trên ứng dụng web

o   Chúng ta tạo 2 file jsp để tiếp tục việc demo là login.jsp và home.jsp

o   Đầu tiên là file login.jsp

o   Tiếp theo, chúng ta tạo file login.jsp

o   Kế tiếp, chúng ta tạo LoginServlet để xử lý Login:

-          Trong code nêu trên chúng ta đã không xử lý lỗi và để trống phần catch. Đây là vấn đề vô cùng nghiêm trọng trong việc xây dựng ứng dụng vì nó sẽ gây ra vấn đề ứng dụng chạy không biết lỗi là gì và kết quả không biết để tracking và fix bug

-          Do vậy, chúng ta thực hiện ghi log vào mệnh đề catch cùng các dòng code được đánh dấu đỏ như sau:

o   Chúng ta tìm hiểu xem dòng code chúng ta đã thêm vào như sau:

§  Tạo 1 đối tượng Logger với tên class hiện tại là LoginServlet vào getLogger() ở dòng code thứ 22

§  Đặt phương thức ghi log entry với log level và message cần ghi vào log tại vị trí mong muốn, trong demo này thì log sẽ được ghi ở các trường hợp sau (các dòng code 33, 37, 40, và 44):

§  Log sẽ được ghi theo level là warn với message là “User not fill in userID or Password” khi user bỏ trống không điền vào 1 trong 2 field hay cả 2 fields userID và Password.

§  Log sẽ được ghi theo level là info với message “Login success!” khi user login thành công.

§  Log sẽ được ghi theo level là info với message “User not found!” khi thông tin được điền trong field userID hoặc Password không chính xác.

§  Log sẽ được ghi theo level là error với message là thông tin của Exception khi có Exception xảy ra.

-          Bây giờ, chúng ta sẽ thử chạy demo, giao diện khi khởi động project sẽ như sau:

o   Chúng ta sẽ không nhập gì hết mà nhấn login

o   Kiểm tra console

o   Kiểm tra thư mục chúng ta dùng log file

 

o   Bây giờ, chúng ta sẽ thử các trường hợp ghi log khác

4.       Thiết lập đường dẫn động ghi log cho ứng dụng web sử dụng Log4j

-          Hard coding là một trong các anti-pattern mà bất kì lập trình viên nào cũng nên tránh mắc phải, phải tìm cách khắc phục. Việc fix cứng đường dẫn ghi log file khi cấu hình file properties ở trên là một trường hợp hard coding tiêu biểu mặc dù chỉ là demo.

-          Để giải quyết vấn đề này, chúng ta có giải pháp như sau:

·         Tạo một property (gồm một cặp key-value kiểu String như trong Hashtable) với key tên tùy ý và value là đường dẫn tuyệt đối tới thư mục /web như hình dưới nhờ phương thức getRealPath(“/”) của context Scope.

Quí vị có thể tham khảo tại: https://stackoverflow.com/questions/12160639/what-does-servletcontext-getrealpath-mean-and-when-should-i-use-it

·         Code bổ sung được thể hiện như dòng đánh dấu đỏ trong hình bên dưới.

·         Chúng ta trở lại mở file properties để thiết lập đường dẫn động để ghi và lưu log file sử dụng giá trị chúng ta vừa setProperty, khắc phục việc fix cứng đường dẫn lưu file log như đã nói ở trên tại dòng đánh dấu đỏ như hình bên dưới (dòng thứ 10)

 

 

 

 

·         Log file khi này sẽ được tạo và ghi log ở vị trí như trong hình – cụ thể ở đây chính là vị trí ứng dụng được deploy trên server - container

 

-          Để thể hiện rõ việc đọc log trong thực tế, chúng ta sẽ thực hiện deploy ứng dụng này vào trong server tomcat rời

o   Thực hiện start server tomcat rời ngoài IDE

o   Cửa sổ console của server sẽ xuất hiện

o   Chúng ta thực hiện deploy gói war vào thư mục webapps của tomcat container bằng cách copy vào

o   Ứng dụng được thể hiện deploy trên console như sau

o   Trong thư mục webapps, gói war được phát sinh thành thư mục tương ứng

o   Thực hiện chạy ứng dụng

o   Thực hiện các thao tác trong các bước trên để tạo ra log

o   Chúng ta thấy console thể hiện log như sau

o   Chúng ta mở vào trong thư mục webapps/DemoLog4J/WEB-INF,mở file Logfile.log, chúng ta sẽ thấy log được nhận ở trên server tại thời điểm ứng dụng được request time (run-time) như sau

o   Chúng ta undeploy ứng dụng bằng cách xóa thư mục và gói war trong webapps

o   Thực hiện tắt server tomcat bằng lệnh shutdown hay nhấn tổ hợp phím Ctrl + C

 

Chúng ta vừa hoàn tất tìm hiểu về cách thiết lập và tích hợp thư viện Log4j vào 1 project Java Web đơn giản để ghi log. Rất mong bài viết sẽ hữu dụng cho quí vị ghi log ngoài log mặc định chỉ support trong servlet và context scope.

Rất mong quí vị góp ý về nội dung bài viết này vì bài viết chúng tôi sẽ cung cấp cho quí vị các nội dung về cách làm và chia sẻ các tình huống lỗi thường xuất hiện trong quá trình phát triển. Chúng tôi mong muốn quí vị cùng chia sẻ những lỗi và cách khắc phục khi quí vị phát triển ứng dụng hay thực hiện theo các hướng dẫn của bài viết như là một sự chia sẽ chung cho người đọc khác. Hẹn gặp lại quí vị ở các bài viết khác.

 

 

 

Không có nhận xét nào:

Đăng nhận xét