通過JMX以HTTP的方式動態管理Logback的配置
對Logback的配置基本瞭解後,我們在實際專案中就可以應用它,不知大家有沒有碰到這樣一種業務,使用JMX動態管理Logback的配置(對JMX不瞭解的,建議上網搜尋相關資料),而無需重啟伺服器。好在Logback內部實現了JMX,我們只需在logback.xml中新增<jmxConfigurator />這樣一條配置就可以在Jconsole中進行管理,如下圖:
總共有六個方法:
我們可以寫個執行緒讓主程式不斷執行並列印日誌,然後通過JConsole修改日誌的級別,輸出不同的日誌資訊。
然而瞭解JMX的人都知道,JMX管理Mbean有一種是基於Http的。
從官網下載logback的jar包,我們觀察logback內部原始碼的JM
開啟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:
ReloadConfigJmx.java 編寫JMX服務端(註冊服務 註冊連線)<?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>
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的拼寫,這塊我已經實現,有興趣的可以給我留言。