log4j——SocketAppender

本文介绍了log4j的SocketAppender功能,它将日志事件序列化并通过Socket发送到远程服务器。SocketServer监听4560端口,接收并反序列化日志信息。示例代码展示了如何使用SimpleSocketServer和SocketClient进行配置和测试,以实现远程日志收集。

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

SocketAppender所实现的功能

  SocketAppender所实现的功能是将本地的日志LoggingEvent类序列化发送到远程主机,在远程主机中完成反序列化,然后通过其中的方法获取相应的日志信息。

SocketServer

  这个SocketServer其主要功能是监听本地的一个端口,这里我们选择官方定义的4560端口号,也就是说SocketServer通过监听4560端口号中的信息,一旦发现有信息写入(ObjectInputStream),即反序列化生成LoggingEvent,通过其中的方法来获取相应的日志信息。

  这个SocketServer在源码中就有现成的例子,在源码中的例子是SimpleSocketServer,其中的源码如下:

package org.apache.log4j.net;

import java.net.ServerSocket;
import java.net.Socket;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;

public class SimpleSocketServer {
    static Logger cat;
    static int port;

    public SimpleSocketServer() {
    }

    public static void main(String[] argv) {
        if (argv.length == 2) {
            init(argv[0], argv[1]);
        } else {
            usage("Wrong number of arguments.");
        }

        try {
            cat.info("Listening on port " + port);
            ServerSocket serverSocket = new ServerSocket(port);

            while(true) {
                cat.info("Waiting to accept a new client.");
                Socket socket = serverSocket.accept();
                cat.info("Connected to client at " + socket.getInetAddress());
                cat.info("Starting new socket node.");
                (new Thread(new SocketNode(socket, LogManager.getLoggerRepository()), "SimpleSocketServer-" + port)).start();
            }
        } catch (Exception var3) {
            var3.printStackTrace();
        }
    }

    static void usage(String msg) {
        System.err.println(msg);
        System.err.println("Usage: java " + SimpleSocketServer.class.getName() + " port configFile");
        System.exit(1);
    }

    static void init(String portStr, String configFile) {
        try {
            port = Integer.parseInt(portStr);
        } catch (NumberFormatException var3) {
            var3.printStackTrace();
            usage("Could not interpret port number [" + portStr + "].");
        }

        if (configFile.endsWith(".xml")) {
            DOMConfigurator.configure(configFile);
        } else {
            PropertyConfigurator.configure(configFile);
        }

    }

    static {
        cat = Logger.getLogger(SimpleSocketServer.class);
    }
}

  SocketNode源码如下:

package org.apache.log4j.net;

import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.net.SocketException;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.LoggingEvent;

public class SocketNode implements Runnable {
    Socket socket;
    LoggerRepository hierarchy;
    ObjectInputStream ois;
    static Logger logger;

    public SocketNode(Socket socket, LoggerRepository hierarchy) {
        this.socket = socket;
        this.hierarchy = hierarchy;

        try {
            this.ois = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
        } catch (InterruptedIOException var4) {
            Thread.currentThread().interrupt();
            logger.error("Could not open ObjectInputStream to " + socket, var4);
        } catch (IOException var5) {
            logger.error("Could not open ObjectInputStream to " + socket, var5);
        } catch (RuntimeException var6) {
            logger.error("Could not open ObjectInputStream to " + socket, var6);
        }

    }

    public void run() {
        try {
            if (this.ois != null) {
                while(true) {
                    LoggingEvent event;
                    Logger remoteLogger;
                    do {
                        event = (LoggingEvent)this.ois.readObject();
                        remoteLogger = this.hierarchy.getLogger(event.getLoggerName());
                    } while(!event.getLevel().isGreaterOrEqual(remoteLogger.getEffectiveLevel()));

                    remoteLogger.callAppenders(event);
                }
            }
        } catch (EOFException var36) {
            logger.info("Caught java.io.EOFException closing conneciton.");
        } catch (SocketException var37) {
            logger.info("Caught java.net.SocketException closing conneciton.");
        } catch (InterruptedIOException var38) {
            Thread.currentThread().interrupt();
            logger.info("Caught java.io.InterruptedIOException: " + var38);
            logger.info("Closing connection.");
        } catch (IOException var39) {
            logger.info("Caught java.io.IOException: " + var39);
            logger.info("Closing connection.");
        } catch (Exception var40) {
            logger.error("Unexpected exception. Closing conneciton.", var40);
        } finally {
            if (this.ois != null) {
                try {
                    this.ois.close();
                } catch (Exception var35) {
                    logger.info("Could not close connection.", var35);
                }
            }

            if (this.socket != null) {
                try {
                    this.socket.close();
                } catch (InterruptedIOException var33) {
                    Thread.currentThread().interrupt();
                } catch (IOException var34) {
                    ;
                }
            }

        }

    }

    static {
        logger = Logger.getLogger(SocketNode.class);
    }
}

  由于有现成的例子,所以说我们直接调用就可以了,其调用的方法如下:

java org.apache.log4j.net.SocketServer port configFile directory

  我本地的调用如下:

F:\Test2\log4j-parent\log4j-SocketAppender\src\main\resources> java -cp log4j-1.2.17.jar org.apache.log4j.net.SocketServer 4560 F:\Test2\log4j-parent\log4j-SocketAppender\src\main\resources\log4j.properties F:\Test2\log4j-parent\log4j-SocketAppender\src\main\resources

SocketClient

  在客户端的使用方式和之前的其它log4j方法本身并没有太大的不同,所以说直接上代码。

log4j.properties配置文件

log4j.rootCategory=info,stdout,Socket

###################
# Console Appender
# 将信息输出到控制台中
###################
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %d{yyyy-MM-dd HH:mm:ss} %5p %t %-5l - %m%n

####################
# Socket Appender
# SocketAppender是一个OutputStreamAppender,它将输出写到一个由主机和端口指定的远程目的地。
# 数据可以通过TCP或UDP发送,可以以任何格式发送。您可以选择使用SSL来保护通信。
####################
log4j.appender.Socket=org.apache.log4j.net.SocketAppender
#指定日志消息的输出最低层次。
log4j.appender.Socket.Threshold=INFO
#远程主机地址(通常是ip地址)
log4j.appender.Socket.RemoteHost=localhost
#远程主机的端口号
log4j.appender.Socket.Port=4560
#应用程序的名称
log4j.appender.Socket.Application=localclient
log4j.appender.Socket.LocationInfo=true

SocketClientTest测试代码

package com.lyc.log4j;

import org.apache.log4j.Logger;
import org.junit.Test;

public class SocketClientTest {

    private static final Logger log = Logger.getLogger(SocketClientTest.class);

    @Test
    public void testSocketAppender() throws Exception{
        for (int i = 0; i < 10; i++) {
            log.warn("this is the message.");
            log.debug("this is the message.");
            log.info("this is the message.");
        }
    }

}

运行结果

这里写图片描述

源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值