巧用CurrentThread.Name来统一标识日志记录(java-logback篇)

java版本支付中心,日志组件使用的是logback。logback.xml里日志pattern配置如下:

    <!--本地日志目录-->
    <property name="USER_HOME" value="${catalina.base}/logs/logback-srv" />
    <property name="LOG_MSG" value="%X{sid}%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p [%c] - %m%n" />
    <property name="LOG_DIR" value="${USER_HOME}/%d{yyyyMMdd}"/>
    <!--2017-08-22 10:43:19.307 [DubboServerHandler-10.0.0.178:38001-thread-187] INFO  [com.emax.paycenter.backend.facade.IPayCenterFacadeImpl]-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_MSG}</pattern>
        </encoder>
    </appender>

pattern里有%t,即代表的是线程Id(起初,我误认为这个%t指的是线程Id!!!),而每一笔交易请求的处理是在一个单独的线程里,那么它就可以标记每一笔交易请求对应的所有日志。日志文件截图如下:

分析日志发现,这个线程标识如截图里的“DubboServerHandler-10.0.0.178:38001-thread-195”会被不同的交易请求重用,不能唯一标记一个线程处理,这显然加大了线上问题的排障难度。昨天晚上,我们项目组里2人决定要针对这一点做一次重构。

之前的.net版支付中心,我对统一标记一笔交易请求的所有日志做过一次重构,见巧用CurrentThread.Name来统一标识日志记录】显然,java的也有必要用一个唯一的标识来标记一笔交易请求的所有日志。

当前线程的线程Id是只读的,我们改不了。那该怎么实现呢?
经验告诉我用currentThread的Name属性来搞。可是问题来了,我在交易处理的第一个语句里给当前线程名赋值后,此后的各module各方法里的每一条log.info语句都要显式记录上当前线程名,改动太多了。而且,这样的代码不免有股怪怪的味道。
当然,另一个办法是按照.net版那种思路,做个日志代理类,对上面的调用log.info并显式记录当前线程名做个封装,然后,逻辑代码里记日志就调用这个代理类。这样实现的弊端与上面的方案半斤八两。

那怎么办呢?

问呗。
先问度娘,无解。
接着问同事,说要自己写一个apperder。对logback底层代码的未知会加大解决问题的难度。
【百度:logback 自定义appender
读logback源码系列文章(五)——Appender http://kyfxbl.iteye.com/blog/1173788】

无心插柳

我早上上班后,先了解了一下构造一个唯一字符串标识来给当前线程名赋值。然后在交易处理的的第一个语句前,写了如下两行代码,

public BaseResponse invoke(String requestJSON, BaseRequest baseRequest) throws Exception {
        String threadName = String.format("%s_%s_%s",
                baseRequest.getMethod(),
                new SimpleDateFormat("HHmmssS").format(new Date()),
                UUID.randomUUID().toString().toUpperCase().substring(0, 5));
        Thread.currentThread().setName(threadName);

        log.info("#IPayCenterFacadeImpl,调用服务:{}", baseRequest.getMethod());
        log.info("#IPayCenterFacadeImpl,请求参数:{}", requestJSON);
        //1.获取API接口实现
        IPayCenterApi payCenterApi = (IPayCenterApi) payCenterServiceFactory.getService(baseRequest.getMethod());

        //2.处理业务逻辑
        BaseResponse result = payCenterApi.handle(requestJSON);

        return result;
    }

不经意间,在运行代码时,我发现%t那段的线程信息标识是我给当前线程名设置的那个字符串标识。
这才发现,%t或%thread输出的原来是产生日志的线程名!!

调试代码发现:Thread.currentThread().getName():DubboServerHandler-192.168.40.80:28005-thread-2,Thread.currentThread().getId():246

经过了这个波折,我们的问题最终得到解决,兴奋异常。看看下面的日志截图,一股强烈的成就感油然而生 O(∩_∩)O

时间: 2024-10-05 23:47:31

巧用CurrentThread.Name来统一标识日志记录(java-logback篇)的相关文章

巧用CurrentThread.Name来统一标识日志记录(完结篇)

上一篇文章<巧用CurrentThread.Name来统一标识日志记录(续)>所述就是<巧用CurrentThread.Name来统一标识日志记录>里改用当前线程名统一记日志后的问题. 我在csdn里也提问了(here and here),很遗憾最终没有查到原因.不过,很欣赏@sp1234大哥中肯的意见: 设计软件,面向业务来设计,例如用一个自定义的变量来保存参数.这样不管这问题中不同的过程被调用时在同一个线程还是不同线程,变量的值都是一致的. 如果“高大上”到过分技术层面,由于我

巧用CurrentThread.Name来统一标识日志记录

先看下面的日志: 2017/5/21 18:00:01 [OrderQuery_180001914_C72FF]请求支付中心参数:{"order_no":"KB201705210000165","sign":"e6c3559cd4b36458b180f15bfcd9b5a5"} 2017/5/21 18:00:01 [OrderQuery_180001914_C72FF]支付中心验签通过. 2017/5/21 18:00:01

巧用CurrentThread.Name来统一标识日志记录(续)

开篇不提前文.本文通过模拟场景来抛出问题. 我在web站点程序里新建一个tmp1.ashx文件.其类代码如下: using System; using System.IO; using System.Threading; using System.Web; namespace PaymentPlatform.Test { /// <summary> /// tmp1 的摘要说明 /// </summary> public class tmp1 : IHttpHandler { pu

通用日志记录(java)

使用AOP记录操作日志信息 添加一个统一处理日志AOP /** * 统一日志处理Handler * @author Mingchenchen * */ public class LogAopHandler { @Autowired private AuditLogDao auditLogDao; /** * controller层面记录操作日志 * 注意此处是aop:around的 因为需要得到请求前的参数以及请求后接口返回的结果 * @throws Throwable */ public Ob

SLF4J - 一个允许你统一日志记录API的抽象层

一.什么是SLF4J 我们在做Java开发时,如果需要记录日志,有很多日志API可供选择,如: java.util.logging Apache log4j logback SLF4J又是个什么东东呢?为什么使用SLF4J比使用log4j或者java.util.logging更好呢?这是因为与所有提到的这些日志记录库相比,SLF4J没有真正地实现日志记录,相反它只是一个允许你使用任何处于后端的日志记录库的 抽象层 . 如果你正在编写内部或者外部使用的API或者应用库的话,那么你真的不需要让使用你

用slf4j统一管理日志总结

参考网页:http://www.slf4j.org/ 一.使用slf4j统一管理并配置统一使用log4j日志 使用的jar:(slf4j-api-1.7.5.jar,jcl-over-slf4j-1.7.5.jar,jul-to-slf4j-1.7.5.jar,slf4j-log4j12-1.7.5.jar,log4j-1.2.12.jar) 因为项目中多个框架使用不同的日志或者现在修改以前项目中的日志框架改用另一种日志,所以使用slf4j统一管理日志会比较方便. 1.slf4j是一个接口标准.

Spring MVC异常统一处理(异常信息的国际化,日志记录)

JAVA EE项目中,不管是对底层的数据操作,还是业务层的处理过程,还是控制层的处理,都不可避免的会遇到各种可预知的(业务异常主动抛出).不可预知的异常需要处理.一般dao层.service层的异常都会直接抛出,最后由controller统一进行处理,每个过程都单独处理异常,且要考虑到异常信息和前端的反馈,代码的耦合度高,不统一,后期维护的工作也多. 同时还必须考虑异常模块和日志模块.国际化的支持. 因此需要一种异常处理机制将异常处理解耦出来,这样保证相关处理过程的功能单一,和系统其它模块解耦,

巧用Logcat把日志记录到文件

在一些开发阶段,产品已经小部分分发出去,在出现问题的时候,我们希望用户能把当时的Logcat日志也发过来提供给程序员进行分析,这里介绍一个巧妙利用logcat命令行进行日志记录的方法,不用自己写日志记录的代码. Android的shell里面提供个logcat的命令,是用来查看系统日志的,这个命令同时支持日志过滤.日志记录到文件,并支持自动日志文件滚动.控制日志文件大小.因此,我们在系统启动的时候,用Runtime调用一下logcat命令,启动一个进程,就可以把我们通过Logcat发的日志记录到

关于日志记录的总结

前段时间,公司的一个项目,需要做很多的数据接口和同步程序,于是就遇到了日志记录的问题,何时记录,如何记录,哪些要记哪些不用记等问题.针对日志记录的问题,经过一系列讨论,终于达成了统一的处理办法.解决了各个模块系统,不同的开发人员,日志记录不统一,随意的问题.今天终于抽出时间把这个问题总结并结合网络上的资料,进行整理. 为什么要记录日志 记录日志是调试程序,监视程序运行的一种重要的方式,主要有两个目的:bug的及时发现和定位,显示程序运行状态.正确详细的日志记录能够快速的定位问题.同样,通过查看日