package com.zsElectric.boot.system.quartz; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.stream.Stream; /** * 日志文件清理定时任务 * 定期清理超过指定天数的历史日志文件 * * @author zsElectric * @since 2026-01-06 */ @Slf4j @Component public class LogCleanupJob { @Value("${spring.application.name:zsElectric-boot}") private String appName; /** * 日志保留天数 */ private static final int LOG_RETENTION_DAYS = 30; /** * 日志目录 */ private static final String LOG_BASE_PATH = "/logs"; /** * 每天凌晨3点执行一次 * 清理超过30天的日志文件 */ @Scheduled(cron = "0 0 3 * * ?") public void cleanupExpiredLogs() { log.info("开始执行日志清理任务,清理{}天前的日志文件", LOG_RETENTION_DAYS); Path logDir = Paths.get(LOG_BASE_PATH, appName); if (!Files.exists(logDir)) { log.warn("日志目录不存在: {}", logDir); return; } Instant cutoffTime = Instant.now().minus(LOG_RETENTION_DAYS, ChronoUnit.DAYS); int deletedCount = 0; int failedCount = 0; try (Stream files = Files.list(logDir)) { for (Path file : (Iterable) files::iterator) { // 只处理 .log 文件,跳过当前正在写入的日志文件 String fileName = file.getFileName().toString(); if (!fileName.endsWith(".log") || fileName.equals("log.log")) { continue; } try { BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class); Instant lastModified = attrs.lastModifiedTime().toInstant(); if (lastModified.isBefore(cutoffTime)) { Files.delete(file); deletedCount++; log.debug("已删除过期日志文件: {}", fileName); } } catch (IOException e) { failedCount++; log.error("删除日志文件失败: {}", fileName, e); } } } catch (IOException e) { log.error("读取日志目录失败: {}", logDir, e); } log.info("日志清理任务执行完成,成功删除{}个文件,失败{}个", deletedCount, failedCount); } }