Log là gì?

Log là quá trình ghi lại những thông tin được thông báo, lưu lại quá trình hoạt động của một ứng dụng. Mục đích là có thể xem lại các thông tin hoạt động của ứng dụng trong quá khứ như debug khi có lỗi xảy ra, check health, xem infor, error, warning, ...

Có nhiều cách để ghi log: có thể lưu vào file, console, database, ...

Các thành phần

Hình bên dưới đại diện cho các thành phần cốt lõi và luồng điều khiển của API ghi nhật ký trong Java

hình ảnh_2024-12-10_231309725.png
Application

Là nguồn gốc tạo ra các thông điệp log. Trong ứng dụng bạn tạo ra các Logger (như info(), error(), debug() ) để ghi lại các sự kiện hoặc trạng thái của hệ thống.


Logger

Là thành phần trung tâm của hệ thống logging. Nó nhận các thông điệp log từ ứng dụng và chuyển chúng tới các Handler.

Nhiệm vụ:

  • Xác định cấp độ (Level): Logger kiểm tra cấp độ log của thông điệp( INFO, WARNING, SEVERE, ...) so với cấu hình của nó. Nếu thông điệp không đạt mức ưu tiên, nó sẽ bị bỏ qua.
  • Gửi đến Handler: Logger chuyển thông điệp đến các Handler tương ứng.
  • Áp dụng bộ lọc (Filter): Logger có thể có các bộ lọc để loạ bỏ những log không cần thiết.

Ví dụ:

Logger logger = Logger.getLogger("newLoggerName");
logger.setLevel(Level.WARNING); // Chỉ log từ WARNING trở lên
logger.info("This is an INFO message.");   // Bị bỏ qua
logger.warning("This is a WARNING message."); // Được xử lý
logger.severe("This is a SEVERE message.");   // Được xử lý
Phương thức getLogger() của lớp Logger được sử dụng để tìm hoặc tạo mới Logger. Đối số chuỗi khai báo tên của trình ghi nhật ký.

Ở đây, điều này tạo ra một đối tượng Logger mới hoặc trả về một đối tượng hiện có Logger cùng tên.

Đó là một quy ước để định nghĩa một Logger sau lớp hiện tại đang sử dụng class.getName()

Logger logger = Logger.getLogger(MyClass.class.getName());
Mỗi loại Logger có một mức khai báo tầm quan trọng của thông báo nhật ký. Có 7 cấp độ nhật ký cơ bản:
  • SEVERE: (1000)thất bại nghiêm trọng
  • WARNING: (900)thông báo cảnh báo, một vấn đề tiềm ẩn
  • INFO: (800)thông tin thời gian chạy chung
  • CONFIG: (700)thông tin cấu hình
  • FINE: (500)thông tin chung về nhà phát triển (theo dõi thông báo)
  • FINER: (400)thông tin chi tiết về nhà phát triển (thông báo theo dõi)
  • FINEST: (300)thông tin nhà phát triển rất chi tiết (theo dõi thông báo)
  • OFF: tắt ghi nhật ký cho tất cả các cấp (không ghi gì)
  • ALL: bật ghi nhật ký cho tất cả các cấp (nắm bắt mọi thứ)

Mỗi cấp độ nhật ký có một giá trị số nguyên xác định mức độ nghiêm trọng của chúng ngoại trừ hai cấp độ nhật ký đặc biệt OFF và ALL


Handler

Handler (trong Java Util Logging) hoặc Appender (trong Logback/Log4j) chịu trách nhiệm xử lý thông điệp log và quyết định nơi chúng sẽ được gửi đến (console, file, database, hoặc hệ thống bên ngoài).

Một Logger có thể có nhiều Handler.

Nhiệm vụ:

  • Áp dụng thêm bộ lọc (Filter): Mỗi Handler có thể áp dụng bộ lọc riêng để quyết định thông điệp log nào sẽ được xử lý.
  • Định dạng log (Formatter): Handler sử dụng Formatter để định dạng thông điệp log theo mẫu mong muốn trước khi gửi.
  • Gửi log đến hệ thống đích: Handler quyết định nơi gửi log, chẳng hạn như Consoler(gửi log đến màn hình console), File(ghi log vào file)

Filter

Bộ lọc được sử dụng để kiểm soát những log nào sẽ được xử lý ở cả Logger và Handler.

Filter giúp giảm bớt những thông điệp log không cần thiết, tối ưu hóa hiệu suất.


Formatter

Formatter định dạng thông điệp log thành chuỗi văn bản dễ đọc trước khi được gửi đến hệ thống đích.

Bạn có thể tùy chỉnh định dạng để bao gồm: thời gian (timestamp), cấp độ (level), tên logger (logger name), thông điệp (message)


External System

Là bất kỳ hệ thống bên ngoài nào nhận, lưu trữ, hoặc xử lý các thông điệp nhật ký từ ứng dụng. Đây là nơi các log được gửi đến sau khi đã được xử lý qua Logger và Handler.

Cách sử dụng

- Sử dụng Maven thêm phần phụ thuộc này vào file pom.xml
<dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.13</version>
</dependency>
- Logger
public class EmployeeDAO {
    private static final Logger logger = LoggerFactory.getLogger(EmployeeDAO.class);

    public List<Employee> listEmployees() {
        try (Session session = DatabaseUtil.getSessionFactory().openSession()) {
            logger.info("Fetching all employees...");
            return session.createQuery("from Employee", Employee.class).list();
        } catch (Exception e) {
            logger.error("Error fetching employees: {}", e.getMessage(), e);
            return null;
        }
    }
}
- Appender
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
//Appender này ghi log ra console (terminal)
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
//Appender này ghi log vào file và hỗ trợ tính năng "Rolling" (tự động xoay vòng file log theo thời gian)
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/application-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="STDOUT" ></appender-ref>
        <appender-ref ref="FILE" ></appender-ref>
    </root>
</configuration>
- Sau khi chạy chương trình, refesh lại project ta sẽ thấy file log được tạo ra trong project
hình ảnh_2024-12-11_003514652.png