log4j 环境包括三个主要组件:
logger(日志记录器):控制要启用或禁用哪些日志记录语句。可以对日志记录器指定如下级别: ALL 、 DEBUG、 INFO 、 WARN 、 ERROR , FATAL 。
layout(布局):根据用户的愿望格式化日志记录请求。
appender:向目的地发送格式化的输出。
log4j 框架允许向任何日志记录器附加多个 appender。可以在任何时候对某个日子记录器添加(或删除)appender。附随 log4j 分发的 appender 有多个,包括:
ConsoleAppender;FileAppender;SMTPAppender ;JDBCAppender;JMSAppender;NTEventLogAppender;SyslogAppender。
也可以创建自己的自定义 appender。
3.本工程设计的目标
通过自建appender类,来实现:
[1]在控制台输出日志;
[2]在log文件输出日志;
[3]在应用程序中建立日志模块(在UI层表现为建立一个日志面板),输出日志;
[4]对于不同包路径下的日志独立输出(在UI层表现为分不同的面板输出)。
4.预备知识
你可以在下面2篇文章中找到Log4j的相关基础介绍。
5.项目文件分布与效果
文件分布如图一所示。我们对于com.log.one包下的所有java文件中的日志信息输出到log one模块(图二);对于com.log.two包下的所有java文件中的日志信息输出到log two模块(图四)。本文只象征性的建立了两个测试文件,分别放在两个包下。
com.log.one.LogTestOne.java
public
class
LogTestOne {
private
final
static
Logger
log
= Logger.getLogger(LogTestOne.
class
);
public
void
doLog(){
log
.debug(
"TestOne debug"
);
log
.info(
"TestOne info"
);
log
.warn(
"TestOne warn"
);
log
.error(
"TestOne error"
);
log
.fatal(
"TestOne fatal"
);
}
}
|
com.log.two.LogTestTwo.java
public
class
LogTestTwo {
private
final
static
Logger
log
= Logger.getLogger(LogTestTwo.
class
);
public
void
doLog() {
log
.debug(
"TestTwo debug"
);
log
.info(
"TestTwo info"
);
log
.warn(
"TestTwo warn"
);
log
.error(
"TestTwo error"
);
log
.fatal(
"TestTwo fatal"
);
}
}
|
图一
对于应用程序中的日志模块,提供一些UI层的基本操作,包括清空(图二,图四);变灰(图三);复制到粘贴板。
The Main Text象征性的表示主应用程序的所有操作。
图二
图三
图四
同时在控制台输出所有日志信息。(图五)
图五
同时在文本文件中输出所有日志信息。(图六)
图六
6.log4j.xml
本项目使用如下日志配置文件,将其放在项目的classpath下。
<!
DOCTYPE
log4j:configuration
SYSTEM
"log4j.dtd"
>
<
log4j:configuration
xmlns:log4j
=
"http://jakarta.apache.org/log4j/"
debug
=
"false"
>
<!-- =================== -->
<!-- Appenders -->
<!-- =================== -->
<
appender
name
=
"CONSOLE"
class
=
"org.apache.log4j.ConsoleAppender"
>
<
errorHandler
class
=
"org.apache.log4j.helpers.OnlyOnceErrorHandler"
/>
<
param
name
=
"Target"
value
=
"System.out"
/>
<
param
name
=
"Threshold"
value
=
"DEBUG"
/>
<
layout
class
=
"org.apache.log4j.PatternLayout"
>
<!-- The default pattern: Date Priority [Category] Message\n -->
<
param
name
=
"ConversionPattern"
value
=
"%-5p %l%m%n"
/>
</
layout
>
</
appender
>
<
appender
name
=
"FILE"
class
=
"org.apache.log4j.RollingFileAppender"
>
<
errorHandler
class
=
"org.apache.log4j.helpers.OnlyOnceErrorHandler"
/>
<
param
name
=
"File"
value
=
"logui.log"
/>
<
param
name
=
"Threshold"
value
=
"INFO"
/>
<
param
name
=
"Append"
value
=
"false"
/>
<
param
name
=
"MaxFileSize"
value
=
"5000KB"
/>
<
param
name
=
"MaxBackupIndex"
value
=
"50"
/>
<
layout
class
=
"org.apache.log4j.PatternLayout"
>
<
param
name
=
"ConversionPattern"
value
=
"%d %-5p [%c{1}] %m%n"
/>
</
layout
>
</
appender
>
<
appender
name
=
"ONE"
class
=
"com.log.utils.LogOneAppender"
>
<
errorHandler
class
=
"org.apache.log4j.helpers.OnlyOnceErrorHandler"
/>
</
appender
>
<
appender
name
=
"TWO"
class
=
"com.log.utils.LogTwoAppender"
>
<
errorHandler
class
=
"org.apache.log4j.helpers.OnlyOnceErrorHandler"
/>
</
appender
>
<!-- =============== -->
<!-- Loggers -->
<!-- =============== -->
<
logger
name
=
"com.log.one"
>
<
level
value
=
"DEBUG"
/>
<
appender-ref
ref
=
"ONE"
/>
<
appender-ref
ref
=
"CONSOLE"
/>
</
logger
>
<
logger
name
=
"com.log.two"
>
<
level
value
=
"DEBUG"
/>
<
appender-ref
ref
=
"TWO"
/>
<
appender-ref
ref
=
"CONSOLE"
/>
</
logger
>
<
root
>
<
priority
value
=
"INFO"
/>
<
appender-ref
ref
=
"FILE"
/>
</
root
>
</
log4j:configuration
>
|
这里除常规的CONSOLE和FILE appender,增加两个appender,ONE和TWO,分别通过自建类LogOneAppender和LogTwoAppender定义。
public
class
LogOneAppender
extends
AppenderSkeleton{
public
LogOneAppender() {}
protected
void
append(LoggingEvent event) {
LogUI.log(event);
}
public
void
close() {}
public
boolean
requiresLayout() {
return
false
;
}
}
|
public
class
LogTwoAppender
extends
AppenderSkeleton{
public
LogTwoAppender() {}
protected
void
append(LoggingEvent event) {
LogUI.log(event);
}
public
void
close() {}
public
boolean
requiresLayout() {
return
false
;
}
}
|
在logger中通过logger name,com.log.one和com.log.two指定到上述的appender。
7.主界面设计LogUI.java
主面板为frame,其中嵌入LogPanel。log类的实体是一个Log4Jmonitor类的实例,通过它的addLogArea方法可以添加日志模块,其中的第二个参数对应log4j配置文件中的logger name。这里还提供一个Cache功能,即如果在主类(LogUI)或日志类(Log4Jmonitor)还没有实例化之前,已经有日志信息,则进行缓存。
public
class
LogUI {
private
static
LogUI
instance
;
private
static
JFrame
frame
;
private
Log4JMonitor
logMonitor
;
private
static
List<Object>
logCache
=
new
ArrayList<Object>();
public
LogUI() {
instance
=
this
;
}
///////////////////////UI
private
void
buildUI() {
frame
.addWindowListener(
new
WindowAdapter() {
public
void
windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame
.getContentPane().add(buildContentPanel(), BorderLayout.
CENTER
);
frame
.setDefaultCloseOperation(JFrame.
DO_NOTHING_ON_CLOSE
);
frame
.setSize(100, 75);
}
private
Component buildContentPanel() {
JSplitPane contentSplit =
new
JSplitPane();
contentSplit.setTopComponent(
new
JTextArea(
"The Main Text"
));
contentSplit.setBottomComponent(buildLogPanel());
contentSplit.setDividerLocation(550);
contentSplit.setResizeWeight(1);
return
contentSplit;
}
private
Component buildLogPanel() {
logMonitor
=
new
Log4JMonitor();
logMonitor
.addLogArea(
"log one"
,
"com.log.one"
,
true
).setLevel(
Level.
DEBUG
);
logMonitor
.addLogArea(
"log two"
,
"com.log.two"
,
true
).setLevel(
Level.
DEBUG
);
for
(Object message :
logCache
) {
logMonitor
.logEvent(message);
}
return
logMonitor
;
}
public
void
show() {
buildUI();
frame
.setVisible(
true
);
}
////////////////////Log
public
static
synchronized
void
log(
final
Object msg) {
if
(
instance
==
null
||
instance
.
logMonitor
==
null
) {
logCache
.add(msg);
return
;
}
if
(SwingUtilities.isEventDispatchThread()) {
instance
.
logMonitor
.logEvent(msg);
}
else
{
SwingUtilities.invokeLater(
new
Runnable() {
public
void
run() {
instance
.
logMonitor
.logEvent(msg);
}
});
}
}
//////////////////Test Cases
public
void
doTests(){
LogTestOne one=
new
LogTestOne();
one.doLog();
LogTestTwo two=
new
LogTestTwo();
two.doLog();
}
public
static
void
main(String[] args)
throws
Exception {
frame
=
new
JFrame(
"LogUI "
);
LogUI logUi =
new
LogUI();
logUi.show();
logUi.doTests();
}
}
|
8.log类的实体Log4Jmonitor
通过此类来建立日志模块。其中用到的JlogList.java(见附件)提供对日志模块的所有基本功能。addLogArea方法增加日志模块。logEvent方法对输出的日志事件类型做出判断,对该日志所属的日志模块(本实例为com.log.one和com.log.two)做出判断。
public
class
Log4JMonitor
extends
JTabbedPane {
private
JLogList
defaultLogArea
;
public
Log4JMonitor() {
super
(JTabbedPane.
BOTTOM
, JTabbedPane.
SCROLL_TAB_LAYOUT
);
}
public
JLogList addLogArea(String title, String loggerName,
boolean
isDefault) {
JLogList logArea =
new
JLogList(title);
logArea.addLogger(loggerName, !isDefault);
addTab(title, logArea);
if
(isDefault)
defaultLogArea
= logArea;
return
logArea;
}
public
void
logEvent(Object msg) {
if
(msg
instanceof
LoggingEvent) {
LoggingEvent event = (LoggingEvent) msg;
String loggerName = event.getLoggerName();
for
(
int
c = 0; c < getTabCount(); c++) {
Component tabComponent = getComponentAt(c);
if
(tabComponent
instanceof
JLogList) {
JLogList logArea = (JLogList) tabComponent;
if
(logArea.monitors(loggerName)) {
logArea.addLine(msg);
}
}
}
}
else
if
(
defaultLogArea
!=
null
) {
defaultLogArea
.addLine(msg);
}
}
public
boolean
hasLogArea(String loggerName) {
for
(
int
c = 0; c < getTabCount(); c++) {
Component tabComponent = getComponentAt(c);
if
(tabComponent
instanceof
JLogList) {
JLogList logArea = (JLogList) tabComponent;
if
(logArea.monitors(loggerName)) {
return
true
;
}
}
}
return
false
;
}
}
|
本文转自zhangjunhd51CTO博客,原文链接:http://blog.51cto.com/zhangjunhd/48895,如需转载请自行联系原作者