设为首页 收藏本站
查看: 676|回复: 0

[经验分享] Tomcat 7基于SocketAppender的日志采集方案

[复制链接]

尚未签到

发表于 2015-8-8 11:44:12 | 显示全部楼层 |阅读模式
  当前系统中的日志由各个独立的Tomcat产生,日志存储的比较分散,不便于管理,而且由于采用将文件写入NAS的方式记录日志,当磁盘出现故障的情况下会导致Tomcat异常。为消除日志实体和Tomcat程序的依赖以及解决日志的管理问题,决定采用基于Socket的远程日志收集方案。
  本方案需要对Tomcat的日志系统做一些改动,具体方案如下:
  一、Tomcat的改造:
  Tomcat原生的日志模块是基于java.util.Logging改造的日志收集器,使用和配置均比较简单,但是不适用于一些复杂的日志记录需求,比如此次的远程日志收集方案。为适应当前的需求,采用Log4j作为日志记录器。
  首先从Tomcat网站找到JULI log4j jar和JULI adapters jar两个链接(http://tomcat.apache.org/download-70.cgi,在extra分类下),下载后得到tomcat-juli.jar和tomcat-juli-adapters.jar两个jar文件,将tomcat-juli.jar拷贝至tomcat安装目录的bin文件夹下覆盖原来的文件,将tomcat-juli-adapters.jar和log4j.jar拷贝至tomcat安装目录的lib文件夹下,同时删除conf文件夹下的logging.properties文件。在lib目录下建立log4j.properties文件,内容如下:
  log4j.rootLogger=INFO,Console,Server   
  
  #Console Appender
  log4j.appender.Console=org.apache.log4j.ConsoleAppender  
  log4j.appender.Console.layout=org.apache.log4j.PatternLayout   
  log4j.appender.Console.layout.ConversionPattern=%d{yy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n   
  
  #Socket Appender
  log4j.appender.Server=org.apache.log4j.net.SocketAppender  
  log4j.appender.Server.Port=4712
  log4j.appender.Server.RemoteHost=192.168.1.200  
  log4j.appender.Server.layout.ReconnectionDelay=10000
  log4j.appender.Server.application=test  #这条的含义下面会说
  
  log4j.logger.org.apache=INFO, Server
  log4j.logger.org.apache.catalina.core=INFO, Server
  log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=INFO, Server
  log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]=INFO, Server
  log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]=INFO, Server
  log4j.logger.org.apache.catalina.session=INFO, Server
  log4j.logger.accessLog=Server
  
  log4j.additivity. accessLog =false
  其中org.apache.log4j.net.SocketAppender就是log4j提供的基于Socket的日志收集器,下边三条分别指定了远程日志采集服务器的端口、IP和重连时间。
  还有一部分是Tomcat的访问日志,由于访问日志是独立配置在server.xml的Valve配置节中,默认如下
  
  我们需要提供自定义的实现用以将访问日志也通过Log4j输出,代码如下:
  package com.surdoc.tomcat.extend.log;
  
  import java.text.DateFormat;
  import java.text.MessageFormat;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  
  import org.apache.catalina.valves.AccessLogValve;
  import org.apache.log4j.Logger;
  
  public class Log4jAccessLogValve extends AccessLogValve {
           private final Logger logger = Logger.getLogger("accessLog");
      protected static final String valveinfo ="com.surdoc.tomcat.extend.log.Log4JAccessLogValve";  
  
      @Override
      public void log(String message) {  
          logger.info(message+"\n");   
      }
  
      @Override
      public String getInfo() {
          return valveinfo;
      }
  
      @Override
      protected void open() {
      }
  }
  将这个类编译后打成名为log4jaccesslogvalve.jar的jar包,放到tomcat安装目录的lib文件夹下,注意在这里将Logger命名为accessLog,与log4j.properties中的log4j.logger.accessLog这个Logger对应,然后将上面提到的server.xml中的访问日志配置改为此类:
  
  至此Tomcat改造完毕。
  二、应用中的日志设置
  我们当前的应用也采用了Log4j作为日志记录器,所以只需要将log4j配置文件中的logger都指向SocketAppender就行,如下:
  log4j.rootLogger=WARN, A1
  
           #Console Appender
  log4j.appender.A1=org.apache.log4j.ConsoleAppender
  log4j.appender.A1.layout=org.apache.log4j.PatternLayout
  log4j.appender.A1.layout.ConversionPattern=%-d{yy-MM-dd HH\:mm\:ss}  [%c\:%L]-[%p] %m%n
  
  #Socket Appender
  log4j.appender.Server=org.apache.log4j.net.SocketAppender  
  log4j.appender.Server.Port=4712
  log4j.appender.Server.RemoteHost=192.168.1.200  
  log4j.appender.Server.layout.ReconnectionDelay=10000
  log4j.appender.Server.application=test
  
  log4j.logger.org.apache=INFO,Server
  log4j.logger.org.hibernate=INFO,Server
  log4j.logger.org.springframework=INFO,Server
  log4j.logger.com.sursen.webdocbase=INFO,Server
  
  三、日志采集服务器
  Log4j中提供了一个简单的日志采集器org.apache.log4j.net.SimpleSocketServer,只需要将监听端口号和server端的配置在启动时传入:
  java -classpath log4j-1.2.17.jar org.apache.log4j.net.SimpleSocketServer 4712 log4j-server.properties
  这里我们监听4712端口,和tomcat的SocketAppender配置一致。
  至于log4j-server.properties这个文件,先看一下内容:
  log4j.rootLogger=WARN,Console
  
  log4j.appender.Console=org.apache.log4j.ConsoleAppender  
  log4j.appender.Console.layout=org.apache.log4j.PatternLayout
  log4j.appender.Console.layout.ConversionPattern=%d{yy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n
  
  log4j.appender.Catalina=org.apache.log4j.DailyRollingFileAppender  
  log4j.appender.Catalina.File=logs/catalina.log   
  log4j.appender.Catalina.layout=org.apache.log4j.PatternLayout  
  log4j.appender.Catalina.layout.ConversionPattern=%d{yyyy.MM.dd HH:mm:ss} %5p %c{1}(%L):? %m%n
  
  log4j.appender.Manager=org.apache.log4j.DailyRollingFileAppender  
  log4j.appender.Manager.File=logs/manager.log
  log4j.appender.Manager.layout=org.apache.log4j.PatternLayout  
  log4j.appender.Manager.layout.ConversionPattern=%d{yyyy.MM.dd HH:mm:ss} %5p %c{1}(%L):? %m%n
  
  log4j.appender.HostManager=org.apache.log4j.DailyRollingFileAppender  
  log4j.appender.HostManager.File=logs/host-manager.log
  log4j.appender.HostManager.layout=org.apache.log4j.PatternLayout  
  log4j.appender.HostManager.layout.ConversionPattern=%d{yyyy.MM.dd HH:mm:ss} %5p %c{1}(%L):? %m%n
  
  log4j.appender.AccessLog=org.apache.log4j.DailyRollingFileAppender  
  log4j.appender.AccessLog.File=logs/accesslog.log
  log4j.appender.AccessLog.layout=org.apache.log4j.PatternLayout  
  log4j.appender.AccessLog.layout.ConversionPattern=%m%n
  
  log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
  log4j.appender.R.File=logs/webdocbaseLog.log
  log4j.appender.R.DatePattern = '.'yyyy-MM-dd
  log4j.appender.R.layout=org.apache.log4j.PatternLayout
  log4j.appender.R.layout.ConversionPattern=%-d{yy/MM/dd HH:mm} [%c:%L]-[%p] %m%nlog4j.appender.file.layout.ConversionPattern=%m
  
  
#Logger

  log4j.logger.org.apache=INFO, Catalina
  log4j.logger.org.apache.catalina.core=INFO, Catalina
  log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=INFO,Catalina
  log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]=INFO,Manager
  log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]=INFO,HostManager
  log4j.logger.accessLog=INFO, AccessLog
  log4j.logger.com.sursen.webdocbase=INFO,R
  和改造之前的log4j配置文件没什么区别,Tomcat和服务器端是通过logger名进行对应的,举个例子:accessLog这个logger会将日志记录到服务器启动目录下的logs文件夹下的accesslog.log文件中,如果现在有两个tomcat:tomcat1和tomcat2,他们都有名为accessLog的logger,服务器端则会将由这两个logger发出的日志都写到logs/accesslog.log这个文件中,这样不便于区分不同tomcat的日志,接下来我们要实现自定义的日志收集器,我们可以通过log4j.appender.Server.application这个参数来标识一个特定的tomcat(甚至只表示一个appender),而这个值用来与服务器端conf目录下的logroot.properties进行对应以确定其日志存储的路径,logroot.properties内容像这样:
  test=logs/test
  test就是log4j.appender.Server.application对应的值,这样凡是标识了test的日志都会记录到logs/test这个文件夹下,对于不同的log4j.appender.Server.application需要有不同的服务器端配置,这些配置均放在服务器启动路径下的config/client文件夹下,其名称与log4j.appender.Server.application这个值也是对应的,比如对于test这个配置名就是test.properties。
  接下来看一下服务器端代码,我们在Log4j提供的SimpleSocketServer基础上进行修改,在Eclipse里新建Java项目,先在项目中加入log4j的源码,因为源码也要做一些修改:
packagecom.surdoc.log4j.extend.server;


import java.io.File;

importjava.io.FileInputStream;

importjava.io.IOException;

importjava.io.InputStream;

importjava.net.InetAddress;

importjava.net.ServerSocket;

import java.net.Socket;

importjava.util.Hashtable;

importjava.util.Properties;

import java.util.Set;


importorg.apache.log4j.Hierarchy;

importorg.apache.log4j.Level;

importorg.apache.log4j.Logger;

importorg.apache.log4j.PropertyConfigurator;

importorg.apache.log4j.spi.RootLogger;


public classDispatchSocketServer {

    static String CLIENT_DIR = "client"; //必须是client文件夹

    static String CONFIG_FILE_EXT = ".properties";//配置文件后缀

    static Logger cat = Logger.getLogger(DispatchSocketServer.class);


    staticDispatchSocketServer server;

static int port;

// key=application, value=hierarchy

   Hashtable hierarchyMap;

    String dir;


    public static void main(Stringargv[]) {

            if (argv.length == 2)

                   init(argv[0], argv[1]);

            else

                   usage("Wrong number of arguments.");

            try {

                   cat.info("Listeningon port " + port);

                   ServerSocket serverSocket = new ServerSocket(port);

                   while (true) {

                            cat.info("Waiting toaccept a new client.");

                            Socket socket =serverSocket.accept();

                            InetAddressinetAddress = socket.getInetAddress();

                            cat.info("Connectedto client at " + inetAddress);

                            cat.info("Startingnew 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" + DispatchSocketServer.class.getName() + " portconfigFile directory");

            System.exit(1);

    }

   

    static voidinitLogFilePath(String configDir){

            Stringconfigpath = configDir + File.separator + "logroot.properties";//路径配置文件

            Propertiesprop = new Properties();

            try {

               InputStreamin = newFileInputStream(configpath);

               prop.load(in);

               in.close();

           } catch (IOException e) {

               e.printStackTrace();

           }

//logroot.properties中的值存入系统变量

            Setkeys = prop.keySet();

            for(Object key:keys){

               Stringk = (String)key;

               Stringv = (String)prop.getProperty(k);

               System.setProperty(k,v);

            }

    }


    static void init(StringsrvPort, String configDir) {

            initLogFilePath(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 = newDispatchSocketServer(configDir);

    }


    publicDispatchSocketServer(String configDir) {

            this.dir = configDir;

            hierarchyMap = newHashtable(11);

           configureHierarchy();

    }




    // This methodassumes that there is no hiearchy for inetAddress


    // yet. It willconfigure one and return it.


    voidconfigureHierarchy() {

            FileconfigFile = new File(dir + File.separator + CLIENT_DIR);

            if(configFile.exists() && configFile.isDirectory()) {

                   String[] clients = configFile.list();

                    for (int i = 0; i

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-95635-1-1.html 上篇帖子: 将mina整合到tomcat中 下篇帖子: Tomcat限制文件上传大小(转)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表