Bootstrap

SpringBoot获取项目日志

目的

对于布署在远端的服务,我们想快速的获取到日志。对于使用了日志服务,也可能因为上报间隔太长,日志不够实时。

所以想通过一些方式,可以不用进入到容器内也可以简单快速获取到日志,而且是实时的日志。目标就是获取最新的n条日志,搜索啥的功能也不需要,这是ES的功能。

思路

1、想办法获取到项目里的所有日志,然后保存在内存中。

2、读取日志文件里的内容。

思路一

对于思路一有三种方法,要全局的获取日志,只要打日志的入口统一就可以了。获取之后把日志放到一个list或queue中,因为日志会无限增长,所以要限制在内存里日志数量。

方法一:统一对打印日志的类进行封装,实现简单,缺点是需要对现有代码进行改造。

方法二:一般日志框架都使用logback,或者其他的框架,它们会有类似全局入口的地方,这就需要深入了解框架,然后定制化的开发。这种方式不用去改造代码,侵入比较小,缺点是不通用,门槛高。

eg:

这是我找到的logback能获取项目日志的全局入口,只要在这里收集日志就可以了(二选一)。侵入到了配置文件,感觉用起来也不是很爽,做不到通用。而且在使用这个的时候,发现jpa不是用了logback,对于sql日志就拿不到了。

 方式三:使用AOP去切打印日志的方法。

上面三种实现都绕不开一个问题,日志的储存。需要限制条数,数据的正确性。如果不加锁,最后可能造成日志的丢失,本来查日志就是为了排查问题,结果日志先来捣乱。加了锁对性能有影响,毕竟日志是很底层的东西,使用频率很高,可能会影响整个系统的性能。而且这段逻辑是和业务一起执行的,需要保证它的正确性和稳定性,不然因为查看日志的这个小需求造成业务崩溃,实属得不偿失。

思路二

这种实现方式就不用去管使用了什么日志框架了,只要你给了我日志文件就可以了。但是还是有方式二说的问题,拿不到sql,因为 jpa打印的日志保存不了到文件。这种方式的优点也是缺点,没有日志文件什么都干不了。另外,新功能和原先的业务没有任何关联,就算有问题也不会影响到业务,没有存储、线程安全问题,唯一有点瑕疵的就是,从文件读的数据都是字符串,只能白纸黑字的展示了,前端要渲染成彩色就很难了。

这种实现方式也没什么好讲的,就文件操作,需要注意的点是,不能从前往后去获取日志,要从后往前读,Java提供了这样的IO操作类。

主要代码:

/**
         * 使用RandomAccessFile,可以倒着读日志的最后n条日志,而不至于从头遍历到末尾
         */
        try (RandomAccessFile file = new RandomAccessFile(logStoreMap.get(logStore), "r")) {
            final long fileLength = file.length();
            long position = fileLength - 1;

            // 把光标定位到文件末尾
            file.seek(position);

            final List<String> logList = new ArrayList<>(size);
            for (int i = 0; i < size; ++i) {

                StringBuilder log = new StringBuilder();
                while (true) {

                    final byte currentByte = file.readByte();
                    final char currentChar = (char) currentByte;

                    log.append(currentChar);
                    position--;
                    file.seek(position);

                    if (currentChar == '\n') {
                        break;
                    }

                    if (position < 0) {
                        break;
                    }

                }

                // 倒着读 内容需要反转
                logList.add(log.reverse().toString());

                if (position < 0) {
                    break;
                }

            }

            // 倒着读 内容需要反转
            Collections.reverse(logList);
            return logList;

        } catch (FileNotFoundException e) {
            return List.of(exAlert, String.format("FileNotFoundException %s %s:", logStore,
                    logStoreMap.get(logStore)), ThrowableUtil.getStackTrace(e));
        } catch (IOException e) {
            return List.of(exAlert,
                    String.format("IOException %s %s", logStore, logStoreMap.get(logStore)),
                    ThrowableUtil.getStackTrace(e));
        } catch (Throwable e) {
            return List.of(exAlert, ThrowableUtil.getStackTrace(e));
        }

源码:qq_41084438 / spingboot-log · GitCode

效果

;