Chinaunix首页 | 论坛 | 博客
  • 博客访问: 783998
  • 博文数量: 738
  • 博客积分: 7000
  • 博客等级: 少将
  • 技术积分: 5000
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-12 09:00
文章分类

全部博文(738)

文章存档

2011年(1)

2008年(737)

我的朋友

分类:

2008-09-12 09:02:23

    引言:
    在开发与生产环境中,我们有时候需要对日志的配置进行动态切换,要调试、监控和检查系统的运行时信息。
   
    一般有两种方法
    1、通过 Spring 的 Log4jConfigListener 在启动时开启定时器进行定时加载配置文件
    2、通过 JMX 动态控制
    以上可以从我的《利用Spring来管理控制自己的应用程序》专题演讲资料中获取到更加详细的信息,包括示例的源程序,地址为
   

    先说一下上面两种方法的不同与缺点:
    1、通过 Spring 的 Log4jConfigListener,则必须在后台打开线程,现定时扫描,然后来定时工作,有点浪费;
    2、通过 JMX 动态控制的则必须供一个管理的端口,不仅有可能端口被占用(当然有个 workaround 来解决它),还有存在等等需要配置这个管理端口进行对外暴露等等。

    虽然上述两种方法存在着一些不足,但是这两种方法在特定的场合下,都可以很好地来利用它进行完美地工作。
    现在,利用它进行封装与扩展,我们可以巧妙地进行定制,并通过 Web Console 界面来更方便地进行动态切换配置信息,而且不需要重新启动正在运行中的应用程序。

    二、分析
    通过分析 Log4jConfigListener,完整的类名为 org.springframework.web.util.Log4jConfigListener ,可以得到动态加载的过程与原理。
    Log4jConfigListener.java

    public class Log4jConfigListener implements ServletContextListener {

     public void contextInitialized(ServletContextEvent event) {
      Log4jWebConfigurer.initLogging(event.getServletContext());
     }

     public void contextDestroyed(ServletContextEvent event) {
      Log4jWebConfigurer.shutdownLogging(event.getServletContext());
     }
    }

    进而可以得知,一切都是由 Log4jWebConfigurer 来进行操作了,再分析其中的代码,可以得到 Log4jWebConfigurer 的工作过程,并由此进行到 Log4jConfigurer 中。
    最后我们可以得到最直接有用的三个方法,分别如下:
    1、Log4jConfigurer.initLogging(location);
    根据给定的配置文件进行初始化日志配置

    2、Log4jConfigurer.initLogging(location, refreshInterval);
    根据给定的配置文件和间隔时间,进行初始化日志配置并定时重新加载配置文件,

    3、Log4jConfigurer.shutdownLogging();
    关闭日志

    根据以上分析,接下来就是需要进行重新封装的工作了,我们同时保留原来的定时加载的功能,但通过开关进行设置,同时对整个功能进行封装与扩展。

    三、封装与扩展
    1、设计一个名为 Log4JRefreshInterval 的 Bean
    1.1 定义如下可配置选项:
     private String CLASSPATH = "classpath:";
     private String location = CLASSPATH + "log4j.xml";
     private String locationRunning = location;
     private long refreshInterval = 60000;
     private long refreshSecond = 0;
     private long refreshMinute = 0;
     private long refreshHour = 0;
     private boolean refreshDaemon = false;

    增加 refreshDaemon 开关,在配置里根据需要要打开是否定时进行加载日志的配置文件;
    增加一系列的时间配置参数,毫秒、秒、分、时,然后对这些时间进行加和,总和为定时的时间
    refreshHour * 3600 * 1000 + refreshMinute * 60 * 1000 + refreshSecond * 1000 + refreshInterval;

    1.2 封装方法如下方法进行控制
    public interface ILog4JRefreshInterval
    {
     public void init(); // 根据配置信息初始化日志
     public void destroy(); // 销毁日志
     public void refreshIntervalThread(); // 定时加载日志的配置信息
     public void refreshIntervalImmediately(); // 立即加载默认的日志配置信息
     public void refreshIntervalImmediatelyByFilePath(String log4jFilePath); // 立即加载指定的日志配置文件

     public void refreshIntervalImmediately(boolean isXmlConfig,String log4jConfigInfo); // 立即加载指定的日志配置文件
     public String getRunningConfing() throws Exception;//获取正在运行的日志配置信息
    }
    1.3 构建页面
      由于将通过 Web Console 页面进行管理控制,也更加方便,当然也可以通过 Web Services 等等之类的,因为 POJO 所以可以根据项目的实际情况来加以选择。
    创建 index.html 文件,代码如下:
   
   
   
    日志动态配置管理控制台
   
   
   
    日志动态配置管理控制台
   


     

配置内容:(两者只取其一)


     

1、Log4J的文件路径,格式如下:


     

         
  • classpath:log4j.properties 或者 classpath:log4j.xml

  •      
  • file:C:/log4j.properties 或者 file:C:/log4j.xml

  •      
  • C:/log4j.properties 或者 C:/log4j.xml

  •      

     

2、Log4J的详细配置信息:


     

配置方式:
     (请根据实际的配置内容选择相应的类型)


     
       
     
   

   

    查看配置信息
      
    立刻重新加载
      
    立刻停止日志
      
    测试是否正常
   
   
    1.4 构建 Controller
      在此示例中直接采用简单易用的 Spring MVC 进行控制。
      直接 implements Controller 来创建三个 Controller ,分别如下:
     Log4JRefreshController  重新加载日志配置文件的控制器
     Log4JShutdownController 关闭日志的控制器
     Log4JRunningController  获取正在运行的日志配置信息的控制器
    1.5 构建一个 Servlet
     用来测试日志配置信息是否成功加载

    public class HelloServlet extends HttpServlet
    {
     private static final long serialVersionUID = -4506255419343502640L;
     private static final Logger logger = Logger.getLogger(HelloServlet.class);

     public void doGet(HttpServletRequest request,HttpServletResponse response)
     {
      try
      {
       ServletOutputStream out = response.getOutputStream();
      out.println("");
       out.println("");
       out.println("");
       out.println("动态配置测试页面");
       out.println("");
       out.println("");
       out.println("\"日志动态配置管理控制台\"/");
       out.println("

Begin:" + new Date() + "
");
       if(logger.isDebugEnabled())
       {
        logger.debug("DEBUG级别的信息:debugging

");
        out.println("DEBUG级别的信息:debugging

");
           }
       if(logger.isInfoEnabled())
       {
        logger.info("INFO级别的信息:information

");
        out.println("INFO级别的信息:information

");
           }
       logger.warn("warning");
       logger.error("error");
       logger.fatal("fatal");
       out.println("End:" + new Date() + "
");
       out.println("

返  回");
       out.println("

");
       out.flush();
      }
      catch(IOException e)
      {
       e.printStackTrace();
      }
     }
    }

[1]    

【责编:Ken】

--------------------next---------------------

阅读(702) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~