用户工具

站点工具


分享:技术:log4j:实现log4j打日志带uuid

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

后一修订版
前一修订版
分享:技术:log4j:实现log4j打日志带uuid [2016/12/24 08:41]
gxx 创建
分享:技术:log4j:实现log4j打日志带uuid [2016/12/24 11:12] (当前版本)
gxx
行 1: 行 1:
 ====== 实现log4j打日志带uuid(同一个请求线程同一个uuid) ====== ====== 实现log4j打日志带uuid(同一个请求线程同一个uuid) ======
 ===== 实现思路 ===== ===== 实现思路 =====
 +  - [目标前提]:尽量不改变原有的写法Logger logger = Logger.getLogger(A.class);​
   - 新建Logger子类BaseUuidLogger,重写debug,info等方法;在ThreadLocal中获取同一个uuid;打印日志前带上这个uuid   - 新建Logger子类BaseUuidLogger,重写debug,info等方法;在ThreadLocal中获取同一个uuid;打印日志前带上这个uuid
   - spring能管理到的类(@controller,​@service),使用aop切面,扫描Logger变量强制设置成BaseUuidLogger   - spring能管理到的类(@controller,​@service),使用aop切面,扫描Logger变量强制设置成BaseUuidLogger
行 9: 行 10:
  
 所以,修改log4j配置文件把log4j捕获的类型和行号删除,然后,在BaseUuidLogger中重写的debug,info等方法打印日志前带上ThreadLocal中获取的同一个uuid之前再带上调用BaseUuidLogger的堆栈前面一个类的类名和行号信息。 所以,修改log4j配置文件把log4j捕获的类型和行号删除,然后,在BaseUuidLogger中重写的debug,info等方法打印日志前带上ThreadLocal中获取的同一个uuid之前再带上调用BaseUuidLogger的堆栈前面一个类的类名和行号信息。
-<​code>​+<​code ​java BaseUuidLogger.java>
 package com.shhxzq.fin.lifeapp.model.base;​ package com.shhxzq.fin.lifeapp.model.base;​
  
行 120: 行 121:
 ==== log4j.xml ==== ==== log4j.xml ====
 [%C:​%L]指的是[类名:​行号],因为同一个线程请求打印出同一个uuid,所以把%t(指的是线程名)也去掉了。 [%C:​%L]指的是[类名:​行号],因为同一个线程请求打印出同一个uuid,所以把%t(指的是线程名)也去掉了。
-<​code>​+<​code ​xml log4j.xml>
     <​appender name="​ELP-ALL"​ class="​org.apache.log4j.DailyRollingFileAppender">​     <​appender name="​ELP-ALL"​ class="​org.apache.log4j.DailyRollingFileAppender">​
         <param name="​file"​ value="​${la.log4j.dir}/​lifeapp.log"​ />         <param name="​file"​ value="​${la.log4j.dir}/​lifeapp.log"​ />
行 152: 行 153:
 ==== application-context.xml ==== ==== application-context.xml ====
 配置AOP切面,可以扫描到指定路径下所有@Service注解的服务类 配置AOP切面,可以扫描到指定路径下所有@Service注解的服务类
-<​code>​+<​code ​xml application-context.xml>
  <!-- 服务层AOP begin -->  <!-- 服务层AOP begin -->
  <bean id="​serviceAop"​ class="​com.shhxzq.fin.lifeapp.biz.utils.ServiceAop"​ />  <bean id="​serviceAop"​ class="​com.shhxzq.fin.lifeapp.biz.utils.ServiceAop"​ />
行 165: 行 166:
 ==== spring-mvc.xml ==== ==== spring-mvc.xml ====
 要让AOP扫描到@Controller注解的控制器类(虽然是spring管理,但是AOP默认扫描不到),必须加一行配置 要让AOP扫描到@Controller注解的控制器类(虽然是spring管理,但是AOP默认扫描不到),必须加一行配置
-<​code>​+<​code ​xml spring-mvc.xml>
  <!-- 扫描控制器类 -->  <!-- 扫描控制器类 -->
  <​context:​component-scan base-package="​com.shhxzq.fin.lifeapp"​ />  <​context:​component-scan base-package="​com.shhxzq.fin.lifeapp"​ />
行 174: 行 175:
 ==== ServiceAop.java ==== ==== ServiceAop.java ====
 扫面到切面指向的类和方法时候,程序会进入切面类的实现逻辑:通过反射扫描当前执行对象的Logger类型成员变量,new一个BaseUuidLogger子类对象,把这个Logger类型成员变量的所有属性拷贝赋值给BaseUuidLogger,再反射强制set给这个Logger类型成员变量。 扫面到切面指向的类和方法时候,程序会进入切面类的实现逻辑:通过反射扫描当前执行对象的Logger类型成员变量,new一个BaseUuidLogger子类对象,把这个Logger类型成员变量的所有属性拷贝赋值给BaseUuidLogger,再反射强制set给这个Logger类型成员变量。
-<​code>​+<​code ​java ServiceAop.java>
 package com.shhxzq.fin.lifeapp.biz.utils;​ package com.shhxzq.fin.lifeapp.biz.utils;​
  
行 312: 行 313:
 ==== BeanUtils.java ==== ==== BeanUtils.java ====
 一般采用org.apache.commons.beanutils.BeanUtils.java:​copyProperties(Object dest, Object orig)来拷贝两个对象的相同属性,但是这个类不能拷贝private,protected以及父类的所有属性,所以这里使用反射机制新写一个Bean工具类。 一般采用org.apache.commons.beanutils.BeanUtils.java:​copyProperties(Object dest, Object orig)来拷贝两个对象的相同属性,但是这个类不能拷贝private,protected以及父类的所有属性,所以这里使用反射机制新写一个Bean工具类。
-<​code>​+<​code ​java BeanUtils.java>
 package com.shhxzq.fin.lifeapp.biz.utils;​ package com.shhxzq.fin.lifeapp.biz.utils;​
  
行 405: 行 406:
 ==== BaseUuidLoggerUtils.java ==== ==== BaseUuidLoggerUtils.java ====
 前面配置AOP,那么AOP扫描到的@Service和@Controller自动Logger类型成员变量会变成BaseUuidLogger对象;那脱离了spring管理的其它类就只能还一种方法,使用这个工具类手动获取BaseUuidLogger对象。 前面配置AOP,那么AOP扫描到的@Service和@Controller自动Logger类型成员变量会变成BaseUuidLogger对象;那脱离了spring管理的其它类就只能还一种方法,使用这个工具类手动获取BaseUuidLogger对象。
-<​code>​+<​code ​java BaseUuidLoggerUtils.java>
 package com.shhxzq.fin.lifeapp.biz.utils;​ package com.shhxzq.fin.lifeapp.biz.utils;​
  
行 440: 行 441:
 ==== 用法1 ==== ==== 用法1 ====
 spring能管理到的类(@controller,​@service),使用aop切面,扫描Logger变量强制设置成BaseUuidLogger spring能管理到的类(@controller,​@service),使用aop切面,扫描Logger变量强制设置成BaseUuidLogger
-<​code>​+<​code ​java LaCreditServiceImpl.java>
 /** /**
  * 信用卡服务接口实现类  * 信用卡服务接口实现类
行 456: 行 457:
 } }
 </​code>​ </​code>​
-<​code>​+<​code ​java CreditController.java>
 /** /**
  * 信用卡相关接口  * 信用卡相关接口
行 475: 行 476:
 ==== 用法2 ==== ==== 用法2 ====
 spring管理不到的类,比如util工具类,使用BaseUuidLoggerUtils.getBaseUuidLogger()赋值给Logger变量 spring管理不到的类,比如util工具类,使用BaseUuidLoggerUtils.getBaseUuidLogger()赋值给Logger变量
-<​code>​+<​code ​java HawkeyeUtil.java>
 /** /**
  * 监控工具类  * 监控工具类
行 492: 行 493:
 } }
 </​code>​ </​code>​
-===== 待探讨另一种实现方式 ===== +===== 打印效果 ===== 
-解压log4j.jar,拿到Logger.class(或者父类),使用ASM字节码技术框架,修改debug,info等方法(或者修改这些方法统一调后面的某个方法),在打印信息之前带上uuid(在ThreadLocal中获取同一个uuid)+<​code>​ 
 +2016-12-24 09:​28:​46,​503 INFO [com.shhxzq.fin.lifeapp.biz.utils.ServiceAop.java:​around():​93][uuid:​f9ca7f9e-3d01-4fb3-be1e-30866c598f35] : log - com.shhxzq.fin.lifeapp.biz.impl.credit.LaCreditServiceImpl.queryShowCreditMenu request - {"​acceptMode":"​Mobile","​custNo":"​0000045412","​deviceId":"​BiHo7J4ppFXL8vAmQ3WZ7M"​} 
 +2016-12-24 09:​28:​46,​503 INFO [com.shhxzq.fin.lifeapp.remote.impl.SafeCenterServiceImpl.java:​checkShowCreditMenu():​63][uuid:​f9ca7f9e-3d01-4fb3-be1e-30866c598f35] : 判断用户是否可见信用卡服务请求:​BeidouRiskQueryDO{appName='​LIFEAPP',​ dataMap={}, moduleType=101,​ isMeetBreak=true,​ memberId='​0000045412',​ deviceId='​BiHo7J4ppFXL8vAmQ3WZ7M',​ ip='​null',​ weixin='​null'​} 
 +2016-12-24 09:​28:​46,​505 INFO [com.shhxzq.fin.lifeapp.remote.impl.SafeCenterServiceImpl.java:​checkShowCreditMenu():​78][uuid:​f9ca7f9e-3d01-4fb3-be1e-30866c598f35] : 判断用户能否还款返回:​AccessStatus=[0],​Reason=[null] 
 +2016-12-24 09:​28:​46,​506 INFO [com.shhxzq.fin.lifeapp.biz.utils.ServiceAop.java:​around():​120][uuid:​f9ca7f9e-3d01-4fb3-be1e-30866c598f35] : com.shhxzq.fin.lifeapp.biz.impl.credit.LaCreditServiceImpl.queryShowCreditMenu use time : 0.003s 
 +2016-12-24 09:​28:​46,​506 INFO [com.shhxzq.fin.lifeapp.biz.utils.ServiceAop.java:​around():​130][uuid:​f9ca7f9e-3d01-4fb3-be1e-30866c598f35] : log - com.shhxzq.fin.lifeapp.biz.impl.credit.LaCreditServiceImpl.queryShowCreditMenu response - true 
 +</​code>​ 
 +根据uuid 
 +<​code>​ 
 +grep '​f9ca7f9e-3d01-4fb3-be1e-30866c598f35'​ lifeapp.log --color 
 +</​code>​ 
 +可以查到日志中同一次请求的所有日志 
 +===== [待探讨方式1]ASM字节码技术 ​===== 
 +lifeapp项目运行,自动解压log4j.jar,拿到Logger.class(或者父类),使用ASM字节码技术框架,修改debug,info等方法(或者修改这些方法统一调后面的某个方法),在打印信息之前带上uuid(在ThreadLocal中获取同一个uuid)。使用新实现的ClassLoader类重新加载新的Logger.class创建新对象。 
 +==== 用法 ==== 
 +和原始的Logger对象用法一样 
 +<code java HawkeyeUtil.java>​ 
 +/** 
 + * 监控工具类 
 + * 
 + * @author Gxx 
 + * @since 2016/12/2 
 + */ 
 +public class HawkeyeUtil { 
 + 
 +    /** 
 +     * 日志处理器 
 +     */ 
 +    private static Logger logger = Logger.getLogger(HawkeyeUtil.class);​ 
 +     
 +    ... 
 +
 +</​code>​ 
 +===== [待探讨方式2]修改Log4j源码 ===== 
 +拿出Log4j源码,修改debug,info等方法(或者修改这些方法统一调后面的某个方法),在打印信息之前带上uuid(在ThreadLocal中获取同一个uuid)。重新编译,放到src/​main/​java/​目录下Logger对应的包路径下。 
 +==== 用法 ==== 
 +和原始的Logger对象用法一样 
 +<code java HawkeyeUtil.java>​ 
 +/** 
 + * 监控工具类 
 + * 
 + * @author Gxx 
 + * @since 2016/12/2 
 + */ 
 +public class HawkeyeUtil { 
 + 
 +    /** 
 +     * 日志处理器 
 +     */ 
 +    private static Logger logger = Logger.getLogger(HawkeyeUtil.class);​ 
 +     
 +    ... 
 +
 +</​code>​
分享/技术/log4j/实现log4j打日志带uuid.1482540098.txt.gz · 最后更改: 2016/12/24 08:41 由 gxx