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模式下會(huì)強(qiáng)制開啟append;另外start的時(shí)候會(huì)執(zhí)行checkForFileCollisionInPreviousFileAppenders判斷是否有沖突,沒有沖突則執(zhí)行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,判斷有沒有文件名重復(fù)的,有則返回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方法加鎖創(chuàng)建file,然后通過createMissingParentDirectories來創(chuàng)建不存在的父目錄,最后創(chuàng)建根據(jù)file、append參數(shù)、bufferSize來創(chuàng)建ResilientFileOutputStream
stop
public void stop() {
super.stop();
Map<String, String> map = ContextUtil.getFilenameCollisionMap(context);
if (map == null || getName() == null)
return;
map.remove(getName());
}stop方法會(huì)獲取FA_FILENAME_COLLISION_MAP,移除當(dāng)前文件名
writeOut
protected void writeOut(E event) throws IOException {
if (prudent) {
safeWrite(event);
} else {
super.writeOut(event);
}
}FileAppender覆蓋了OutputStreamAppender的writeOut方法,在prudent為true時(shí)執(zhí)行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會(huì)通過fileChannel.lock()進(jìn)行加鎖,然后執(zhí)行fileChannel.position(size),最后通過父類writeOut進(jìn)行寫入;對(duì)于IOException會(huì)執(zhí)行resilientFOS.postIOFailure(e)
小結(jié)
logback的FileAppender繼承了OutputStreamAppender,它定義了append、prudent、bufferSize屬性,它使用的是ResilientFileOutputStream,其writeOut方法主要是新增了對(duì)prudent模式的支持,在prudent為true時(shí)采用的是safeWrite。
以上就是logback的FileAppender文件追加模式和沖突檢測解讀的詳細(xì)內(nèi)容,更多關(guān)于logback FileAppender沖突檢測的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java?IO流—異常及捕獲異常處理?try…catch…finally
這篇文章主要介紹了Java?IO流—異常及捕獲異常處理?try…catch…finally,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
淺談Java中的atomic包實(shí)現(xiàn)原理及應(yīng)用
這篇文章主要介紹了淺談Java中的atomic包實(shí)現(xiàn)原理及應(yīng)用,涉及Atomic在硬件上的支持,Atomic包簡介及源碼分析等相關(guān)內(nèi)容,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12
SpringBoot教程_創(chuàng)建第一個(gè)SpringBoot項(xiàng)目
這篇文章主要介紹了SpringBoot教程_創(chuàng)建第一個(gè)SpringBoot項(xiàng)目,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
SpringBoot thymeleaf eclipse熱部署方案操作步驟
今天小編就為大家分享一篇關(guān)于SpringBoot thymeleaf eclipse熱部署方案操作步驟,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
Lucene實(shí)現(xiàn)索引和查詢的實(shí)例講解
下面小編就為大家分享一篇Lucene實(shí)現(xiàn)索引和查詢的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12
利用Mybatis向PostgreSQL中插入并查詢JSON字段
這篇文章主要介紹了利用Mybatis向PostgreSQL中插入并查詢JSON字段,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07

