log 4 jログサーバ構成開発導入
1つのシステムには複数のサブシステムが構成されている可能性があります.これらのサブシステムには独自のログがあり、異なるオペレーティングシステムとホスト上で実行され、これらのログを収集することは運営者にとっても困難です.そのため、プラットフォームでログサーバを採用して集中的なログ管理を行うことにし、プラットフォーム内のすべてのサブシステムはsocket方式でログ情報をログサーバに転送し、ログサーバによって統一的に記録する.これにより、1つのアプリケーション・ログの異なるインスタンスがそれぞれ印刷されることを回避したり、すべてのサブシステム・ログを集中的に管理したりして、出力パスをカスタマイズすることができます.
実装の原理
Log 4 jは簡単なsocketベースのログサーバを提供していますが、このサーバを直接使用することは私たちのニーズを完全に満たすことはできません.まず、自身のコードに問題があり、修正する必要があります.次に、修正が正しくても、このサーバはクライアントIP構成に従ってappenderを印刷するしかありませんが、私たちの一部のサブシステムは同じホストで実行されています.このサーバを直接使用すると、同じホストで実行されているサブシステムログを一緒に打つしかなく、分析処理が不便です.異なるアプリケーションに従ってログを出力する必要があります.だから私たちはそれを改造しなければなりません.Log 4 jが提供するログサーバはSocketServerである.JAvaとSocketNode.JAva実装では、この2つのクラスを改造して、私たちの目的を達成する必要があります.Log 4 jが提供するSocketServerは、1つのHashtableの変数hierarchyMapを利用して各クライアントのlog 4 j構成情報を保存し、あるクライアントから要求が送信されたことを検知すると、直ちに新しいSocketNodeがその要求を処理し、このSocketNodeの構造パラメータの1つはhierarchyMapから取得したlog 4 j構成情報である.SocketNodeは、この構成情報に基づいてクライアントから送信されたログ要求を直接出力します.改造されたログサーバでは、SocketServerはhierarchyMapを利用して各クライアントのlog 4 j構成情報を保存しているが、今回はクライアントIPではなくアプリケーションに基づいており、あるクライアントから要求が送信されたことを検知すると、同様にNew 1つのSocketNodeがその要求を処理し、hierarchyMapは改造されたSocketNodeの構造パラメータとして扱われる.これにより、SocketNode自身がクライアント要求内容に基づいて、どのlog 4 j構成情報を使用してクライアントログ要求を出力するかを決定することができ、ここで重要なのは、クライアントがどのアプリケーションであるかを示す情報をアップロードする必要があることである.Log 4 jソースコードを解析すると、SocketAppenderのプロパティアプリケーションを構成できます.このプロパティはサービス側で取得できます.SocketNodeはこのプロパティを読み取り、対応するlog 4 j構成情報を自動的に選択して処理します.
コードの変更
1 SocketNode.java
package org.apache.log4j.net;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.Hashtable;
import org.apache.log4j.Hierarchy;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
/**
*
* Read {@link LoggingEvent} objects sent from a remote client using Sockets
*
* (TCP). These logging events are logged according to local policy, as if they
*
* were generated locally.
*
*
*
* For example, the socket node might decide to log events to a local file and
*
* also resent them to a second socket node.
*
* @author zhoulianglg * */
public class SocketNode implements Runnable {
Socket socket;
ObjectInputStream ois;
Hashtable hashtable;
static Logger logger = Logger.getLogger(SocketNode.class);
public SocketNode(Socket socket, Hashtable hashtable) {
this.socket = socket;
this.hashtable = hashtable;
try {
ois = new ObjectInputStream(new BufferedInputStream(
socket.getInputStream()));
} catch (Exception e) {
logger.error("Could not open ObjectInputStream to " + socket, e);
}
}
public void run() {
LoggingEvent event;
Logger remoteLogger;
try {
if (ois != null) {
while (true) {
// read an event from the wire
event = (LoggingEvent) ois.readObject();
Object application = event.getMDC("application");
if (application != null) {
// get a logger from the hierarchy. The name of the
// logger
// is taken to be the name contained in the event.
if(hashtable.get(application)==null || hashtable.get(application).equals("")){
application="default";
logger.info("Using the default");
}
remoteLogger = hashtable.get(application).getLogger(
event.getLoggerName());
// apply the logger-level filter
if (remoteLogger != null
&& event.getLevel().isGreaterOrEqual(
remoteLogger.getEffectiveLevel())) {
// finally log the event as if was generated locally
remoteLogger.callAppenders(event);
}
}
}
}
} catch (java.io.EOFException e) {
logger.info("Caught java.io.EOFException closing conneciton.");
} catch (java.net.SocketException e) {
logger.info("Caught java.net.SocketException closing conneciton.");
} catch (IOException e) {
logger.info("Caught java.io.IOException: " + e);
logger.info("Closing connection.");
} catch (Exception e) {
logger.error("Unexpected exception. Closing conneciton.", e);
} finally {
if (ois != null) {
try {
ois.close();
} catch (Exception e) {
logger.info("Could not close connection.", e);
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException ex) {
}
}
}
}
}
2 SocketServer.java
package org.apache.log4j.net;
import java.io.File;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Hashtable;
import org.apache.log4j.Hierarchy;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.spi.RootLogger;
public class SocketServer {
static String CLIENT_DIR = "client";
static String CONFIG_FILE_EXT = ".properties";
static Logger cat = Logger.getLogger(SocketServer.class);
static SocketServer server;
static int port;// key=application, value=hierarchy
Hashtable hierarchyMap;
String dir;
public static void main(String argv[]) {
if (argv.length == 2)
init(argv[0], argv[1]);
else
usage("Wrong number of arguments.");
// init("8899", "config");
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();
InetAddress inetAddress = socket.getInetAddress();
cat.info("Connected to client at " + inetAddress);
cat.info("Starting new socket node.");
new Thread(new SocketNode(socket, server.hierarchyMap)).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
static void usage(String msg) {
System.err.println(msg);
System.err.println("Usage: java " + SocketServer.class.getName()
+ " port configFile directory");
System.exit(1);
}
static void init(String srvPort, String configDir) {
try {
port = Integer.parseInt(srvPort);
} catch (java.lang.NumberFormatException e) {
e.printStackTrace();
usage("Could not interpret port number [" + srvPort + "].");
}
PropertyConfigurator.configure(configDir + File.separator
+ "socketserver.properties");
server = new SocketServer(configDir);
}
public SocketServer(String configDir) {
this.dir = configDir;
hierarchyMap = new Hashtable(11);
configureHierarchy();
}
// This method assumes that there is no hiearchy for inetAddress
// yet. It will configure one and return it.
void configureHierarchy() {
File configFile = new File(dir + File.separator + CLIENT_DIR);
if (configFile.exists() && configFile.isDirectory()) {
String[] clients = configFile.list();
for (int i = 0; i < clients.length; i++) {
File client = new File(dir + File.separator + CLIENT_DIR
+ File.separator + clients[i]);
if (client.isFile()) {
Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));
String application = clients[i].substring(0,
clients[i].indexOf("."));
cat.info("Locating configuration file for " + application);
hierarchyMap.put(application, h);
new PropertyConfigurator().doConfigure(
client.getAbsolutePath(), h);
}
}
}
}
}
サービス側
実行環境
jdk:jdk1.5以上(1.5含む)
環境設定
linux環境で実行する場合は、次の手順で実行環境を構成できます.
方法1システム変数を構成するシステム変数ファイル(.profile)を開き、ファイルの最後に次のコードを順に追加します:export JAVA_HOME=/usr/java/jdk 1.5.0(実際のパスに準じて)export CLASSSPATH=$JAVA_HOME/lib.tools.jar:$JAVA_HOME/lib:$JAVA_HOME/jre/lib export PATH=$HOME/bin:$JAVA_HOME/jre/bin:$PATH
方法2ローカル変数をlog 4 jsocket.に構成する.shに環境変数構成#を追加!/bin/sh export JAVA_HOME=/usr/java/jdk1.5.0 export CLASSPATH=$JAVA_HOME/lib.tools.jar:$JAVA_HOME/lib:$JAVA_HOME/jre/lib export PATH=$HOME/bin:$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH java -cp ./log4j-1.2.16.jar org.apache.log4j.net.SocketServer 8899 config注:使用方法2が他のシステムに影響しないことを推奨
インストールファイルの取得
http://download.csdn.net/detail/zhoulianglg/4025803
ファイルを取得したら、インストールするパスに解凍します.
ディレクトリ構造
ログサーバパラメータ構成configディレクトリの下にsocketserverというファイル名を確立する.properties
log4j.rootCategory=debug,lgserver log4j.rootLogger=DEBUG,lgserver
#tool #log4j.appender.lgserver=org.apache.log4j.lf5.LF5Appender #log4j.appender.lgserver.MaxNumberOfRecords=700 #console log4j.appender.lgserver=org.apache.log4j.ConsoleAppender
log4j.appender.lgserver.layout=org.apache.log4j.PatternLayout log4j.appender.lgserver.layout.ConversionPattern=[%d{yyyy-MM-dd HH\:mm\:ss}][%5p][%5t][%l] %m%n
クライアントディレクトリに追加するには.propretiesファイル、ファイル名はクライアントから発動したパラメータ名と同じ例:test.properties log4j.rootLogger=debug,test
log4j.appender.test=org.apache.log4j.DailyRollingFileAppender log4j.appender.test.File=logs/test.log log4j.appender.test.Encoding=GBK log4j.appender.test.layout=org.apache.log4j.PatternLayout log4j.appender.test.DatePattern='.'yyyy-MM-dd log4j.appender.test.layout.ConversionPattern=test%d{yyyy-MM-dd HH:mm:ss}[%24F:%-3L:%-5p]%x %m%n
注意:具体的な構成はクライアントlog 4 jの構成と同様で、ここでlogサーバをどのように構成するかは、ここの構成に従ってlogファイルを生成します.ここでは、対応するプロファイルが構成されていない場合、デフォルトでdefaultを実行します.propertiesファイル
サーバーコマンドの有効化
Windowsは直接ダブルクリックしてlog 4 jsocketを開きます.bat unixはsh log 4 jsocketを実行する.sh
≪ログ・サーバーのデプロイ・アドレス|Log Server Deployment Address|emdw≫
IP:192.168.0.14ディレクトリ:/home/ifxt/sibas-cs/logservers
クライアント
環境要件
log4j-1.2.15以上
クライアント構成
log 4 j.propertiesにlog 4 jを加える.rootCategory=debug,test log4j.appender.test=org.apache.log4j.net.SocketAppender#はサーバ側のアドレスlog 4 jに送信.appender.test.RemoteHost=192.168.0.189#ポート番号log 4 j.appender.test.Port=8899 log4j.appender.test.LocationInfo=true#過去のパラメータlog 4 jを送信.appender.test.application=test
適用手順
(Windowsシステムを例に)
最初のステップはlog 4 jログサーバのインストールを取得する
http://download.csdn.net/detail/zhoulianglg/4025803
ファイルを取得したら、保存したいパスに解凍します.例:d:
ステップ2クライアントへの接続の構成
構成するプロジェクトのlog 4 jを開きます.propertiesファイルはlog 4 j.propertiesにlog 4 jを加える.rootCategory=debug,test log4j.appender.test=org.apache.log4j.net.SocketAppender#はサーバ側のアドレスlog 4 jに送信.appender.test.RemoteHost=192.168.0.189
#ポート番号log 4 j.appender.test.Port=8899 log4j.appender.test.LocationInfo=true#過去のパラメータlog 4 jを送信.appender.test.application=test
サービス・エンドの構成
logservers/config/clientディレクトリの下にtestという名前を追加します.propertiesファイル名とクライアントで構成したlog 4 j.appender.test.アプリケーション=test名と同じ具体的な参照構成log 4 j.rootLogger=debug,test
log4j.appender.test=org.apache.log4j.DailyRollingFileAppender log4j.appender.test.File=logs/test.log log4j.appender.test.Encoding=GBK log4j.appender.test.layout=org.apache.log4j.PatternLayout log4j.appender.test.DatePattern='.'yyyy-MM-dd log4j.appender.test.layout.ConversionPattern=test%d{yyyy-MM-dd HH:mm:ss}[%24F:%-3L:%-5p]%x %m%n
注:ここでの構成はlog 4 jサーバがクライアントから送ってきた情報を現在の構成モードに従ってログを出力する役割を果たし、ログモードはここでの構成と関係があり、クライアントの既存の構成とは関係がないここで対応するファイルを構成しなければdefaultがデフォルトで実行される.propertiesファイル
ログサービスの開始
コマンドjava-cp./の実行log4j-1.2.16.jar org.apache.log4j.net.SocketServerポート番号構成ディレクトリ例:java-cp./log4j-1.2.16.jar org.apache.log4j.net.SocketServer 8899 config
注:ポート番号はクライアントlog 4 jである.appender.sibas.Port=8899構成のポート番号