`
wsmajunfeng
  • 浏览: 496863 次
  • 性别: 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....

    (转)如何自建appender扩展Log4j框架

    5. **注册Appender**:在Log4j的配置文件(如log4j.properties或log4j.xml)中,声明你的自定义Appender,并配置相关属性。例如: ```xml &lt;appender name="MyCustomAppender" class=...

    Log4J_全能配置文件.pdf

    - `log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender`:指定了名为`CONSOLE`的appender是控制台输出。 - `log4j.appender.CONSOLE.Target=System.out`:日志输出到标准输出流(System.out)。 - `log4j....

    log4j-socketappender:自定义 Log4J 的 SocketAppender,在日志服务器和调用事件的各种客户端之间进行通信

    自定义 Log4J 的 SocketAppender,在日志服务器和调用事件的各种客户端之间进行通信。 如何使用:AsynchListener - 通知程序 - 当日志服务器在特定端口和机器上准备就绪时,通知日志客户端是否准备好调用通知。 ...

    log4j自定义日志文件名及日志输出格式

    配置文件(log4j.properties)中,你需要将这个自定义的Appender和Layout加入: ```properties log4j.appender.customAppender=your.package.CustomLogAppender log4j.appender.customAppender.layout=your.package...

    log4j配置文件以及配套jar包.rar

    在提供的压缩包中,我们看到了四个文件:log4j-core-2.3.jar、log4j-1.2.17.jar、log4j-api-2.3.jar以及log4j.properties。这里,log4j-core和log4j-api是Log4j 2.x版本的核心库,它们提供了日志记录的功能实现。log...

    SpringBoot框架配置log4j和log4j2的配置代码

    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n log4j.appender.file=org.apache.log4j....

    log4j+slf4j实现 log4j测试代码,log4j+slf4j实现 log4j测试代码

    总结,SLF4J和Log4j的组合使用让日志管理更加灵活,开发者可以通过SLF4J的简洁API进行日志记录,同时利用Log4j的强大功能,如自定义输出格式和多种输出目的地。通过适当的配置和测试,我们可以确保日志系统按照预期...

    log4j自定义

    《深入理解Log4j自定义》 在Java开发中,日志系统扮演着至关重要的角色,它能够帮助我们记录程序运行过程中的各种信息,便于调试、监控和问题排查。Log4j作为一款广泛使用的日志框架,其强大的可配置性和自定义能力...

    log4j-1.2.17的jar包以及依赖包,还有一份log4j的配置文件,输出到控制台和文件夹两种配置

    log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n # 文件Appender log4j.appender.File=org.apache...

    log4j多文件输出打印

    log4j.appender.ERROR.layout=org.apache.log4j.PatternLayout log4j.appender.ERROR.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n # 定义一个名为INFO的Appender,用于记录信息级别及以上的日志 ...

    Log4j2简介及与Log4j效率对比

    6. **自定义日志级别**:除了内置的日志级别(如DEBUG、INFO、WARN、ERROR、FATAL),Log4j2还支持用户自定义的日志级别,可以通过代码或配置文件进行定义。 7. **消息对象支持**:用户可以创建自定义的消息类型,...

    log4j输出多个自定义路径的日志文件小例子

    要实现输出多个自定义路径的日志文件,我们需要在Log4j的配置文件(通常是`log4j.properties`或`log4j.xml`)中定义多个Appender。Appender是Log4j中负责将日志信息输出到指定目的地的组件,例如文件、控制台、网络...

    tomcat下的log4j日志配置

    2. **编写初始化 Servlet**:创建一个自定义的 Servlet 来初始化 Log4j。该 Servlet 的主要任务是在启动时加载特定的 `log4j.properties` 文件。 ```java public class Log4jInitServlet extends HttpServlet { ...

    自定义异常和log4j的使用

    本文将详细讲解如何实现自定义异常以及如何有效地利用Log4j进行日志管理。 首先,让我们来了解自定义异常。在Java中,当我们遇到特定的业务逻辑错误或需要更精确地捕获和处理错误时,我们可以创建自定义异常。...

    log4j-1.2.17.jar下载

    Log4j允许开发者自定义日志输出的方式和格式,通过继承Appender和Layout接口,可以实现如电子邮件通知、日志发送到服务器或其他特殊格式的需求。 六、性能优化 在大型系统中,日志处理可能成为性能瓶颈。Log4j提供...

    Spring项目中怎么配置log4j

    log4j.appender.R=org.apache.log4j.DailyRollingFileAppender log4j.appender.R.File=./logs/app.log log4j.appender.R.ImmediateFlush=true log4j.appender.R.Append=true log4j.appender.R.Threshold=DEBUG ...

    log4j_jar包跟教程说明

    - Log4j允许开发者创建自定义的Appender和Layout来满足特定需求,如发送邮件、写入数据库等。 - Appender决定了日志信息的输出位置,而Layout则决定日志的显示格式。 6. **Log4j的最新版本:Log4j 2** - 随着...

    log4j-1.2.17.jar及配置文件

    Log4j还提供了许多高级特性,如过滤器(Filter)来控制哪些日志信息会被记录,自定义布局(Custom Layout)来实现特定的日志格式,以及异步日志记录以提高性能。此外,还可以通过引入其他模块如SMTPAppender发送邮件...

    log4j jarjar包

    四、Log4j的高级特性 1. **异步日志记录**:Log4j支持异步日志记录,通过AsyncAppender可以在不阻塞主线程的情况下高效地处理日志。 2. **自定义Appender和Layout**:如果内置的Appender和Layout无法满足需求,...

Global site tag (gtag.js) - Google Analytics