`
wsmajunfeng
  • 浏览: 492096 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

自定义log4j的Appender

阅读更多

编写自定义appender 的 步骤

1. 扩展 AppenderSkeleton 抽象类。如果是通过流方式实现读写数据的话,自定一定appender可以从WriterAppender继承,这样只需要把我们自己的 OutputStream连接到WriterAppender.qw上就可以了。更方便快捷。

2. 指定您的 appender 是否需要 layout。这个由requiresLayout()方法确定。

3. 如果某些属性必须同时激活,则应该在 activateOptions() 方法内完成。该方法上在Appender的构造函数之后被调用的。

4. 实现 close() 方法。它必须把 closed 字段的值设置为 true 。记得释放所有资源。

5. 可选地指定要使用的默认 ErrorHandler 对象。系统默认为OnlyOnceErrorHandler,它发送出第一个错误的消息并忽略其余的所有错误,错误消息将输出到 System.err。

6. 编写 append() 方法的代码。这个方法负责附加日志记录事件,并在错误发生时负责调用错误处理程序。我们主要的日志记录等处理任务实际上是在该append()方法内完成的。

 

请看程序。
由测试程序:Log4jTest.java、
自定义的Appdender:UDPAppender
配置文件:log4j.properties
三个源文件组成。
测试程序:Log4jTest.java

写道
package zieckey.study.log4j;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class Log4jTest {

// 获取日志记录器
static Logger logger = Logger.getLogger(Log4jTest.class.getName());

Log4jTest() {
// 读取使用Java属性文件编写的配置文件
logger.debug("Read config file.");
PropertyConfigurator.configure("src/log4j.properties");
}

public static void printLog() {
logger.debug("Log4jTest-->>debug");
logger.info("Log4jTest-->>info");
logger.warn("Log4jTest-->>warn");
logger.error("Log4jTest-->>error");
}

public static void main(String[] args) {
Log4jTest.printLog();
new Log4jTest();
}
}

 自定义的Appdender:UDPAppender

写道
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;

public class UDPAppender extends AppenderSkeleton {

static private int bufferSize = 8 * 1024;
private byte data[];
private String remoteHost = "localhost";
private int port = 5000;
private InetAddress address = null;
private DatagramSocket dataSocket = null;
private DatagramPacket dataPacket = null;

public UDPAppender() {
// LogLog.setInternalDebugging(true);
// LogLog.setQuietMode(false);
// LogLog.debug("default constructor.");
}

private void init() {
try {
dataSocket = new DatagramSocket(this.port + 1);
address = InetAddress.getByName(remoteHost);
} catch (SocketException e) {
LogLog.debug(e.getMessage());
} catch (UnknownHostException e) {
LogLog.debug(e.getMessage());
}
data = new byte[bufferSize];
if (this.layout == null) {
LogLog.debug("The layout is not loaded... we set it.");
String pattern = "%-4r %-5p %d{yyyy-MM-dd HH:mm:ss} %c %m%n";
this.setLayout(new org.apache.log4j.PatternLayout(pattern));
}
}

@Override
protected void append(LoggingEvent event) {
try {
String msg = "UDP Appender...send data: " + this.getLayout().format(event);
data = msg.getBytes();
dataPacket = new DatagramPacket(data, data.length, address, port);
dataSocket.send(dataPacket);
} catch (SocketException se) {
se.printStackTrace();
} catch (IOException ie) {
ie.printStackTrace();
}
}

/**
* Derived appenders should override this method if option structure requires it.
*/
public void activateOptions() {
init();
}

@Override
public void close() {
if (closed) return;
if (!dataSocket.isClosed()) {
dataSocket.close();
}
closed = true;
}

@Override
public boolean requiresLayout() {
return true;
}

/**
* The <b>RemoteHost</b> option takes a string value which should be the host name of the server where a
* {@link SocketNode} is running.
*/
public void setRemoteHost(String host) {
String val = host.trim();
remoteHost = val;
}

/**
* Returns value of the <b>RemoteHost</b> option.
*/
public String getRemoteHost() {
return remoteHost;
}

/**
* The <b>Port</b> option takes a positive integer representing the port where the server is waiting for
* connections.
*/
public void setPort(int port) {
this.port = port;
}

/**
* Returns value of the <b>Port</b> option.
*/
public int getPort() {
return port;
}
}

 配置文件:log4j.properties

写道
log4j.rootLogger=DEBUG,CONSOLE,UDPAppender,LOGFILE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ss} %c %m%n
log4j.appender.UDPAppender=zieckey.study.log4j.UDPAppender
log4j.appender.UDPAppender.RemoteHost=localhost
log4j.appender.UDPAppender.Port=4561
log4j.appender.UDPAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.UDPAppender.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ss} %c %m%n
log4j.appender.LOGFILE=org.apache.log4j.RollingFileAppender
log4j.appender.LOGFILE.File=Log4jTest.log
log4j.appender.LOGFILE.MaxFileSize=20KB
log4j.appender.LOGFILE.MaxBackupIndex=1
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ss} %c %m%n

 

注意配置文件应该放在src目录下。

appender 的生命周期

 

 

1. appender 实例不存在,或许框架还没有配置好。

2. 框架实例化了一个新的 appender。这发生在配置器类分析配置脚本中的一个 appender 声明的时候。配置器类调用 Class.newInstance(YourCustomAppender.class) ,这等价于动态调用 new YourCustomAppender() 。框架这样做是为了避免被硬编码为任何特定的 appender 名称;框架是通用的,适用于任何 appender。

e.g. log4j.appender.file=org.apache.log4j.RollingFileAppender

3. 框架判断 appender 是否需要 layout。如果该 appender 不需要 layout,配置器就不会尝试从配置脚本中加载 layout 信息。

在Appender接口中,有public boolean requiresLayout() 方法,如果return true;则要求layout,需在配置脚本中设置layout信息

e.g. log4j.appender.file.layout=org.apache.log4j.PatternLayout

4. Log4j 配置器调用 setter 方法。在所有属性都已设置好之后,框架就会调用这个方法。

此时对应RollingFileAppender的每个Field,需要有一个setter方法,在配置脚本中也要进行设置

e.g. log4j.appender.file.File=<project>.log

对应的在RollingFileAppender中,有

public void setFile(String file) {

    String val = file.trim();

    fileName = val;

}

其它的属性,如MaxFileSize ,也相同

5. 配置器调用 activateOptions() 方法。在所有属性都已设置好之后,框架就会调用这个方法。

OptionHandler 接口定义了activateOptions()方法,在全部属性设置好了之后,在该方法中进行必要的操作,如打开文件:

写道
if(fileName != null) {

try {

setFile(fileName, fileAppend, bufferedIO, bufferSize);

}

catch(java.io.IOException e) {

errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.",

e, ErrorCode.FILE_OPEN_FAILURE);

}

} else {

//LogLog.error("File option not set for appender ["+name+"].");

LogLog.warn("File option not set for appender ["+name+"].");

LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");

}

 

6. Appender 准备就绪。 此刻,框架可以调用 append() 方法来处理日志记录请求。这个方法由 AppenderSkeleton.doAppend() 方法调用。

该方法为Appender中最关键的方法,append()中可以定义日志的输出,最简单的:

protected void append(LoggingEvent event){

    //if layout is required

    System.out.println(this.getLayout().format(event));

}

7. 最后,关闭appender。 当框架即将要删除您的自定义 appender 实例时,它会调用您的 appender 的 close() 方法。 close() 是一个清理方法,意味着 您需要释放已分配的所有资源。它是一个必需的方法,并且不接受任何参数。它必须把 closed 字段设置为 true ,并在有人尝试使用关闭的 appender 时向框架发出警报。

public void close() {

        if (this.closed)

            return;

        this.closed = true;

    }

注意: 需要在主程序退出前,调用Logger.getRoot().removeAllAppender();这样才能调用Appender的close()方法.

 

编写自定义appender 的 步骤

1. 扩展 AppenderSkeleton 抽象类。

2. 指定您的 appender 是否需要 layout。

3. 如果某些属性必须同时激活,则应该在 activateOptions() 方法内完成。

4. 实现 close() 方法。它必须把 closed 字段的值设置为 true 。记得释放所有资源。

5. 可选地指定要使用的默认 ErrorHandler 对象。系统默认为OnlyOnceErrorHandler,它发送出第一个错误的消息并忽略其余的所有错误,错误消息将输出到 System.err。

6. 编写 append() 方法的代码。这个方法负责附加日志记录事件,并在错误发生时负责调用错误处理程序。

 

log4j 环境包括三个主要组件:

  • logger(日志记录器) :控制要启用或禁用哪些日志记录语句。可以对日志记录器指定如下级别: ALLDEBUGINFOWARNERROR , FATA或 OFF
  • layout(布局): 根据用户的愿望格式化日志记录请求。
  • appender :向目的地发送格式化的输出。

所有的 appender 都必须扩展 org.apache.log4j.AppenderSkeleton 类,这是一个抽象类,它实现了 org.apache.log4j.Appenderorg.apache.log4j.spi.OptionHandler 接口。 AppenderSkeleton 类的 UML 类图看起来如图所示:

自定义log4j的Appender - is00hcw - is00hcw的博客

Appender 接口

package org.apache.log4j;public interface Appender {    void addFilter(Filter newFilter);                        void clearFilters() ;                                                   void close();                                                            void doAppend(LoggingEvent event);                ErrorHandler getErrorHandler();         Filter getFilter();             Layout getLayout();              String getName();           boolean requiresLayout();            void setErrorHandler(ErrorHandler errorHandler);            void setLayout(Layout layout);           void setName(String name);         }

这些方法处理 appender 的如下属性:

  • name: Appender 是命名的实体,因此有一个针对其名称的 setter/getter。
  • layout: Appender 可以具有关联的 Layout,因此还有另一个针对 layout 的setter/getter 方法。注意我们说的是“可以”而不是“必须”。这是因为有些 appender 不需要 layout。lauout 管理格式输出――也就是说,它返回 LoggingEventString 表示形式。另一方面, JMSAppender 发送的事件是 串行化的,因此您不需要对它附加 layout。如果自定义的 appender 不需要 layout,那么 requiresLayout() 方法必须返回 false ,以避免 log4j 抱怨说丢失了 layout 信息。
  • errorHandler : 另一个 setter/getter 方法是为 ErrorHandler 而存在的。appender 可能把它们的错误处理委托给一个 ErrorHandler 对象――即 org.apache.log4j.spi 包中的一个接口。实现类有两个:OnlyOnceErrorHandlerFallbackErrorHandlerOnlyOnceErrorHandle 实现 log4j 的默认错误处理策略,它发送出第一个错误的消息并忽略其余的所有错误。错误消息将输出到 System.errFallbackErrorHandler 实现ErrorHandler 接口,以便能够指定一个辅助的 appender。如果主 appender 失败,辅助 appender 将接管工作。错误消息将输出到 System.err ,然后登录到新的辅助 appender。

还有管理过滤器的其他方法(比如 ddFilter()clearFilters()getFilter() 方法 )。尽管 log4j 具有过滤日志请求的多种内置方法(比如知识库范围级、日志记录器级和 appender 阈值级),但它使用自定义过滤器方法的能力也是非常强大的。

一个 appender 可以包含多个过滤器。自定义过滤器必须扩展 org.apache.log4j.spi.Filter 抽象类。这个抽象类要求把过滤器组织为线性链。 对每个过滤器的 decide(LoggingEvent) 方法的调用要按照过滤器被添加到链中的顺序来进行。自定义过滤器基于三元逻辑。 decide() 方法必须返回 DENYNEUTRAL 或者 ACCEPT 这三个整型常量值之一。

除了 setter/getter 方法以及和过滤器相关的方法外,还有另外两个方法: close()doAppend()close() 方法释放 appender 中分配的任何资源,比如文件句柄、网络连接,等等。在编写自定义 appender 代码时,务必要实现这个方法,以便当您的 appender 关闭时,它的 closed 字段将被设置为 true

自定义log4j的Appender - is00hcw - is00hcw的博客  

  • appender 实例不存在。 或许框架还没有配置好。
  • 框架实例化了一个新的 appender。 这发生在配置器类分析配置脚本中的一个 appender 声明的时候。配置器类调用 Class.newInstance(YourCustomAppender.class) ,这等价于动态调用 new YourCustomAppender() 。框架这样做是为了避免被硬编码为任何特定的 appender 名称;框架是通用的,适用于任何 appender。
  • 框架判断 appender 是否需要 layout。 如果该 appender 不需要 layout,配置器就不会尝试从配置脚本中加载 layout 信息。
  • Log4j 配置器调用 setter 方法。 在所有属性都已设置好之后,框架就会调用这个方法。程序员可以在这里激活必须同时激活的属性。
  • 配置器调用 activateOptions() 方法。 在所有属性都已设置好之后,框架就会调用这个方法。程序员可以在这里激活必须同时激活的属性。
  • Appender 准备就绪。 此刻,框架可以调用 append() 方法来处理日志记录请求。这个方法由 AppenderSkeleton.doAppend() 方法调用。
  • 最后,关闭appender。 当框架即将要删除您的自定义 appender 实例时,它会调用您的 appender 的 close() 方法。 close() 是一个清理方法,意味着 您需要释放已分配的所有资源。它是一个必需的方法,并且不接受任何参数。它必须把 closed 字段设置为 true ,并在有人尝试使用关闭的 appender 时向框架发出警报。
分享到:
评论

相关推荐

    log4j日志驱动包

    log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000 # 发送日志给邮件 log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender log4j.appender....

    log4j使用实战

    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender INFO是日志记录的最低等级,必须写,它和比它高的等级会进入日志,如WARN、ERROR、FATAL、OFF。 关于8个日志等级,参考:...

    oohlalog_grails:用于 log4j Appender 的 OohLaLog Grails 插件

    Grails OohLaLog 插件添加了一个 log4j appender 来将流量转发到 oohlalog api 服务。 这允许其用户跨多个服务器聚合日志、设置警报、自定义计数器并实时监控他们的应用程序。 Log4J 附加程序 修改您的 Config....

    log4j参考手册

    1 Log4J简介 3 2 Log4J实现 3 2.1 Log4J配置 3 2.2 Log4J的类图 4 2.3 日志级别 4 2.4 配置Logger组件 4 2.5 配置Appender组件 5 2.6 配置Layout组件 6 2.7 日志文件的名称 7 2.8 日志文件的大小 7 2.9 Log4j....

    java自定义日志输出文件(log4j日志文件输出多个自定义日志文件)

    打印日志的在程序中是必不可少的,如果需要将不同的日志打印到不同的地方,则需要定义不同的Appender,然后定义每一个Appender的日志级别、打印形式和日志的输出路径,下面看一个示例吧

    NagiosAppender:log4j 支持原生 nagios (nsca) 集成-开源

    该项目包含一个用于 log4j 的自定义 appender,适用于对使用 log4j 架构通过 Nagios nsca 服务器将消息推送到 Nagios 感兴趣的系统管理员和/或开发人员。 2.0.0 版支持异步消息传递、可调超时和用于重新传递支持的...

    java日志框架视频教程

    自定义Logger章节四:JCL1. 快速入门2. 原理解析章节五:Slf4j1. 快速入门2. 绑定日志实现3. 桥接旧日志实现4. 原理解析章节六:Logback1. 快速入门2. 配置文件3. logback-access使用章节七:Log4j21. 快速入门2. ...

    应用分析监控平台 闪电狗.zip

    log4j配置:log4j.appender.MongoDB.layout.ConversionPattern={"timestamp":"%d","level":"%p","className":"%c","message":"%m","pid":"%V","ip":"%I",uuid:"%X{UUID}"} 如何监控tomcat访问日志 1.先配置将...

    jpivot学习总结.doc

    memberReaderClass 设定一个成员读取器,默认情况下 Hierarchy 都是从关系型数据库里读取的,如果你的数据不在 RDBMS 里面的话,你可以通过自定义一个 member reader 来表现一个 Hierarchy 。 3.5. Level 级别 , ...

    Logback用户手册中文版

    目录 ..........................................................................................................................I ...4. Appender ..........................................

Global site tag (gtag.js) - Google Analytics