编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

commons-io的FileAlterationMonitor监听文件变化

wxchong 2024-07-22 22:26:51 开源技术 31 ℃ 0 评论

近期有同学反馈日志文件发生切割后最新的日志文件没有被采集,于是一顿追踪。

现场情况:

1、业务的日志文件根据大小进行的切分,约每35分钟左右会有一次切分,最多保留5份,格式类似,server.log,server.log-1,server.log-2,server.log-3,server.log-4,server.log-5;

2、采集agent采用commons-io的FileAlterationMonitor来监听目录文件的变化;

追踪过程:

1、业务的日志文件切分是没有问题的,正常的log4j切分策略;

2、问题怀疑发生在对FileAlterationMonitor的使用上面,于是一顿追踪;

commons-io监听文件变化主要有三个类;

a)FileAlterationMonitor负责起一个线程以设定的频率发起轮询,

public synchronized void start() throws Exception {
        if (running) {
            throw new IllegalStateException("Monitor is already running");
        }
        for (FileAlterationObserver observer : observers) {
            observer.initialize();
        }
        running = true;
        if (threadFactory != null) {
            thread = threadFactory.newThread(this);
        } else {
            thread = new Thread(this);
        }
        thread.start();
    }

public void run() {
        while (running) {
            for (FileAlterationObserver observer : observers) {
                observer.checkAndNotify();
            }
            if (!running) {
                break;
            }
            try {
                Thread.sleep(interval);
            } catch (final InterruptedException ignored) {
            }
        }
    }

b)FileAlterationObserver负责执行真正的对比,主要逻辑是拿要对比的目录下当前的文件列表和上次对比后在内存记录的结果进行对比,这里有几个注意事项;

一、只是对比目录下的文件数量和名称(本文的问题就在这里,因为切分后,文件数量和每个文件的名称都没变,所以切分未识别出来)

二、这里的对比是递归进行的,如果目录下面不断包含子目录或者文件数量很大,性能可能会有问题;

private void checkAndNotify(FileEntry parent, FileEntry[] previous, File[] files) {
        int c = 0;
        FileEntry[] current = files.length > 0 ? new FileEntry[files.length] : FileEntry.EMPTY_ENTRIES;
        for (FileEntry entry : previous) {
            while (c < files.length && comparator.compare(entry.getFile(), files[c]) > 0) {
                current[c] = createFileEntry(parent, files[c]);
                doCreate(current[c]);
                c++;
            }
            if (c < files.length && comparator.compare(entry.getFile(), files[c]) == 0) {
                doMatch(entry, files[c]);
                checkAndNotify(entry, entry.getChildren(), listFiles(files[c]));
                current[c] = entry;
                c++;
            } else {
                checkAndNotify(entry, entry.getChildren(), FileUtils.EMPTY_FILE_ARRAY);
                doDelete(entry);
            }
        }
        for (; c < files.length; c++) {
            current[c] = createFileEntry(parent, files[c]);
            doCreate(current[c]);
        }
        parent.setChildren(current);
    }

c)FileAlterationListener,b中对比出来的文件变化,包括文件的增删改会通过这里的事件回调出去;

我们知道了本文的问题发生在上面提到的注意事项一,怎么解决呢?

方案1:业务方改成切分后文件名称递增;

方案2:自主实现文件变更检测机制,结合inode来对比,不仅仅通过文件名来对比;

方案3:采用Linux inotify机制;

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表