浏览 8518 次
锁定老帖子 主题:JMX实现Log4J级别的运行时动态更改
精华帖 (1) :: 良好帖 (3) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-03-26
最后修改:2010-03-27
首先来介绍一下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" class="de.stefanheintz.log.jmxservice.LoggingConfigImpl"/> <bean id="exporterLogConfig" class="org.springframework.jmx.export.MBeanExporter"> <property name="beans"> <map> <entry key="de.stefanheintz.log:jmxservice=loggingConfiguration" value-ref="loggingMBean" /> </map> </property> <property name="assembler"> <bean class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler"> <property name="managedInterfaces"> <value>de.stefanheintz.log.jmxservice.LoggingConfig</value> </property> </bean> </property> </bean> 首先我们先介绍一下运行该程序的系统属性的设置: -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暴露的函数,可以看到客户端的日志信息会实时的变化。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-03-27
大家没有遇到要动态更改级别的问题吗?
|
|
返回顶楼 | |
发表时间:2010-03-27
曾开发过这样的系统,通过日志控制台,下发日志策略到日志系统中,这些日志策略有:日志记本地,日记写远程文件,日志写数据库,同时可控制只记录某个时间段的日志。这样的项目如果控制台和日志系统都是Java开发的话,很适合使用JMX来控制,当然通过其他协议下发策略也是可以的,当初我们项目就是通过UDP承载syslog协议来做的
|
|
返回顶楼 | |
发表时间:2010-03-27
确实遇到过。。一直没认真研究。
|
|
返回顶楼 | |
发表时间:2010-03-28
对不起,问下。 log4j在web容器下不是可以自己监控配置文件的更改并做对应的修改吗?
|
|
返回顶楼 | |
发表时间:2010-03-28
calorie520 写道 曾开发过这样的系统,通过日志控制台,下发日志策略到日志系统中,这些日志策略有:日志记本地,日记写远程文件,日志写数据库,同时可控制只记录某个时间段的日志。这样的项目如果控制台和日志系统都是Java开发的话,很适合使用JMX来控制,当然通过其他协议下发策略也是可以的,当初我们项目就是通过UDP承载syslog协议来做的
去年 自己弄了一个用jmx控制日志 流量监测 系统启动和关闭的东西 日志采用的是sl4j spring2.0 |
|
返回顶楼 | |
发表时间:2010-03-28
logger的filter可以根据包来进行设置
还可以根据logger的内容进行 过滤 这些是log的设置 jmx控制log可以通过spring很简单的完成 |
|
返回顶楼 | |
发表时间:2010-03-28
log对外暴露jmx服务 如果我没有记错的话 应该只是一个设置的问题
你仔细看一看log4j的文档 它的配置文件支持jmx的 |
|
返回顶楼 | |