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="xx@xx.com"/>
<property name="smtpPort" value="25"/>
<property name="password" value="xx"/>
<property name="SSL" value="false"/>
<property name="email_to" value="xx@xx.com"/>
<property name="email_from" value="xx@xx.com"/>
<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,滚动条拉到最下面,显示及操作如下:
本文已同步更新到公众号,沟通交流请关注公众号。