1. 程式人生 > >通過JMX以HTTP的方式動態管理Logback的配置

通過JMX以HTTP的方式動態管理Logback的配置

對Logback的配置基本瞭解後,我們在實際專案中就可以應用它,不知大家有沒有碰到這樣一種業務,使用JMX動態管理Logback的配置(對JMX不瞭解的,建議上網搜尋相關資料),而無需重啟伺服器。好在Logback內部實現了JMX,我們只需在logback.xml中新增<jmxConfigurator />這樣一條配置就可以在Jconsole中進行管理,如下圖:


總共有六個方法:


我們可以寫個執行緒讓主程式不斷執行並列印日誌,然後通過JConsole修改日誌的級別,輸出不同的日誌資訊。

然而瞭解JMX的人都知道,JMX管理Mbean有一種是基於Http

從官網下載logback的jar包,我們觀察logback內部原始碼的JM

X實現。


開啟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的拼寫,這塊我已經實現,有興趣的可以給我留言。