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.");
}
}
}