ROP与logback 一种多线程下日志管理实践方式

解决痛点

在分布式系统中,无关日志穿行其中,导致我们无法查看整个调用过程;我们可能需要对一个用户的操作进行归类,例如:线程ID+时间戳,或者requestId等。如此我们可以从大量日志中grep中某个用户的操作流程

slf4j与MDC介绍

MDC ( Mapped Diagnostic Contexts ),顾名思义,其目的是为了便于我们诊断线上问题而出现的方法工具类。虽然,Slf4j 是用来适配其他的日志具体实现包的,但是针对 MDC功能,目前只有logback 以及 log4j 支持,或者说由于该功能的重要性,slf4j 专门为logback系列包装接口提供外部调用
主要用到MDC的这几个方法

public class MDC {
  //Put a context value as identified by key
  //into the current thread's context map.
  public static void put(String key, String val);

  //Get the context identified by the key parameter.
  public static String get(String key);

  //Remove the context identified by the key parameter.
  public static void remove(String key);

  //Clear all entries in the MDC.
  public static void clear();
}

一般我们在代码中只需要调用put方法,将对应的值put到线程上下文Map中,然后在使用的地方调用get方法即可使用;对一些线程池的使用场景,我们可能需要清理数据等操作,需要调用clear方法

MDC最简使用示例

public class LogTest {
    private static final Logger logger = LoggerFactory.getLogger(LogTest.class);
    public static void main(String[] args) {
        MDC.put("THREAD_ID", String.valueOf(Thread.currentThread().getId()));
        logger.info("纯字符串信息的info级别日志");
    }
}

logback.xml中配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <property name="log.base" value="${catalina.base}/logs" />

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

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder charset="UTF-8">
            <pattern>[%d{yyyy-MM-dd HH:mm:ss} %highlight(%-5p) %logger.%M\(%F:%L\)] %X{THREAD_ID} %msg%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="console" />
    </root>
</configuration>

于是就输出:

[2018-04-22 15:34:35 INFO  com.zbj.log4j.LogTest.main(LogTest.java:29)] 1 纯字符串信息的info级别日志

在logback.xml中使用%{ }来占位,替换到MDC中对应的MDC的key值

普通Web项目中使用

直接使用Intercept、Filter或者Aspect三者之一即可

ROP框架中使用

需要将新增的拦截器加入到ROP拦截器中,如下所示

    <!--注册拦截器,可配置多个-->
    <rop:interceptors>
        <bean class="com.zbj.**.**Interceptor"/>
    </rop:interceptors>

即在拦截器中的

public class Open**Interceptor extends AbstractInterceptor {

    /**
     * 会设置到logback中 requestId 的值
     */
    private final String SID = "requestId";

    /**
     * 在数据绑定后,服务方法调用前执行该拦截方法
     *
     * @param ropRequest
     */
    @Override
    public void beforeService(RopRequest ropRequest) {
        RopRequestContext ropRequestContext = ropRequest.getRopRequestContext();
        MDC.put(SID, ropRequestContext.getRequestId());
    }

    /**
     * 在数据绑定后,服务方法调用前执行该拦截方法
     *
     * @param ropRequestContext
     */
    @Override
    public void beforeService(RopRequestContext ropRequestContext) {
    }

    /**
     * 在服务执行完成后,响应返回前执行该拦截方法
     *
     * @param ropRequestContext
     */
    @Override
    public void beforeResponse(RopRequestContext ropRequestContext) {
        MDC.remove(SID);
    }

    /**
     * 对method为user.add的方法进行拦截,你可以通过methodContext中的信息制定拦截方案
     *
     * @param ropRequestContext
     * @return
     */
    @Override
    public boolean isMatch(RopRequestContext ropRequestContext) {
        return false;
    }
}

参考文章:
https://blog.csdn.net/liubo2012/article/details/46337063
http://shift-alt-ctrl.iteye.com/blog/2345272
https://blog.csdn.net/sunzhenhua0608/article/details/29175283

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值