Log4j 配置appender

本文介绍如何自定义Log4j的Appender,包括扩展AppenderSkeleton抽象类、实现必要的方法如append()和close(),以及配置Appender的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

编写自定义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

4j;

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 RemoteHost 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 RemoteHost option.
 */
public String getRemoteHost() {
    return remoteHost;
}

/**
 * The Port 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 Port 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目录下。

PS:网上的一篇好文 http://www.blogjava.net/dwys0343/articles/96019.html
自定义log4j的Appender
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=.log
    对应的在RollingFileAppender中,有
    public void setFile(String file) {
    String val = file.trim();
    fileName = val;
    }
    其它的属性,如MaxFileSize ,也相同

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

    OptionHandler 接口定义了activateOptions()方法,在全部属性设置好了之后,在该方法中进行必要的操作,如打开文件
    e.g
    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() 方法的代码。这个方法负责附加日志记录事件,并在错误发生时负责调用错误处理程序。

转载于:https://www.cnblogs.com/Dennis-mi/articles/6727026.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值