Chào mọi người. Dạo này bận việc quá, tranh thủ mãi mới ngồi viết bài được. Hôm nay mình sẽ chia sẻ kinh nghiệm của mình liên quan đến vấn đề ghi log trong phát triển phần mềm.

Ghi log là gì?
Nói đến ghi log thì chắc đã nhiều bạn biết đây là một công việc lưu vết lại quá trình xử lý của 1 đoạn code/chức năng/ứng dụng, hoặc ghi lại lỗi xảy ra (nếu có)
Mọi hệ thống lớn như hệ quản trị cơ sở dữ liệu đều ghi log chi tiết user nào execute query gì trên session nào vào thời gian nào. Hay Microsoft, web browser, adobe,… đều có chức năng ghi lại log và hiển thị cửa sổ Send report cho nhà phát triển khi phần mềm có lỗi xảy ra.

Kết quả hình ảnh cho send report window

Ghi log để làm gì?
Vậy lưu vết xong thì để làm gì? Tất nhiên là phục vụ việc truy vết rồi.
Nếu bạn ghi log lỗi thì khi chương trình có lỗi bạn có thể nhìn được lỗi gì, ở đoạn code nào và dễ dàng trong việc tìm phương án xử lý. Nhiều trường hợp chương trình gặp lỗi trên môi trường production mà không thể tái hiện lại được, đó là khi cần đến log để tìm nguyên nhân.
Nếu bạn ghi log sử dụng ứng dụng, bạn sẽ biết user nào vào truy cập vào ứng dụng và thao tác gì, từ đó tìm được thủ phạm của những vụ phá hoại.
Nếu ghi log ở các đoạn code phức tạp, các tiến trình chạy ngầm, bạn sẽ biết được trạng thái của tiến trình đó đang chạy như thế nào, biết được tốc độ xử lý của các nghiệp vụ phức tạp, có cơ sở để tìm ra các đoạn code gây cao tải cho hệ thống.
Và rất nhiều lợi ích khác

Có những cách ghi log nào?
– Print ra màn hình 😀
– Ghi ra file lưu trên ổ cứng
– Kết nối ftp đến server khác để lưu file và truyền file sang server lưu log, hoặc gửi qua service, email đến nhà phát triển.
– Insert log vào 1 bảng trong cơ sở dữ liệu
– …

Ghi log bằng gì?
– Dùng lệnh print ra màn hình
– Dùng thư viện log4j, slf4j trong java
– Insert log vào cơ sở dữ liệu bằng cách execute lệnh SQL hoặc dùng ORM như Hibernate,…
– Tự xây dựng module ghi log của riêng mình 😀

Ghi log những cái gì?
Không phải ghi nhiều quá cũng tốt, ghi nhiều quá sẽ làm thừa log khó kiểm soát và trace log, tốn dung lượng để lưu trữ, hoặc làm trôi đi các log cần thiết
Cũng không thể ghi quá ít dẫn đến việc không có log để xử lý
Để ghi đủ log thì mình đưa ra một số vị trí như sau:
– Trong các khối catch exception, cần phải ghi log để tìm ra được vị trí gây lỗi trong ứng dụng khi có vấn đề xảy ra.
– Các chức năng sử dụng nhiều, có khả năng gây cao tải hệ thống, các chức năng quan trọng cần ghi log để giám sát thường xuyên, đảm bảo hệ thống vẫn đang chạy ổn định.
– Với các tiến trình chạy ngầm, tối thiểu cần phải ghi log mỗi khi start và finish kèm theo tổng thời gian xử lý để biết được tiến trình có chạy đúng lịch đã đặt hay không, tốc độ xử lý nhanh hay chậm. Với các tiến trình lớn chạy lâu có nhiều bước thì cần ghi log mỗi khi bắt đầu hoặc hoàn thành 1 bước để giám sát được tiến trình đang xử lý ở bước nào, gặp lỗi hoặc rollback ở bước nào. Nếu cần thiết thì có thể ghi thêm thông tin tình trạng server hiện tại như Ram, CPU, Disk IO,… để có cơ sở đánh giá nguy cơ cao tải hệ thống, có phương án sắp lịch lại tiến trình hạn chế việc nhiều tiến trình cùng chạy đồng thời.
– Trong các nghiệp vụ phức tạp có nhiều bước xử lý cũng nên ghi log từng bước tương tự tiến trình. Hay các đoạn code tiềm ẩn rủi ro ví dụ như chức năng không quá quan trọng đang phải xử lý tạm thời do chưa tìm được phương án tối ưu, hoặc thời gian release quá gấp thì nên ghi log giám sát logic có bất thường hay không để xử lý tức thời.
– Log khi giao tiếp với hệ thống khác. Ở đây có 2 chiều giao tiếp đó là các api/service public cho hệ thống khác kết nối vào, hoặc các đoạn gọi sang api/service của hệ thống khác, hoặc bất kỳ kết nối nào khác phải triển khai bằng viết code. Tất cả đều cần ghi log gồm một số thông tin cơ bản như: Link Api, path/method xử lý, bản tin request, bản tin response, thời gian xử lý. Và tốt hơn hết là nên ghi log này vào bảng trong cơ sở dữ liệu để thuận tiện nhất khi cần trace log. Bởi vì việc tích hợp giữa các hệ thống thường sẽ xảy ra rất nhiều vấn đề, nếu không có log cụ thể sẽ khó xác định được lỗi do bên nào, dẫn đến tình trạng đổ trách nhiệm cho nhau và không giải quyết được vấn đề.
– Ngoài ra một số hệ thống hoặc chức năng quan trọng, cần phải ghi log cụ thể về tác động thay đổi dữ liệu trong cơ sở dữ liệu. Insert/update/delete/select đến bản ghi nào, dữ liệu trước và sau khi thay đổi. Để kiểm soát tác động vào dữ liệu và rollback dữ liệu khi cần thiết.
– Hay trường hợp gặp lỗi trên server, không tái hiện được trên local, cũng không debug được trên server thì chỉ có bổ sung log vào các vị trí nghi ngờ để tìm lỗi

Ghi log như thế nào?
Khi ghi log cần phải đảm bảo được một số nguyên tắc như sau:
Nếu quá trình ghi log xảy ra lỗi thì ứng dụng vẫn phải chạy bình thường. Mặc dù phần trên mình đề cập đến rất nhiều vấn đề thể hiện tầm quan trọng của việc ghi log, nhưng mục đích chính vẫn chỉ giúp ích cho người vận hành hệ thống, còn đối với end-user thì chả có ý nghĩa gì. Vậy nên nếu ghi log lỗi mà làm lỗi cả nghiệp vụ chính nên tốt nhất đừng ghi log.
Thời gian xử lý ghi log không được làm ảnh hưởng đến thời gian xử lý nghiệp vụ. Dù ghi log ra file hay insert vào cơ sở dữ liệu hoặc lưu vào bất kỳ đâu thì cũng sẽ tốn 1 thời gian nào đó để xử lý, nhưng dù có tốn vài phút hay chỉ vài mili giây thì cũng không nên để nó làm ảnh hưởng đến tổng thời gian xử lý của nghiệp vụ. Vì khi gặp phải nghiệp vụ lớn giao dịch liên tục thì cái giá phải trả cho thời gian ghi log nhân lên không hề nhỏ
Từ các nguyên tắc trên mình có một số lời khuyên tương ứng khi ghi log:
Luôn catch mọi exception của các đoạn code ghi log khi nhúng vào nghiệp vụ chức năng của phần mềm, đảm bảo không có lỗi nào có thể throw từ xử lý ghi log ra nghiệp vụ chính.
Ghi log bất đồng bộ bằng 1 tiến trình khác, đơn giản nhất là chạy nó ở 1 thread riêng.
+ Tránh dùng lệnh System.out.print (hoặc tương tự) để in log ra màn hình vì in ra màn hình là một thao tác thực hiện tuần tự rất chậm
+ Tránh dùng e.printStackTrace() để in log ra màn hình, cũng vì lý do trên
+ Nên sử dụng các thư viện ghi log bất đồng bộ như log4j trong java. Nhìn qua thì log4j vẫn chỉ là 1 lệnh logger.infor("Nội dung")nhưng thực chất bên trong đó là cả 1 hệ thống xử lý. Nội dung cần ghi log sẽ được submit vào 1 hàng đợi, bên cạnh đó sẽ có 1 tiến trình chạy ngầm quét hàng đợi để lấy nội dung thực hiện việc ghi log, như vậy đã đảm bảo được việc ghi log không ảnh hưởng đến thời gian xử lý nghiệp vụ.

Giám sát log?
Giờ khi mà phần mềm đã có log thì việc tiếp theo là sử dụng dữ liệu log đó cho nhiệm vụ giám sát hệ thống. Có rất nhiều cách giám sát hệ thống qua log như
Mở file log bằng tay, gõ lệnh select bảng log bằng tay, và đọc thông tin log bằng mắt 😀 Việc này đòi hỏi người giám sát phải có kiến thức về phần mềm và cơ sở dữ liệu cũng như nắm quyền truy cập vào các tài nguyên kể trên để xem thông tin log. Cách này khá thông dụng trong môi trường development vì khả năng đọc log tức thời, gọn nhẹ nhanh chóng.
– Còn trên môi trường production, người giám sát có thể không có kiến thức về phần mềm, họ chỉ ngồi trực hệ thống và báo cho đội kỹ thuật khi có sự cố. Vậy nên lúc này phần mềm cần có thêm chức năng giám sát hệ thống một cách trực quan bằng hình ảnh, màu sắc, dữ liệu nhiều thông tin cần được hiển thị dưới dạng bảng có hàng và cột tường minh. Để làm được việc này cũng có nhiều cách xử lý
+ Tích hợp các hệ thống giám sát log có sẵn như JMX Remote, Java Profiler, Nagios, Spring Boot Actuator hay một bộ hoàn chỉnh như Logstash (thu thập dữ liệu log realtime) + ElasticSearch/Solr (phân tích dữ liệu log, full text search nhanh chóng vào tối ưu) + Kibana (giao diện hiển thị thông tin dữ liệu log 1 cách trực quan từ ElasticSearch)

Kết quả hình ảnh cho kibana elasticsearch logstash

+ Tự xây dựng một tool (đơn giản hay phức tạp tùy nhu cầu) để đọc dữ liệu file log, phân tích và hiển thị cảnh báo lên giao diện 🙂 Cách này thì không khuyên dùng vì rất nhiều hệ thống có sẵn kể trên đã làm rất tốt, khả năng tương thích cao mà lại miễn phí 😀

Qua bài này các bạn đã nắm được cơ bản về tầm quan trọng của việc ghi log trong phát triển phần mềm, và một số nguyên tắc cần nắm được khi ghi log. Ở bài sau mình sẽ trình bày các ví dụ cụ thể để tích hợp được module ghi log tiêu chuẩn cơ bản nhất vào phần mềm.

[Java] Phần 13 – Log 2: Tích hợp log4j vào phần mềm

[Java] Phần 14 – Log 3: Ghi log bất đồng bộ vào Database

2 Replies to “[Java] Phần 12 – Log 1: Tầm quan trọng của ghi log trong phát triển phần mềm”

Bình luận