logback的FileAppender文件追加模式和冲突检测解读
更新时间:2023年10月30日 10:02:11 作者:codecraft
这篇文章主要为大家介绍了logback的FileAppender文件追加模式和冲突检测解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
序
本文主要研究一下logback的FileAppender
FileAppender
ch/qos/logback/core/FileAppender.java
public class FileAppender<E> extends OutputStreamAppender<E> { public static final long DEFAULT_BUFFER_SIZE = 8192; static protected String COLLISION_WITH_EARLIER_APPENDER_URL = CODES_URL + "#earlier_fa_collision"; /** * Append to or truncate the file? The default value for this variable is * <code>true</code>, meaning that by default a <code>FileAppender</code> will * append to an existing file and not truncate it. */ protected boolean append = true; /** * The name of the active log file. */ protected String fileName = null; private boolean prudent = false; private FileSize bufferSize = new FileSize(DEFAULT_BUFFER_SIZE); //...... }
FileAppender继承了OutputStreamAppender,它定义了append、prudent、bufferSize属性
start
public void start() { int errors = 0; if (getFile() != null) { addInfo("File property is set to [" + fileName + "]"); if (prudent) { if (!isAppend()) { setAppend(true); addWarn("Setting \"Append\" property to true on account of \"Prudent\" mode"); } } if (checkForFileCollisionInPreviousFileAppenders()) { addError("Collisions detected with FileAppender/RollingAppender instances defined earlier. Aborting."); addError(MORE_INFO_PREFIX + COLLISION_WITH_EARLIER_APPENDER_URL); errors++; } else { // file should be opened only if collision free try { openFile(getFile()); } catch (java.io.IOException e) { errors++; addError("openFile(" + fileName + "," + append + ") call failed.", e); } } } else { errors++; addError("\"File\" property not set for appender named [" + name + "]."); } if (errors == 0) { super.start(); } }
start方法要求fileName必须有值,在prudent模式下会强制开启append;另外start的时候会执行checkForFileCollisionInPreviousFileAppenders判断是否有冲突,没有冲突则执行openFile方法
checkForFileCollisionInPreviousFileAppenders
protected boolean checkForFileCollisionInPreviousFileAppenders() { boolean collisionsDetected = false; if (fileName == null) { return false; } @SuppressWarnings("unchecked") Map<String, String> map = (Map<String, String>) context.getObject(CoreConstants.FA_FILENAME_COLLISION_MAP); if (map == null) { return collisionsDetected; } for (Entry<String, String> entry : map.entrySet()) { if (fileName.equals(entry.getValue())) { addErrorForCollision("File", entry.getValue(), entry.getKey()); collisionsDetected = true; } } if (name != null) { map.put(getName(), fileName); } return collisionsDetected; }
checkForFileCollisionInPreviousFileAppenders方法从上下文读取FA_FILENAME_COLLISION_MAP,判断有没有文件名重复的,有则返回true
openFile
public void openFile(String file_name) throws IOException { lock.lock(); try { File file = new File(file_name); boolean result = FileUtil.createMissingParentDirectories(file); if (!result) { addError("Failed to create parent directories for [" + file.getAbsolutePath() + "]"); } ResilientFileOutputStream resilientFos = new ResilientFileOutputStream(file, append, bufferSize.getSize()); resilientFos.setContext(context); setOutputStream(resilientFos); } finally { lock.unlock(); } }
openFile方法加锁创建file,然后通过createMissingParentDirectories来创建不存在的父目录,最后创建根据file、append参数、bufferSize来创建ResilientFileOutputStream
stop
public void stop() { super.stop(); Map<String, String> map = ContextUtil.getFilenameCollisionMap(context); if (map == null || getName() == null) return; map.remove(getName()); }
stop方法会获取FA_FILENAME_COLLISION_MAP,移除当前文件名
writeOut
protected void writeOut(E event) throws IOException { if (prudent) { safeWrite(event); } else { super.writeOut(event); } }
FileAppender覆盖了OutputStreamAppender的writeOut方法,在prudent为true时执行safeWrite
safeWrite
private void safeWrite(E event) throws IOException { ResilientFileOutputStream resilientFOS = (ResilientFileOutputStream) getOutputStream(); FileChannel fileChannel = resilientFOS.getChannel(); if (fileChannel == null) { return; } // Clear any current interrupt (see LOGBACK-875) boolean interrupted = Thread.interrupted(); FileLock fileLock = null; try { fileLock = fileChannel.lock(); long position = fileChannel.position(); long size = fileChannel.size(); if (size != position) { fileChannel.position(size); } super.writeOut(event); } catch (IOException e) { // Mainly to catch FileLockInterruptionExceptions (see LOGBACK-875) resilientFOS.postIOFailure(e); } finally { if (fileLock != null && fileLock.isValid()) { fileLock.release(); } // Re-interrupt if we started in an interrupted state (see LOGBACK-875) if (interrupted) { Thread.currentThread().interrupt(); } } }
safeWrite会通过fileChannel.lock()进行加锁,然后执行fileChannel.position(size),最后通过父类writeOut进行写入;对于IOException会执行resilientFOS.postIOFailure(e)
小结
logback的FileAppender继承了OutputStreamAppender,它定义了append、prudent、bufferSize属性,它使用的是ResilientFileOutputStream,其writeOut方法主要是新增了对prudent模式的支持,在prudent为true时采用的是safeWrite。
以上就是logback的FileAppender文件追加模式和冲突检测解读的详细内容,更多关于logback FileAppender冲突检测的资料请关注脚本之家其它相关文章!
相关文章
Java爬虫Jsoup+httpclient获取动态生成的数据
这篇文章主要介绍了Java爬虫Jsoup+httpclient获取动态生成的数据的相关资料,需要的朋友可以参考下2017-05-05
最新评论