1. 程式人生 > >log4j——SocketAppender

log4j——SocketAppender

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

}

執行結果

這裡寫圖片描述

原始碼