動態調整(springMVC+slf4j)log等級(DEBUG/INFO/WARN/ERROR)


1、logback.xml

<pre name="code" class="html"><?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- APP NAME -->
    <property name="APP_NAME" value="template" />
    <!-- 日誌ROOT DIR -->
    <property name="LOG_ROOT_DIR" value="Logs/${APP_NAME}"/>
    <!--  格式化輸出。
       %d/date{HH:mm:ss.SSS}:輸出日誌的打印日誌,模式語法與java.text.SimpleDateFormat 兼容
       %-5p/le/level:級別從左顯示5個字符寬度
       %t/thread	輸出產生日誌的線程名。
       %logger{36} 表示logger名字最長36個字符 爲0表示只輸入logger最右邊點符號之後的字符串
       %F java源文件名 *.java
       %L 行
       %m/msg/message:日誌內容
       %n:換行符 -->
    <property name="ENCODER_PATTERN" value="%d{[yyyy-MM-dd HH:mm:ss]}[%level][%logger{1}:%L] %msg%n" />
    <property name="ENCODING" value="UTF-8"/>

    <contextName>${APP_NAME}</contextName>
    <jmxConfigurator />

    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
        <resetJUL>true</resetJUL>
    </contextListener>

    <!-- 輸出到控制檯 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder charset="${ENCODING}">
            <pattern>${ENCODER_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- appender 是<configuration>的子節點,是負責寫日誌的組件。有兩個必要屬性name和class。name指定appender名稱,class指定appender的全限定名 -->
    <appender name="TEMPLATE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 滾動記錄文件,先將日誌記錄到指定文件,當符合某個條件時,將日誌記錄到其他文件 -->
        <file>${LOG_ROOT_DIR}/template.log</file>
        <encoding>${ENCODING}</encoding>

        <append>true</append> <!--true:日誌被追加到文件結尾,false:清空現存文件,默認是true-->
        <encoder> <!-- 對記錄事件進行格式化 -->
            <pattern>${ENCODER_PATTERN}</pattern>
        </encoder>
        <!--
        過濾器,執行一個過濾器會有返回個枚舉值,即DENY,NEUTRAL,ACCEPT其中之一。
        返回DENY,日誌將立即被拋棄不再經過其他過濾器;
        返回NEUTRAL,有序列表裏的下個過濾器過接着處理日誌;
        返回ACCEPT,日誌會被立即處理,不再經過剩餘過濾器。
        -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>       <!--用於配置符合過濾條件的操作-->
            <onMismatch>DENY</onMismatch>   <!--用於配置不符合過濾條件的操作-->
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_ROOT_DIR}/template_%d{yyyy-MM-dd}.log.gz</fileNamePattern><!-- 壓縮後的文件名設置 -->
        </rollingPolicy>
        <!--日誌文件最大的大小-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <!--日誌異步到數據庫 -->
    <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
        <!--日誌異步到數據庫 -->
        <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
            <!--連接池 -->
            <dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
                <driverClass>com.mysql.jdbc.Driver</driverClass>
                <url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
                <user>root</user>
                <password>root</password>
            </dataSource>
        </connectionSource>
    </appender>

    <!-- 郵件發送相關 -->
    <property name="smtpHost" value="smtp.exmail.qq.com"/>
    <property name="username" value="[email protected]"/>
    <property name="smtpPort" value="25"/>
    <property name="password" value="xx"/>
    <property name="SSL" value="false"/>
    <property name="email_to" value="[email protected]"/>
    <property name="email_from" value="[email protected]"/>
    <property name="email_subject" value="【Error:${APP_NAME}】%logger{20}:%L"/>

    <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
        <smtpHost>${smtpHost}</smtpHost>
        <smtpPort>${smtpPort}</smtpPort>
        <username>${username}</username>
        <password>${password}</password>
        <SSL>${SSL}</SSL>
        <asynchronousSending>false</asynchronousSending>
        <to>${email_to}</to>
        <from>${email_from}</from>
        <subject>${email_subject}</subject>
        <layout class="ch.qos.logback.classic.html.HTMLLayout">
            <pattern>%d{[yyyy-MM-dd HH:mm:ss]}[%level][%logger:%L] %msg</pattern>
        </layout>
        <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>NEUTRAL</onMismatch>
        </filter>
    </appender>
    <!-- 郵件發送相關 -->

    <root level="DEBUG">
        <appender-ref ref="TEMPLATE_FILE"/>
        <appender-ref ref="console"/>
        <!--<appender-ref ref="DB"/>
        <appender-ref ref="EMAIL"/>-->
    </root>

    <!-- 配置獨立包 -->
    <logger name="com.alibaba.dubbo" level="WARN">
        <appender-ref ref="ERROR_FILE"/>
        <appender-ref ref="console"/>
    </logger>
</configuration>


2、Controller

import com.saohuobang.payment.service.JMXConfigService;
import javax.annotation.Resource;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 作者 yaohua.liu
 * 日期 2015-11-24 11:32
 * 說明 日誌等級動態控制接口
 */
@RequestMapping(value = "/log")
@Controller
public class JMXConfigController extends BackdoorController{

    @Resource
    private JMXConfigService JMXConfigService;

    @RequestMapping(value = "/startJMXConfig.api")
    @ResponseBody
    public Object startJMXConfig(@RequestParam(required = false) String port) throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException {
        String result = JMXConfigService.startJMXConfig(port);
        return result;
    }

    @RequestMapping(value = "/stopJMXConfig.api")
    @ResponseBody
    public Object stopJMXConfig() throws Exception {
        String result = JMXConfigService.stopJMXConfig();
        return result;
    }
}

3、Service

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;

/**
 * 作者 yaohua.liu
 * 日期 2015-11-25 13:50
 * 說明 ...
 */

public interface JMXConfigService {

    public String startJMXConfig(String port) throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException;
    public String stopJMXConfig() throws Exception;
}


4、impl實現

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.jmx.JMXConfigurator;
import com.google.common.base.Strings;
import com.saohuobang.payment.service.JMXConfigService;
import com.sun.jdmk.comm.HtmlAdaptorServer;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * 作者 yaohua.liu
 * 日期 2015-11-25 14:23
 * 說明 ...
 */
@Service
public class JMXConfigServiceImpl implements JMXConfigService {

    private Logger logger = LoggerFactory.getLogger(JMXConfigService.class);

    public final String DOMAIN_NAME = "logback_jmx";
    public final String RELOAD_CONFIG_NAME = "reloadConfig";
    public final String CONNECTOR_NAME = "htmlConnector";
    private MBeanServer mBeanServer;
    private JMXConfigurator reloadConfig;
    private HtmlAdaptorServer connector;
    public LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    private int defaultPort = 10110;

    @Override
    public String startJMXConfig(String portStr) throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException {
        mBeanServer = MBeanServerFactory.createMBeanServer(DOMAIN_NAME);

        int port = 0;
        try {
            if (Strings.isNullOrEmpty(portStr)) {
                port = defaultPort;
            } else {
                port = Integer.parseInt(portStr);
            }
        } catch (Exception e) {
            logger.error("格式化JMX端口:{}失敗,使用默認端口:{}", portStr, defaultPort);
            port = defaultPort;
        }
        // 註冊服務
        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();

        return DOMAIN_NAME + ":" + port;
    }

    @Override
    public String stopJMXConfig() throws Exception {
        if (connector != null && connector.isActive()) {
            connector.stop();
        }

        mBeanServer = null;
        reloadConfig = null;
        connector = null;

        return "stop success!";
    }
}

5、訪問:http://127.0.0.1:10001/log/startJMXConfig.api

返回:logback_jmx:10110,說明開通的端口爲10110

頁可以在請求時指定端口:http://127.0.0.1:10001/log/startJMXConfig.api?port=101010


6、打開地址:http://127.0.0.1:10110/

7、點擊name=reloadConfig,跳轉到:http://127.0.0.1:10110/ViewObjectRes//logback_jmx%3Aname%3DreloadConfig,滾動條拉到最下面,顯示及操作如下:






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章