通过jmx动态修改logback的日志级别

个人博客原文地址:http://www.ltang.me/2018/04/02/jmx-logback/

应用上线后常常会面对这样一种困境,即,如果把日志级别开得太高,那么当系统出现问题时不好查,如果把日志级别定得太低,那么硬盘很可能很快就被撑爆了。
这时候我们常常选择先将日志级别定高点,当出现问题时,再调低。大部分时候人们习惯的做法是修改logback.xml配置文件,然后重启应用。
这听起来当然有问题,我应用跑得好好的,用户用着好好的,为什么要重启呢,谁来应对重启时客户的怒火呢?

logback的开发者想得周到啦,他们为用户提供了一种动态修改日志级别的能力,而不需要你重启应用。下面的内容仅作为一次简单尝试:

  1. 修改logback.xml文件

    ...
    <jmxConfigurator/>
    
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %level [%thread] [%class:%line] - %m%n</pattern>
        </encoder>
    </appender>
    ...
    

    实际上我们只是新增了一行<jmxConfigurator/>

  2. 启动应用,观察日志

    2018-04-02 19:23:50 INFO [metrics-logger-reporter-thread-1] [com.codahale.metrics.Slf4jReporter:214] - ....
    2018-04-02 19:23:50 INFO [metrics-logger-reporter-thread-1] [com.codahale.metrics.Slf4jReporter:183] - ...
    2018-04-02 19:24:00 INFO [qbScheduler-4] [com.gzcb.creditcard.fdp.utils.ReturnFileTasksScheduler:34] - 定时扫描返回文件开始执行...
    2018-04-02 19:24:00 INFO [qbScheduler-4] [com.gzcb.creditcard.fdp.utils.ReturnFileTasksScheduler:37] - 当前Web节点不是master,跳过...
    


```
3. 启动jconsole, 连接应用,选择MBean

  1. 找到ch.qos.logback.classic.default目录下的类ch.qos.logback.classic.jmx.JMXConfigurator

  2. 选择操作,选择setLoggerLevel,输入参数,第一个是loggerName,第二个是loggerLevel,点击按钮
    jconsole

  3. 观察日志

    2018-04-02 19:30:27 DEBUG [DefaultQuartzScheduler_QuartzSchedulerThread] [org.quartz.core.QuartzSchedulerThread:276] - ...
    2018-04-02 19:30:50 INFO [metrics-logger-reporter-thread-1] [com.codahale.metrics.Slf4jReporter:214] - ...
    2018-04-02 19:30:50 INFO [metrics-logger-reporter-thread-1] [com.codahale.metrics.Slf4jReporter:183] - ...
    2018-04-02 19:30:56 DEBUG [DefaultQuartzScheduler_QuartzSchedulerThread] [org.quartz.core.QuartzSchedulerThread:276] - ...
    2018-04-02 19:31:00 INFO [qbScheduler-4] [com.gzcb.creditcard.fdp.utils.ReturnFileTasksScheduler:34] - ...
    2018-04-02 19:31:00 INFO [qbScheduler-4] [com.gzcb.creditcard.fdp.utils.ReturnFileTasksScheduler:37] - ...
    2018-04-02 19:31:22 DEBUG [DefaultQuartzScheduler_QuartzSchedulerThread] [org.quartz.core.QuartzSchedulerThread:276] - ...
    

    我们发现本来全是info的日志,突然变成有debug级别输出了。如果再次修改loggerLevel为info,debug日志又消失了。

    基础乞丐版应用就是这么简单,请自行尝试。如果想获取更多内容,自行访问https://logback.qos.ch/manual/jmxConfig.html

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的 JMX 动态 MBean 的例子,该 MBean 可以动态地添加和移除属性、操作和通知等。 首先,需要实现 DynamicMBean 接口,定义 MBean 的属性、操作和通知等。下面是一个简单的实现: ```java public class SimpleDynamicMBean implements DynamicMBean { private Map<String, Object> attributes = new HashMap<String, Object>(); private Map<String, MBeanOperationInfo> operations = new HashMap<String, MBeanOperationInfo>(); private MBeanInfo mbeanInfo; public SimpleDynamicMBean() { // 初始化 MBean 的信息 init(); } // 初始化 MBean 的信息 private void init() { // 添加属性 attributes.put("name", "default"); attributes.put("age", 18); // 添加操作 MBeanParameterInfo[] params = new MBeanParameterInfo[] { new MBeanParameterInfo("name", String.class.getName(), "name of the person"), new MBeanParameterInfo("age", int.class.getName(), "age of the person") }; operations.put("setPerson", new MBeanOperationInfo("setPerson", "set person's name and age", params, void.class.getName(), MBeanOperationInfo.ACTION)); // 构建 MBean 的信息 mbeanInfo = new MBeanInfo(this.getClass().getName(), "SimpleDynamicMBean", null, null, operations.values().toArray(new MBeanOperationInfo[0]), null); } @Override public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { if (!attributes.containsKey(attribute)) { throw new AttributeNotFoundException("Attribute " + attribute + " not found"); } return attributes.get(attribute); } @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { if (!attributes.containsKey(attribute.getName())) { throw new AttributeNotFoundException("Attribute " + attribute.getName() + " not found"); } attributes.put(attribute.getName(), attribute.getValue()); } @Override public AttributeList getAttributes(String[] attributes) { AttributeList resultList = new AttributeList(); for (String attribute : attributes) { try { Object value = getAttribute(attribute); resultList.add(new Attribute(attribute, value)); } catch (Exception e) { e.printStackTrace(); } } return resultList; } @Override public AttributeList setAttributes(AttributeList attributes) { AttributeList resultList = new AttributeList(); for (Object object : attributes) { Attribute attribute = (Attribute) object; try { setAttribute(attribute); String name = attribute.getName(); Object value = getAttribute(name); resultList.add(new Attribute(name, value)); } catch (Exception e) { e.printStackTrace(); } } return resultList; } @Override public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException { if (!operations.containsKey(actionName)) { throw new IllegalArgumentException("Operation " + actionName + " not found"); } MBeanOperationInfo info = operations.get(actionName); return null; } @Override public MBeanInfo getMBeanInfo() { return mbeanInfo; } } ``` 在上面的实现中,我们定义了一个简单的 MBean,包括两个属性(name 和 age)和一个操作(setPerson)。在实现中,我们使用了一个 Map 来保存属性值,使用了一个 Map 来保存操作信息,同时也实现了 DynamicMBean 接口中的其他方法。 下面是一个简单的使用例子,演示如何动态地添加和移除属性、操作和通知等: ```java // 创建一个 MBeanServer MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // 创建一个动态 MBean SimpleDynamicMBean mbean = new SimpleDynamicMBean(); // 将 MBean 注册到 MBeanServer 中 ObjectName name = new ObjectName("mydomain:type=SimpleDynamicMBean"); mbs.registerMBean(mbean, name); // 添加一个属性 mbean.addAttribute("gender", "male"); // 添加一个操作 MBeanParameterInfo[] params = new MBeanParameterInfo[] { new MBeanParameterInfo("gender", String.class.getName(), "gender of the person") }; mbean.addOperation("setGender", "set person's gender", params, void.class.getName(), MBeanOperationInfo.ACTION); // 移除一个属性 mbean.removeAttribute("gender"); // 移除一个操作 mbean.removeOperation("setGender"); // 销毁 MBean mbs.unregisterMBean(name); ``` 在上面的例子中,我们首先创建了一个 MBeanServer,然后创建了一个动态 MBean,并将其注册到 MBeanServer 中。接着,我们动态地添加和移除了一个属性和一个操作,最后销毁了该 MBean。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值