第十三章:從 log4j 遷移
本章涉及到的內(nèi)容為將 log4j 的組件鳍怨,例如 appender 或者 layout 遷移到 logback-classic玻佩。
僅僅調(diào)用 log4j 客戶端 API 的軟件钻蹬,也就是 org.apache.log4j
包中 Logger
或者 Category
類酷师,可以通過(guò) SLF4J 遷移工具使用 SLF4J 來(lái)進(jìn)行自動(dòng)遷移珠闰。為了將 log4j.property 文件轉(zhuǎn)換為同等的 logback 配置惜浅,你可以使用 log4j.properties 轉(zhuǎn)換器。
在某種程度上來(lái)說(shuō)伏嗜,log4j 與 logback-classic 密切相關(guān)坛悉。核心組件杭朱,logger,appender 以及 layout 在兩個(gè)框架中都存在吹散,并且目的一致弧械。類似的,最重要的內(nèi)部數(shù)據(jù)結(jié)構(gòu)空民,叫做 LoggingEvent
刃唐,在兩個(gè)框架中非常相似,但是實(shí)現(xiàn)完全不同界轩。最主要的是画饥,在 logback-classic 中,LoggingEvent
實(shí)現(xiàn)了 ILoggingEvent
接口浊猾。遷移 log4j 組件到 logback-classic 最大的改變?cè)谟?LoggingEvent
類相關(guān)的實(shí)現(xiàn)不同抖甘。但是,請(qǐng)放心葫慎,這些變化是有限的衔彻。如果你盡了最大的努力仍然不能將 log4j 組件遷移到 logback-classic,你可以通過(guò) logback 開(kāi)發(fā)郵件列表來(lái)進(jìn)行提問(wèn)偷办。logback 的開(kāi)發(fā)者應(yīng)該可以提供指導(dǎo)艰额。
遷移 log4j 的 layout
假設(shè)我們現(xiàn)在要遷移一個(gè)簡(jiǎn)單的,名叫 TrivialLog4jLayout 的 log4j layout椒涯,它將日志事件中的消息作為格式化消息返回柄沮。代碼如下:
package chapters.migrationFromLog4j;
import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent;
public class TrivialLog4jLayout extends Layout {
public void activateOptions() {
}
public String format(LoggingEvent loggingEvent) {
return loggingEvent.getRenderedMessage();
}
public boolean ignoresThrowable() {
return true;
}
}
等價(jià)的 logback-classic TrivialLogbackLayout 如下:
package chapters.migrationFromLog4j;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.LayoutBase;
public class TrivialLogbackLayout extends LayoutBase<ILoggingEvent> {
public String doLayout(ILoggingEvent loggingEvent) {
return loggingEvent.getMessage();
}
}
正如你所見(jiàn),在 logback-classic layout 中废岂,格式化的方法叫做 doLayout
祖搓,而在 log4j 中叫 format()
。因?yàn)樵?logback-classic 中沒(méi)有等價(jià)的方法湖苞,所以 ignoresThrowable()
方法則不需要拯欧。logback-classic layout 必須繼承 LayoutBase<ILoggingEvent>
類。
activateOptions()
方法的優(yōu)點(diǎn)值得進(jìn)一步討論袒啼。在 log4j 中哈扮,一個(gè) layout 有它自己的 activateOptions()
方法,通過(guò) log4j 的配置程序蚓再,也就是 PropertyConfigurator
與 DOMConfigurator
滑肉,會(huì)在 layout 所有的選項(xiàng)都設(shè)置完之后調(diào)用。因此摘仅,layout 有機(jī)會(huì)去檢查它的所有的選項(xiàng)是否一致靶庙,如果是,那么開(kāi)始進(jìn)行初始化娃属。
在 logback-classic 中六荒,layout 必須實(shí)現(xiàn) LifeCycle 接口护姆,該接口包含了一個(gè) start()
方法。這個(gè) start()
方法相當(dāng) log4j 中的 activateOptions()
方法掏击。
遷移 log4j 的 appender
遷移 appender 與遷移 layout 相當(dāng)?shù)念愃坡言怼O旅媸怯幸粋€(gè)名為 TrivialLog4jAppender 的簡(jiǎn)單 appender,它會(huì)在控制臺(tái)輸出由它的 layout 返回的字符串砚亭。
package chapters.migrationFromLog4j;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class TrivialLog4jAppender extends AppenderSkeleton {
protected void append(LoggingEvent loggingevent) {
String s = this.layout.format(loggingevent);
System.out.println(s);
}
public void close() {
// nothing to do
}
public boolean requiresLayout() {
return true;
}
}
在 logback-classic 中等價(jià)的寫(xiě)法為 TrivialLogbackAppender灯变,如下:
package chapters.migrationFromLog4j;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
public class TrivialLogbackAppender extends AppenderBase<ILoggingEvent> {
@Override
public void start() {
if (this.layout == null) {
addError("No layout set for the appender named [" + name + "].");
return;
}
super.start();
}
@Override
protected void append(ILoggingEvent loggingevent) {
// AppenderBase.doAppend 只會(huì)在這個(gè) appender 成功啟動(dòng)之后調(diào)用這個(gè)方法
String s = this.layout.doLayout(loggingevent);
System.out.println(s);
}
}
比較這兩個(gè)類,你會(huì)發(fā)現(xiàn) append()
方法的內(nèi)容沒(méi)有改變捅膘。requiresLayout
方法在 logback 中沒(méi)有用到添祸,所以它可以被移除。在 logback 中寻仗,stop()
方法與 log4j 中的 close()
方法等價(jià)刃泌。然而,logback-classic 中的 AppenderBase
包含一個(gè)沒(méi)有實(shí)現(xiàn)的 stop
方法署尤,但是在這個(gè)簡(jiǎn)單的 appender 已經(jīng)足夠了耙替。