内容简介:深入参合logback
项目中通过slf4j桥接到logback进行日志记录。出于可靠性考虑,需要监控日志文件大小,防止因为日志文件过大导致系统不可用。
从slf4j到logback
平时我们在获取日志的logger对象的时候,都会通过 LoggerFactory
对象,但是现在我们要获取的是 ILoggerFactory
对象:
ILoggerFactory iLoggerFactory = LoggerFactory.getILoggerFactory();
如果当前slf4j是桥接到logback的,这个 iLoggerFactory
的最终实现会是 ch.qos.logback.classic.LoggerContext
对象。这样我们就获取到了logback的上下文信息。
获取logback appender
通过logback的 LoggerContext
对象,我们可以先获取到logback所有的logger,进而获取到这些logger对应的所有appender。
LoggerContext lc = (LoggerContext)iLoggerFactory; List<Logger> loggers = lc.getLoggerList(); FileAppender<ILoggingEvent> fileAppender = null; for (Logger logger : loggers) { Iterator<Appender<ILoggingEvent>> appenderIterator = logger.iteratorForAppenders(); while (appenderIterator.hasNext()) { Appender<ILoggingEvent> appender = appenderIterator.next(); if (appender instanceof FileAppender) { fileAppender = (FileAppender<ILoggingEvent>) appender; break; } } if (fileAppender != null) { break; } }
由于我们的目标是获取日志文件,因此我们只关注 FileAppender
对象。
日志文件
已经获取到了 FileAppender
之后,就可以获取这个appender写入的文件路径。
String fileName = fileAppender.getFile();
事实上,大部分时候我们不会直接使用 FileAppender
,而是会使用 RollingFileAppender
。不论是哪个对象,我们都只能获取到当前正在使用的日志文件,无法再获取到之前回卷的日志文件。
关于 RollingFileAppender
获取日志文件之外,还有一个需求是能够删除日志文件。最初的设想是能够手动触发 RollingFileAppender
的回卷操作,这样可以直接把所有带有特定格式的日志文件直接删除。 RollingFileAppender
类中实际也包含了 rollover()
方法。但是直接调用的时候,可能抛出异常。
查看异常栈之后发现,回卷之前, RollingPolicy
需要计算当前文件回卷之后的文件名,如果回卷文件名格式中包含了index(%i)的时候,会因为第一次没有初始化而导致失败。因此最好不要直接调用该方法强制回卷文件。
logback的单元测试(强制同步写入)
作为一个日志框架,IO性能非常重要,异步写入成为了标配。但是在单元测试中,我们没有办法等待缓冲区写入硬盘,极有可能导致对日志文件的断言失败。
为了能够正常进行单元测试,需要实现一个同步写入的appender,它会创建一个每次写日志都执行sync操作的output stream。
public class ImmediateFileAppender<E> extends RollingFileAppender<E> { @Override public void openFile(String file_name) throws IOException { synchronized (lock) { File file = new File(file_name); boolean result = FileUtil.createMissingParentDirectories(file); if (!result) { addError("Failed to create parent directories for [" + file.getAbsolutePath() + "]"); } ImmediateResilientFileOutputStream resilientFos = new ImmediateResilientFileOutputStream(file, append); setOutputStream(resilientFos); } } @Override protected void writeOut(E event) throws IOException { super.writeOut(event); } }
这个类主要作用是重写打开文件,将文件输出流设置成自定义的 ImmediateResilientFileOutputStream
。下面是这个类的实现:
public class ImmediateResilientFileOutputStream extends OutputStream { protected FileOutputStream os; public ImmediateResilientFileOutputStream(File file, boolean append) throws FileNotFoundException { os = new FileOutputStream(file, append); } @Override public void write(int b) throws IOException { os.write(b); } @Override public void flush() throws IOException { if (os != null) { try { os.flush(); os.getFD().sync(); // 这里强制进行sync操作 } catch (IOException e) { // ignore } } } }
和默认实现的主要差别,就是在 FileOutputStream
刷新之后,再执行一次 sync
操作,确保缓冲区同步到磁盘中。
最后,测试用的logback-test.xml中,需要将以前的RollingFileAppender改成这个类。并且确保immediateFlush设置为true。
注意:因为每次写入都强制同步,千万不要用到生产环境中~
以上所述就是小编给大家介绍的《深入参合logback》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【1】JavaScript 基础深入——数据类型深入理解与总结
- 深入理解 Java 函数式编程,第 5 部分: 深入解析 Monad
- 深入理解 HTTPS
- 深入理解 HTTPS
- 深入浅出Disruptor
- 深入了解 JSONP
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。