首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

JMX兑现Log4J级别的运行时动态更改

2012-11-14 
JMX实现Log4J级别的运行时动态更改首先来介绍一下MBean暴露的接口,主要是根据filter得到logger,设置logger

JMX实现Log4J级别的运行时动态更改

    首先来介绍一下MBean暴露的接口,主要是根据filter得到logger,设置logger的对象,动态的得到当前log4j的配置等,这个比较简单。

import org.apache.log4j.Level;public interface LoggingConfig {/** *  * @param filter returns only loggers, which contain the filter string * @return all available loggers */public String[] getLoggers(String filter);/** * assigns the {@link Level#INFO} to the given class * @param target the FQCN of the class */public void assignInfoLevel(String target);/** * assigns the {@link Level#WARN} to the given class * @param target the FQCN of the class */public void assignWarnLevel(String target);/** * assigns the {@link Level#ERROR} to the given class * @param target the FQCN of the class */public void assignErrorLevel(String target);/** * assigns the {@link Level#DEBUG} to the given class * @param target the FQCN of the class */public void assignDebug(String target);/** * assigns the {@link Level#FATAL} to the given class * @param target the FQCN of the class */public void assignFatalLevel(String target);/** * assigns the {@link Level#TRACE} to the given class * @param target the FQCN of the class */public void assignTraceLevel(String target);/** * deactivates the logging of the given class * @param target the FQCN of the class */public void deactivateLogging(String target);/** * reloads the log4j configuration from the <code>log4j.properties</code> file in the classpath  */public void resetConfiguration();/** *  * @return the log4j configuration from the <code>log4j.properties</code> file in the classpath  */public String printLog4jConfig();


    下面的是它的实现类,实现了NotificationPublisherAware接口,在运行的时候会注入一个NotificationPublisher对象,实现Notification的发送。

import java.io.PrintWriter;import java.io.StringWriter;import java.net.URL;import java.util.ArrayList;import java.util.Enumeration;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.management.Notification;import org.apache.log4j.Level;import org.apache.log4j.LogManager;import org.apache.log4j.Logger;import org.apache.log4j.PropertyConfigurator;import org.apache.log4j.config.PropertyPrinter;import org.apache.log4j.spi.LoggerRepository;import org.springframework.jmx.export.notification.NotificationPublisher;import org.springframework.jmx.export.notification.NotificationPublisherAware;public class LoggingConfigImpl implements LoggingConfig, NotificationPublisherAware {private Map<NotificationType, Long> notificationTypeMap = new HashMap<NotificationType, Long>();private NotificationPublisher publisher;public void setNotificationPublisher(NotificationPublisher notificationPublisher) {        this.publisher = notificationPublisher;    }public String[] getLoggers(String filter) {LoggerRepository r = LogManager.getLoggerRepository();Enumeration<Logger> enumList = r.getCurrentLoggers();Logger logger = null;List<String> resultList = new ArrayList<String>();while (enumList.hasMoreElements()) {logger = (Logger) enumList.nextElement();if (filter == null|| (filter != null && logger.getName().contains(filter))) {resultList.add(logger.getName());}}return (String[]) resultList.toArray(new String[] {});}public void assignInfoLevel(String target) {assignLogLevel(target, Level.INFO);}public void assignWarnLevel(String target) {assignLogLevel(target, Level.WARN);}public void assignErrorLevel(String target) {assignLogLevel(target, Level.ERROR);}public void assignDebug(String target) {assignLogLevel(target, Level.DEBUG);}public void assignFatalLevel(String target) {assignLogLevel(target, Level.FATAL);}public void deactivateLogging(String target) {assignLogLevel(target, Level.OFF);}public void assignTraceLevel(String target) {assignLogLevel(target, Level.TRACE);}private void assignLogLevel(String target, Level level) {String message = level.toString() + " for '" + target + "'";Logger existingLogger = LogManager.exists(target);if(existingLogger != null) {Level currentLevel = existingLogger.getLevel();if(currentLevel == null) {message = "initial to " + message;} else {message = "from " + currentLevel.toString() + " to " + message;}} LogManager.getLogger(target).setLevel(level);sendNotification(NotificationType.CHANGE_LOG_LEVEL, message);}private synchronized void sendNotification(NotificationType notificationType, String message) {Long counter = 0L;if(!notificationTypeMap.containsKey(notificationType))notificationTypeMap.put(notificationType, counter);counter = notificationTypeMap.get(notificationType);notificationTypeMap.put(notificationType, Long.valueOf(counter + 1));Notification notification = new Notification(notificationType.toString(), this, counter);notification.setUserData(message);publisher.sendNotification(notification);}public void resetConfiguration() {ClassLoader cl = getClass().getClassLoader();LogManager.resetConfiguration();URL log4jprops = cl.getResource("log4j.properties");if (log4jprops != null) {PropertyConfigurator.configure(log4jprops);}sendNotification(NotificationType.RESET_CONFIGURATION , "used file: " + log4jprops.getFile());}public String printLog4jConfig() {StringWriter sw = new StringWriter();PrintWriter pw = new PrintWriter(sw);PropertyPrinter pp = new PropertyPrinter(pw);pp.print(pw);// System.out.println(sw.toString());return sw.toString();}}


下面定义的是Notification的类型

public enum NotificationType {     CHANGE_LOG_LEVEL, RESET_CONFIGURATION}


其实最主要的就是下面的配置文件,借助sping的JMX Support,就可以避免了MBean的注册等一些细节。

<!-- Service to set the log level of a class. -->    <bean id="loggingMBean" value-ref="loggingMBean" /></map></property><property name="assembler">      <bean name="code">-Dcom.sun.management.jmxremote-Dcom.sun.management.jmxremote.port=8004-Dcom.sun.management.jmxremote.ssl=false-Dcom.sun.management.jmxremote.authenticate=false-Dcom.sun.management.jmxremote-Dcom.sun.management.jmxremote.port=8004-Dcom.sun.management.jmxremote.ssl=false-Dcom.sun.management.jmxremote.authenticate=true-Dcom.sun.management.jmxremote.access.file=D:/temp/jmxremote.access-Dcom.sun.management.jmxremote.password.file=D:/temp/jmxremote.password


下面我们介绍一下测试,我们构造一个客户端程序,然后使用jconsole调用刚才我们暴露的接口来更改log级别,然后客户端程序的log信息会有相应的调整,然后再jconsole里面可以看到客户端发出的Notification。

public class LetsGo {/** * @param args */public static void main(String[] args) {Test test = new TestImpl();                }}public interface Test {void logAllLogLevels();}import org.apache.log4j.Logger;public class TestImpl implements Test {private static final Logger logger = Logger.getLogger(TestImpl.class);public void logAllLogLevels() {while (true) {try {Thread.currentThread().sleep(500L);} catch (InterruptedException e) {e.printStackTrace();}logger.trace("This is the TRACE logging");logger.debug("This is the DEBUG logging");logger.warn("This is the WARN logging");logger.info("This is the INFO logging");logger.error("This is the ERROR logging");logger.fatal("This is the FATAL logging");}}}


用jconsole连接后,可以找到我们的mbean,然后我们调用mbean暴露的函数,可以看到客户端的日志信息会实时的变化。






1 楼 asialee 2010-03-27   大家没有遇到要动态更改级别的问题吗? 2 楼 calorie520 2010-03-27   曾开发过这样的系统,通过日志控制台,下发日志策略到日志系统中,这些日志策略有:日志记本地,日记写远程文件,日志写数据库,同时可控制只记录某个时间段的日志。这样的项目如果控制台和日志系统都是Java开发的话,很适合使用JMX来控制,当然通过其他协议下发策略也是可以的,当初我们项目就是通过UDP承载syslog协议来做的 3 楼 sw1982 2010-03-27   确实遇到过。。一直没认真研究。 4 楼 nickycheng 2010-03-28   对不起,问下。 log4j在web容器下不是可以自己监控配置文件的更改并做对应的修改吗? 5 楼 spyker 2010-03-28   calorie520 写道曾开发过这样的系统,通过日志控制台,下发日志策略到日志系统中,这些日志策略有:日志记本地,日记写远程文件,日志写数据库,同时可控制只记录某个时间段的日志。这样的项目如果控制台和日志系统都是Java开发的话,很适合使用JMX来控制,当然通过其他协议下发策略也是可以的,当初我们项目就是通过UDP承载syslog协议来做的
去年 自己弄了一个用jmx控制日志  流量监测 系统启动和关闭的东西

日志采用的是sl4j
spring2.0
6 楼 spyker 2010-03-28   logger的filter可以根据包来进行设置
还可以根据logger的内容进行 过滤 
这些是log的设置

jmx控制log可以通过spring很简单的完成 7 楼 spyker 2010-03-28   log对外暴露jmx服务 如果我没有记错的话 应该只是一个设置的问题
你仔细看一看log4j的文档
它的配置文件支持jmx的

热点排行