log4j 日志服务器配置开发部署
2011-11-21 10:03
525 查看
功能说明
一个系统可能有多个子系统组成,这些子系统都有自己的日志,并且运行在不同的操作系统和主机上,收集这些日志对运营人员来说也比较困难。因此决定在平台中采用日志服务器来做到集中日志管理,平台中所有子系统通过socket方式将日志信息传到日志服务器,再由日志服务器统一记录。这样既避免了一个应用日志不同实例分别打印,也可以将所有子系统日志集中管理,并能够自定义输出路径。
实现原理
Log4j提供了一个简单的基于socket的日志服务器,但直接使用这个服务器不能完全满足我们的需求,首先它自身代码存在问题,需要修改;其次即使修改正确,该服务器也只能按客户端IP配置打印appender,而我们有些子系统是运行在同一主机,直接使用该服务器只能将运行在同一主机上的子系统日志打在一起,不便于分析处理。我们要求按照不同应用输出日志。因此我们要对其进行改造。Log4j提供的日志服务器由SocketServer.java和SocketNode.java实现,我们需要改造这两个类,以达到我们的目的。
Log4j提供的SocketServer利用一个Hashtable的变量hierarchyMap保存各个客户端的log4j配置信息,一旦侦听到某个客户端发送请求过来,则立刻New一个SocketNode来处理该请求,该SocketNode的构造参数中有一个是从hierarchyMap中获取的log4j配置信息,SocketNode将根据该配置信息直接输出客户端发送的日志请求。
改造后的日志服务器, SocketServer仍然利用hierarchyMap保存各个客户端的log4j配置信息,但这次不是基于客户端IP,而是基于应用的,当侦听到某个客户端发送请求过来,则同样New一个SocketNode来处理该请求,hierarchyMap将作为改造后的SocketNode一个构造参数,这样SocketNode自己就能够根据客户端请求内容来决定使用哪个log4j配置信息输出客户端日志请求,这里有个关键就是客户端需要上传信息表明自己是哪个应用。
分析Log4j源码,我们发现可以为SocketAppender配置一个属性application,而这个属性在服务端是可以获取的,SocketNode读取这个属性并自动选择相应的log4j配置信息来处理
更改代码
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. * * <p> * * 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<String, Hierarchy> hashtable; static Logger logger = Logger.getLogger(SocketNode.class); public SocketNode(Socket socket, Hashtable<String, Hierarchy> 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<String, Hierarchy> 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<String, Hierarchy>(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环境,我们可以用如下步骤配置运行环境。
方法一 配置系统变量
打开系统变量文件(.profile),在文件的末尾依次添加以下代码:
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
方法二 配置局部变量
在log4jsocket.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
注:建议使用方法二不影响其它系统
获取安装文件
http://download.csdn.net/detail/zhoulianglg/4025803
获取文件后,解压到要安装的路径。
目录结构
logservers
config
client
default.properties
test1.properties
test2.properties
socketserver.properties
log4j-1.2.16.jar
log4jsocket.bat
log4jsocket.sh
在日志服务器参数配置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
要在client目录添加.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
注:具体配置就跟客户端log4j配置方式一样,这里如何配置log服务器就会按照这里的配置生成log文件
若此处没有配置相应的配置文件 默认执行 default.properties 文件
启用服务器命令
windows 直接双击打开 log4jsocket.bat
unix运行 sh log4jsocket.sh
日志服务器部署地址
IP:192.168.0.14
目录:/home/ifxt/sibas-cs/logservers
客户端
环境要求log4j-1.2.15以上
客户端配置
在log4j.properties中加入
log4j.rootCategory=debug,test
log4j.appender.test=org.apache.log4j.net.SocketAppender
#发送到服务器端的地址
log4j.appender.test.RemoteHost=192.168.0.189
#端口号
log4j.appender.test.Port=8899
log4j.appender.test.LocationInfo=true
#发送过去的参数
log4j.appender.test.application=test
应用步骤
(以windows系统为例)第一步获取安装log4j日志服务器
http://download.csdn.net/detail/zhoulianglg/4025803
获取文件后,解压到你想存放的路径想。如:d:\
第二步为客户端配置连接
打开你要配置的项目的log4j.properties 文件
在log4j.properties中加入
log4j.rootCategory=debug,test
log4j.appender.test=org.apache.log4j.net.SocketAppender
#发送到服务器端的地址
log4j.appender.test.RemoteHost=192.168.0.189
#端口号
log4j.appender.test.Port=8899
log4j.appender.test.LocationInfo=true
#发送过去的参数
log4j.appender.test.application=test
配置服务端
在logservers/config/client 目录下添加一个命名为 test.properties 文件 文件名称与你在客户端配置的
log4j.appender.test.application=test名称相同
具体参考配置
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
注:此处配置作用是log4j服务器把客户端送过来的信息 按照现在的配置模式输出日志,日志模式跟此处配置有关,与客户端原有配置没有关系
此处要没有配置 相应的文件,就会默认 执行 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
注:端口号即为客户端log4j.appender.sibas.Port=8899 配置的端口号
相关文章推荐
- JSP/SERVLET开发应用服务器软件BEA WebLogic的配置和部署
- UBuntu9.10配置Log4j日志服务器
- 学习GO第一天,自我感觉可麻利的开干了-GO语言配置、开发、服务器部署
- 学习GO第一天,自我感觉可麻利的开干了-GO语言配置、开发、服务器部署
- UBuntu9.10配置Log4j日志服务器
- [原]阿里云服务器 操作实战 部署C语言开发环境(vim配置,gcc) 部署J2EE网站(jdk,tomcat)
- log4j无日志生成? 我将一个web项目部署在tomcat server.xml配置文件中,当我启动tomcat是无日志输出。
- JBoss配置学习:概述 ,日志(Log4j),命名服务(NS) ,事务(TM),EJB开发 ,消息服务(JMS)
- UBuntu9.10配置Log4j日志服务器
- [原]阿里云服务器 操作实战 部署C语言开发环境(vim配置,gcc) 部署J2EE网站(jdk,tomcat)
- 在Eclipse中配置Web服务器,并开发部署一个简单的web应用
- 阿里云服务器 操作实战 部署C语言开发环境(vim配置,gcc) 部署J2EE网站(jdk,tomcat)
- 解决VS无法连接到已配置的开发web服务器或者部署在IIS上的web服务打不开的问题
- 【配置阿里云 I】申请配置阿里云服务器,并部署IIS和开发环境,项目上线经验
- linux后台服务器开发环境部署配置和验证(nginx+apache+php-fpm+FASTCGI(C/C++))
- 【Linux 操作系统】阿里云服务器 操作实战 部署C语言开发环境(vim配置,gcc) 部署J2EE网站(jdk,tomcat)
- linux环境下部署tomcat工程,日志不走log4j配置而打印到catalina.out可能的原因
- log4j配置日志服务器
- eclipse进行Web开发环境配置-设置自动部署WEB项目到我们配置的tomcat服务器
- 在CentOS7阿里云服务器部署ThinkPHP5,并配置phpstrom实现同步开发(微信小程序及管理员后端)