对Logback的配置基本了解后,我们在实际项目中就可以应用它,不知大家有没有碰到这样一种业务,使用JMX动态管理Logback的配置(对JMX不了解的,建议上网搜索相关资料),而无需重启服务器。好在Logback内部实现了JMX,我们只需在logback.xml中添加<jmxConfigurator />这样一条配置就可以在Jconsole中进行管理,如下图:
总共有六个方法:
我们可以写个线程让主程序不断运行并打印日志,然后通过JConsole修改日志的级别,输出不同的日志信息。
然而了解JMX的人都知道,JMX管理Mbean有一种是基于Http的。
从官网下载logback的jar包,我们观察logback内部源码的JMX实现。
打开JMXConfiguratorMBean.java ,发现它就是一个接口
public interfaceJMXConfiguratorMBean {
void reloadDefaultConfiguration() throwsJoranException;
void reloadByFileName(String fileName) throwsJoranException, FileNotFoundException;
void reloadByURL(URL url) throwsJoranException;
void setLoggerLevel(String loggerName, StringlevelStr);
String getLoggerLevel(String loggerName);
String getLoggerEffectiveLevel(StringloggerName);
List<String> getLoggerList();
List<String> getStatuses();
}
正好是我们在Jconsole中操作的方法,那么我们只要将JMXConfigurator注册到JMX中就可以管理logback了,下面通过一个简单例子说明:
logback.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 根节点,设置为调试模式 自动重扫描配置文件 间隔为30秒 -->
<configuration>
<span style="color:#ff0000;"><jmxConfigurator /> </span>
<!-- 定义控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- 定义过滤器 相比logger内定义优先级高 -->
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
<!-- <level>warn</level>-->
<!-- </filter>-->
<!-- 定义日志格式 -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
%date{yyyy-MM-dd HH:mm:ss} %level [%thread] %10logger[%file:%line] - %msg%n
</pattern>
</layout>
</appender>
<!-- 单独对指定的日志设定级别,使该日志对象输出地日志级别限定在:“INFO”级别,不受跟级别的限制 目标可以是类或者包-->
<!-- <logger name="com.ztgame.logback.test" level="info">-->
<!-- <appender-ref ref="SIZE_BASE" />-->
<!-- </logger>-->
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
ReloadConfigJmx.java 编写JMX服务端(注册服务 注册连接)
package cn.gt.logback;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.jmx.JMXConfigurator;
import com.sun.jdmk.comm.HtmlAdaptorServer;
public class ReloadConfigJmx {
public static final String DOMAIN_NAME = "logback_jmx";
public static final String RELOAD_CONFIG_NAME = "reloadConfig";
public static final String CONNECTOR_NAME = "htmlConnector";
private static MBeanServer mBeanServer;
private static JMXConfigurator reloadConfig;
private static HtmlAdaptorServer connector;
private static int port = 8092;
public static void init(LoggerContext loggerContext) throws Exception {
mBeanServer = MBeanServerFactory.createMBeanServer(DOMAIN_NAME);
// 注册服务
ObjectName on = new ObjectName(DOMAIN_NAME + ":name=" + RELOAD_CONFIG_NAME);
reloadConfig = new JMXConfigurator(loggerContext, mBeanServer, on);
mBeanServer.registerMBean(reloadConfig, new ObjectName(DOMAIN_NAME + ":name=" + RELOAD_CONFIG_NAME));
// 注册连接
connector = new HtmlAdaptorServer();
connector.setPort(port);
mBeanServer.registerMBean(connector, new ObjectName(DOMAIN_NAME + ":name=" + CONNECTOR_NAME));
connector.start();
}
public static void destroy() throws Exception {
connector.stop();
mBeanServer = null;
reloadConfig = null;
connector = null;
port = 0;
}
}
启动一个线程,通过http动态修改配置,观察控制台输出。
CommonTest.java
package cn.gt.logback;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
/**
* logback + JMX
* @author gengtao
*/
public class CommonTest {
public static LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
private static Logger logger = lc.getLogger("CONSOLE");
public void run(){
int i =0;
System.out.println(logger.getName());
for(int j = 0; j < 300; j++){
System.out.println("测试第 " + ++i + "次循环,请注意观察控制台输出");
logger.trace("do trace");
logger.debug("do debug");
logger.info("do info");
logger.warn("do warn");
logger.error("do error");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception{
ReloadConfigJmx.init(lc);
CommonTest test =new CommonTest();
test.run();
}
}
然后我们运行这个主函数,eclipse控制台输出为:(只截取了片段)
通过浏览器访问localhost:8092,点击name=reloadConfig,就会看到如下页面:
然后我们设置Logger的级别:
点击setLoggerLevel按钮后会提示操作成功,然后我们测试getLoggerLevel:
点击按钮会看到,设置已经生效:
然后我们回到eclipse控制台观看输出信息(截取片段如下):
info 和 warn级别的信息消失了,事实证明我们实现了Http方式通过JMX管理Logback,其他4个方法,有兴趣的人可以研究一下,和这个类似,比如重载配置,会立即生效。
另外不知大家有没有注意到,当你在浏览器中操作时会自动生成一条连接:
这个连接是JMX自动生成的。在实际开发中我们有可能面临这样一种情况:在linux系统下,我们希望通过Java脚本来达成我们的目的,一条命令就可以动态管理我们的配置,那么这条连接就有作用了,我们自己编写网络连接以及URL的拼写,这块我已经实现,有兴趣的可以给我留言。