使用自动任务自动检测磁盘空间并清除旧日志

场景:项目每天都会产生大量的日志信息并占据服务器大量空间,旧的日志并没有利用价值,所以我们需要定时清除旧日志,保证磁盘不会占满影响日志正常输出。

程序代码:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author Miku
 * @Date 2024/09/04 14:54
 * @Description 定时自动清理磁盘
 * @Version 1.0
 */
@Component
public class FileCleanerScheduled {

    private static final Logger log = LoggerFactory.getLogger(FileCleanerScheduled.class);

    // todo 如果可以的话,路径放配置文件更好
    private static final String CLEAN_FILE_CONFIG_PATH = "/home/miku/config/clean_file_config.txt";
    // 磁盘利用率超过80%则清理
    private double thresholdDisk;
    // 监控的磁盘路径
    private String diskPath;
    // 删除指定日期之前的日志数据
    private String targetDate;
    // 日期格式
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    // 每周日的午夜执行
    @Scheduled(cron = "0 0 0 * * SUN")
    public void runTask() {
        try {
            loadConfig();
            checkConfig();

            File disk = new File(diskPath);
            long totalSpace = disk.getTotalSpace();
            long freeSpace = disk.getFreeSpace();
            // 磁盘利用率
            double diskUsageRatio = (double) (totalSpace - freeSpace) / totalSpace;
            if (diskUsageRatio > thresholdDisk) {
                Date thresholdDate;
                try {
                    thresholdDate = DATE_FORMAT.parse(targetDate);
                } catch (ParseException e) {
                    throw new IOException("日期格式不正确", e);
                }
                cleanOldFiles(disk, thresholdDate);
            }
        } catch (Exception e) {
            log.error("执行自动清理磁盘定时任务出错:{}", e.getMessage());
        }
    }

    /**
     * 检查配置文件是否有误
     */
    private void checkConfig() {
        File file = new File(diskPath);
        if (!file.isDirectory()) {
            log.error("配置的磁盘路径无效:{}", diskPath);
            throw new RuntimeException("无效的磁盘路径");
        }

        if (thresholdDisk < 0 || thresholdDisk > 1) {
            log.error("磁盘利用率阈值无效:{}", thresholdDisk);
            throw new RuntimeException("无效的磁盘利用率阈值");
        }

        try {
            DATE_FORMAT.parse(targetDate);
        } catch (ParseException e) {
            log.error("日期格式无效:{}", targetDate);
            throw new RuntimeException("无效的日期格式");
        }
    }

    /**
     * 加载配置文件
     */
    private void loadConfig() {
        File file = new File(CLEAN_FILE_CONFIG_PATH);
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // 忽略以 # 开头的注释行
                if (line.trim().startsWith("#") || line.trim().isEmpty()) {
                    continue;
                }

                String[] parts = line.split("=", 2);
                if (parts.length == 2) {
                    switch (parts[0].trim()) {
                        case "thresholdDisk":
                            thresholdDisk = Double.parseDouble(parts[1].trim());
                            break;
                        case "diskPath":
                            diskPath = parts[1].trim();
                            break;
                        case "targetDate":
                            targetDate = parts[1].trim();
                            break;
                        default:
                            log.error("未知配置或错误配置:{}", parts[0]);
                    }
                }
            }
        } catch (Exception e) {
            log.error("配置文件读取失败:{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 清理旧文件
     *
     * @param disk          清理的目录文件
     * @param thresholdDate 门槛日期,在此日期之前全部清理
     */
    private void cleanOldFiles(File disk, Date thresholdDate) {
        File[] files = disk.listFiles();
        if (files == null) {
            return;
        }
        for (File file : files) {
            if (file.isFile()) {
                String fileName = file.getName();
                String filePath = file.getParent() + File.separator + fileName;
                // 从文件名中取出日期
                String dateString = getDateByFileName(fileName);
                try {
                    Date fileDate = DATE_FORMAT.parse(dateString);
                    if (fileDate.before(thresholdDate)) {
                        Optional.of(file.delete()).ifPresentOrElse(delete -> log.info("已删除文件:{}", filePath), () -> log.error("删除文件失败:{}", filePath));
                    }
                } catch (ParseException e) {
                    log.info("该文件名不存在日期:{}", filePath);
                }
            } else if (file.isDirectory()) {
                cleanOldFiles(file, thresholdDate);
            }
        }
    }

    /**
     * 从文件名中通过正则获取日期
     *
     * @param fileName 文件名
     * @return 日期或""
     */
    private String getDateByFileName(String fileName) {
        String regex = "\\d{4}-\\d{2}-\\d{2}";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(fileName);
        return matcher.find() ? matcher.group() : "";
    }
}

clean_file_config.txt文件

# 磁盘利用率阈值,超过该值将触发清理操作,范围为0.0到1.0,例如:0.80
thresholdDisk = 0.80

# 需要监控并处理的磁盘路径,例如: E:\ip 或 /home/miku/log
diskPath = /home/miku/log

# 将会自动清理该日期之前的日志,格式为 yyyy-MM-dd,例如2024-07-01
targetDate = 2024-07-01
  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨崇M柒

网络乞讨一下,嘿嘿嘿~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值