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

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

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();

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

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();
}


}

[size=medium]
下面定义的是Notification的类型
[/size]

public enum NotificationType {
CHANGE_LOG_LEVEL, RESET_CONFIGURATION
}

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

<!-- 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>


[size=medium]
首先我们先介绍一下运行该程序的系统属性的设置:
[/size]

-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

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

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");
}
}

}

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

[img]http://dl.iteye.com/upload/attachment/225072/8f188cad-cd2f-3cc2-8e3e-8a28f40980fe.png[/img]
[img]http://dl.iteye.com/upload/attachment/225085/af913bd3-42c2-31d9-896b-f021fb9c8cec.png[/img]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值