+4

Tự động tạo mới thư mục theo định dạng ngày tháng năm sau mỗi lần sinh log với logback Spring Boot

Trong bài viết này, tôi sẽ hướng dẫn các bạn sử dụng logback trong spring boot và tạo thư mục chứa log file theo định dạng "yyyy-MM-dd" và "yyyy-MM-dd hhmmss":

Công cụ và thư viện được sử dụng trong bài viết:

  • Spring tool suite 4
  • Spring boot 2.7.3
  • Maven 3
  • Java 8
  • Logback 1.2.11

1. Cấu trúc thư mục:

image.png

2. Nội dung file pom:

Mặc định, trong spring boot khi bạn add "spring-boot-starter-web" -> logback sẽ được bao gồm: image.png

3. Cấu hình logback:

Spring boot sẽ tự động đọc logback config theo những tên bên dưới:

  • logback-spring.xml
  • logback.xml

Trong bài viết này tôi sử dụng "logback-spring.xml":

<?xml version="1.0" encoding="UTF-8"?>

<configuration>
    
	<!--<timestamp key="byDate" datePattern="yyyy-MM-dd" /> -->
    
	<timestamp key="bySecond" datePattern="yyyy-MM-dd'T'HHmmss" timeReference="contextBirth"/> 
    
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
            </Pattern>
        </layout>
    </appender>
    
	<appender name="roleSiftingAppender" class="ch.qos.logback.classic.sift.SiftingAppender">
	<discriminator>
        <key>folderDate</key>
        <defaultValue>${bySecond}</defaultValue>
    </discriminator>
    <sift>
    <appender name="RollingFile"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${LOG_PATH}/${folderDate}/service-log.log</file>
        
        <encoder
            class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n</Pattern>
        </encoder>

        <rollingPolicy
            class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- rollover daily and when the file reaches x MegaBytes -->
            <fileNamePattern>${LOG_PATH}/${folderDate}/archived/service-log-%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>50MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
    </appender>
    </sift>
    </appender>

		<!-- LOG everything at INFO level -->
		<root level="info">
		  <appender-ref ref="roleSiftingAppender" />
          <appender-ref ref="Console" />
		</root>
		<!-- LOG "com.example.logback.*" at TRACE level -->
		<logger name="com.example.logback" level="trace" additivity="false">
			<appender-ref ref="roleSiftingAppender" />
			<appender-ref ref="Console" />
		</logger>
	
</configuration>

Tôi sẽ phân tích một vài biến giá trị trong log file config:

  • Biến giá trị "byDate" -> tạo ra folder chứa log file với format "yyyy-MM-dd"
  • Biến giá trị "bySecond" -> tạo ra folder chứa log file với format "yyyy-MM-dd'T'HHmmss"
  • Biến giá trị "${LOG_PATH}" -> mặc định giá trị sẽ được lấy từ application.yml hoặc application.properties:

image.png

Tiếp theo tôi sẽ start service:

  • Service started success:

image.png

  • Kiểm tra thư mục chứa log file:

image.png

image.png

=> Thư mục chứa log và log file được tạo thành công.

Tiếp theo tôi sẽ tạo một controller và khai báo mapping để kiểm tra xem sau khi thực hiện một hành động(truy cập đường dẫn được khai báo trong controller) -> folder chứa log có tự động sinh ra 1 folder mới hay không?

Tôi tạo 1 class như bên dưới:

image.png

Tôi truy cập vào đường dẫn vừa được tạo trong controller và kết quả:

image.png

Kiểm tra thư mục chứa log:

image.png

Kiểm tra nội dung log file:

image.png

Các bạn thấy có một vấn đề ở đây, thư mục chứa log không được tự động tạo mới sau khi thực hiện một hành động, hệ thống sẽ tự động cập nhật nội dung log file đến thự mục chứa log cũ đã được tạo trước đó trong lần start service đầu tiên. Để hệ thống tạo ra 1 thư mục chứa log file mới thì cần phải restart service. Nguyên nhân là do trong lần start service đầu tiên hệ thống ghi nhớ đường dẫn chứa log file và trong những lần sau log sinh ra hệ thống không tự động cập nhật lại theo thời gian thực.

Tới đây tôi sẽ giải quyết vấn đề bằng việc sử dụng SiftingAppender trong logback:

    <appender name="roleSiftingAppender" class="ch.qos.logback.classic.sift.SiftingAppender">
	<discriminator>
        <key>folderDate</key>
        <defaultValue>${bySecond}</defaultValue>
    </discriminator>
    <sift>
    <appender name="RollingFile"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${LOG_PATH}/${folderDate}/service-log.log</file>
        
        <encoder
            class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n</Pattern>
        </encoder>

        <rollingPolicy
            class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- rollover daily and when the file reaches x MegaBytes -->
            <fileNamePattern>${LOG_PATH}/${folderDate}/archived/service-log-%d{yyyy-MM-dd}.%i.log
            </fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>50MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
    </appender>
    </sift>
    </appender>

Trong tag <discriminator> có 2 tag:

  • Tag <key> chứa tên biến, tại đây tôi để tên biến là "folderDate"
  • Tag <defaultValue> chứa giá trị tên thư mục chứa log. chúng ta cần cập nhật giá trị này theo thời gian thực mỗi lần thực hiện 1 hành động

Đế cập nhật giá trị tag <defaultValue> tôi sẽ tạo thêm 1 class implement Filter, mục đích là để bắt lấy các hành động.

image.png

Trong class filter tôi sử dụng hàm "doFilter()" để bắt các hành động. Trong hàm "doFilter()" tôi sẽ lấy giá trị thời gian thực và dùng "MDC" để update lại giá trị cho tên thư mục chứa log với tên biến giá trị là "${folderDate}"

Khai báo filter class này trong class khởi động "LogBackdemoApplication":

image.png

Tôi sẽ restart service và kiểm tra lại:

  • Cho lần đầu start service:

image.png

image.png

  • Cho lần thứ 2 khi thử truy cập đường dẫn khai báo trong controller:

image.png

image.png

image.png

Như vậy, vấn đề đã được giải quyết. Với cách này có thể tạo thư mục chứa log theo thời gian thực. Trong thực tế có thể áp dụng phương pháp này để mỗi ngày có thể tự tạo thư mục chứa log theo thời gian thực, nếu muốn tạo thư mục chứa log theo định dạng "yyyy-MM-dd" chỉ cần sử dụng biến giá trị "byDate"thayvıˋ"{byDate}" thay vì "{bySecond}".


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí