引言: 在开发与生产环境中,我们有时候需要对日志的配置进行动态切换,要调试、监控和检查系统的运行时信息。 一般有两种方法 1、通过 Spring 的 Log4jConfigListener 在启动时开启定时器进行定时加载配置文件 2、通过 JMX 动态控制 以上可以从我的《利用Spring来管理控制自己的应用程序》专题演讲资料中获取到更加详细的信息,包括示例的源程序,地址为 http://yulimin.javaeye.com/blog/52354
先说一下上面两种方法的不同与缺点: 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 的 javaBean 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 文件,代码如下: <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>日志动态配置管理控制台</tITle> <link href="facade.css" rel="stylesheet" type="text/css"/> </head> <body> <img src="logger.jpg" alt="日志动态配置管理控制台"/> <form action="log4JRefresh.do" method="post"> <p>配置内容:(两者只取其一)</p> <p><input checked type="radio" name="configMethod" onclick="isXmlConfig.disabled=true;log4jConfigInfo.value='';log4jConfigInfo.disabled=true;log4jFilePath.disabled=false;log4jFilePath.focus();"/>1、Log4J的文件路径,格式如下:<input name="log4jFilePath" ondblclick="this.value='/var/log4j.properties'" size="100"/></p> <ul> <li>classpath:log4j.properties 或者 classpath:log4j.xml</li> <li>file:C:/log4j.properties 或者 file:C:/log4j.xml</li> <li>C:/log4j.properties 或者 C:/log4j.xml</li> </ul> <p><input type="radio" name="configMethod" onclick="log4jFilePath.value='';log4jFilePath.disabled=true;isXmlConfig.disabled=false;log4jConfigInfo.disabled=false;log4jConfigInfo.focus();"/>2、Log4J的详细配置信息:</p> <p>配置方式: <select name="isXmlConfig"> <option value="0" selected>Property</option> <option value="1">XML</option> </select>(请根据实际的配置内容选择相应的类型)</p> <textarea name="log4jConfigInfo" rows="23" cols="123" ondblclick="this.value=''">
# default.layout.ConversionPattern = %t [%c{3}]-[%-5p]:[%L]:%m%n default.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t] [%c{3}]-[%-5p]:[%L]:%m%n
</textarea> <input type="submIT" value="提 交"/> <input type="reset" value="重 置"/> </form> <br> <a href="log4JRunning.do" tITle="查看正在运行的Log4J配置信息。">查看配置信息</a> <a href="log4JRefresh.do" tITle="立刻重新加载通过配置文件加载的Log4J配置信息。">立刻重新加载</a> <a href="log4JShutdown.do" tITle="立刻停止Log4J的服务,所有日志关停。">立刻停止日志</a> <a href="HelloServlet" tITle="调用Servlet来测试Log4J信息是否正常。">测试是否正常</a> </body> </html> 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("<html xmlns=\"http://www.w3.org/1999/xhtml\">"); out.println("<head>"); out.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=GBK\"/>"); out.println("<title>动态配置测试页面</tITle>"); out.println("<link href=\"facade.css\" rel=\"stylesheet\" type=\"text/css\"/>"); out.println("</head><body>"); out.println("<img src=\"logger.jpg\" alt=\"日志动态配置管理控制台\"/>"); out.println("<p>Begin:" + new Date() + "<br/>"); if(logger.isDebugEnabled()) { logger.debug("DEBUG级别的信息:debugging<p>"); out.println("DEBUG级别的信息:debugging</p>"); } if(logger.isInfoEnabled()) { logger.info("INFO级别的信息:information<p>"); out.println("INFO级别的信息:information</p>"); } logger.warn("warning"); logger.error("error"); logger.fatal("fatal"); out.println("End:" + new Date() + "<br/>"); out.println("<p><a href=\"javaScript:history.go(-1)\">返 回</a>"); out.println("</p></body></html>"); out.flush(); } catch(IOException e) { e.printStackTrace(); } } } [1] [2] [3] [4] 下一页 |