log4j如何加载、log4j如何使用…

2023-02-27 13:07 30次浏览 攻略

在某些情况下,您需要自定义log4j的输出格式,而不影响前面的代码。

例如这样的需求,硬性规定了项目的日志格式为:

日期 日志等级 ClassName:line – [版本号] [请求ip地址] [项目应用名称] [服务接口模块] [模块方法] [业务参数1] [业务参数2] [业务参数3] 日志详细内容(必须为json格式)

示例:

2018-05-10 14:04:50,972 INFO ViolationService:51 – [v1.0.0] [192.168.137.47] [merc] [OrderController] [messageList] [null] [] [] {"body":"订单状态消息列表resp:{"code":1000,"msg":"成功"}"}

其中:

版本号是指当前服务接口实际的版本信息,例如V1.0.1;

请求ip地址为用户真实的请求ip;

项目应用名称为项目的名称或者标识,例如支付服务定义应用名称为payService;

服务接口模块是指请求接口对应的模块代码,例如请求订单接口,则接口模块为OrderControlller;

模块方法是指接口对应的请求方法,例如下单接口对应模块方法为createOrder;

业务参数1可根据实际情况写入相应的业务数据,录入订单号orderId,该参数可为空;

业务参数2同上;

业务参数3同上;

日志详细内容是指请求接口时需打印出来的描述信息,例如创建订单异常时,在异常捕捉方法体中描述异常详细信息,日志内容需定义到一个json结构中。

以上是我遇到的场景,这时在不影响原有项目代码的基础上,我们做出日志格式的调整,使用如下方案:

1.通过log4j的占位替换符%X{}配合MDC格式化日志,使用AOP切面在请求线程开始处填充替换符变量

2.继承log4j的具体appender类,重写subAppend方法,修改日志输出的内容格式。

此时log4j文件如下

  1. log4j.rootCategory=INFO, stdout, file, errorfile
  2. #log4j.ca
  3. log4j.logger.error=errorfile
  4. log4j.a
  5. log4j.a
  6. log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L%X{log_version}%X{log_ip}%X{log_item}%X{log_module}%X{log_method}%X{log_req_params} %m%n
  7. log4j.a
  8. log4j.a${log.dir}/${}.log
  9. log4j.a;.'yyyy-MM-dd
  10. log4j.a
  11. log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L%X{log_version}%X{log_ip}%X{log_item}%X{log_module}%X{log_method}%X{log_req_params} %m%n
  12. log4j.a
  13. log4j.a${log.dir}/${}_error.log
  14. log4j.a;.'yyyy-MM-dd
  15. log4j.a = ERROR
  16. log4j.a
  17. log4j.appender.errorfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L%X{log_version}%X{log_ip}%X{log_item}%X{log_module}%X{log_method}%X{log_req_params} %m%n

在log4j.properties文件,我们做了两个变动,一个是添加了%X{value}的变量,另一个则是将原本的DailyRollingFileAppender修改成了com.。

处理log4j的变量,对代码进行controller切面,在一个http请求java的入口中放入线程变量,该线程变量在当次http请求生命周期内生效。

切面代码如下:

  1. @Around("execution(public * com…*.*(..))")
  2. public Object aroundController(ProceedingJoinPoint joinPoint) {
  3. ServletrequestAttributes attributes =(ServletRequestAttributes) Reque();
  4. HttpServletRequest request =a();
  5. String execIp = reque("X-Real-IP");
  6. i(execIp)){
  7. execIp=reque();
  8. }
  9. String execClass= joinPoint.getTarget().getClass().getSimpleName();
  10. String execMethod = joinPoint.getSignature().getName();
  11. Map<String,String[]> map = reque();
  12. List<String> paramsList = new ArrayList<>();
  13. for;String,String []> m : map.entrySet()){
  14. String [] value = m.getValue();
  15. ( m.getKey() + "=" + S(value,","));
  16. }
  17. String execParams = "[" + S(paramsList,"&") + "] [] []";
  18. MDC.put("log_version"," – [V1.0.0]");
  19. MDC.put("log_item"," [violation-mini]");
  20. MDC.put("log_module"," [" + execClass + "]");
  21. MDC.put("log_method"," [" + execMethod+ "]");
  22. MDC.put("log_req_params"," " + execParams);
  23. MDC.put("log_ip"," [" + execIp+ "]");
  24. Object result= null;
  25. try {
  26. result = joinPoint.proceed();
  27. } catch (Throwable throwable) {
  28. LOGGER.error("方法异常:",throwable);
  29. }
  30. return result;
  31. }

至此,格式中的MDC变量都已被放入成功。

下一步,将原本的日志内容套上json外套。

新建GrayLogConsoleAppender类继承具体的appender类

代码如下:

  1. package com.;
  2. import net.;
  3. import org.a;
  4. import org.a;
  5. import org.a;
  6. import org.a;
  7. import java.lang.re;
  8. /**
  9. * @Author: Lxx
  10. * @Description:
  11. * @Date: Created in 17:29 2018/5/30
  12. */
  13. public class GrayLogConsoleAppender extends ConsoleAppender {
  14. @Override
  15. protected void subAppend(LoggingEvent event) {
  16. try {
  17. Class<LoggingEvent> clazz = LoggingEvent.class;
  18. Field filed = clazz.getDeclaredField("throwableInfo");
  19. (true);
  20. Object exception = (event);
  21. JSONObject json = new JSONObject();
  22. if(exception != null){
  23. if(exception instanceof ThrowableInformation){
  24. ThrowableInformation throwableInformation = (ThrowableInformation) exception;
  25. String [] details = ();
  26. String error_msg = S(details,"rn");
  27. j("exception",error_msg);
  28. }
  29. }
  30. (event,null);
  31. boolean flag = false;
  32. Field filed1 = clazz.getDeclaredField("message");
  33. (true);
  34. Object message = (event);
  35. if (message instanceof String) {
  36. String msg = (String) message;
  37. if (message != null) {
  38. flag = true;
  39. }
  40. j("body", msg);
  41. (event, j());
  42. }
  43. if(!flag){
  44. Field filed2 = clazz.getDeclaredField("renderedMessage");
  45. (true);
  46. Object message2 = (event);
  47. if (message2 instanceof String) {
  48. String msg = (String) message2;
  49. j("body", msg);
  50. (event, j());
  51. }
  52. }
  53. } catch (Exception e) {
  54. e.printStackTrace();
  55. }
  56. (event);
  57. }
  58. }

至此,已为日志内容套上json外套,并且当有异常日志时,将异常的堆栈信息放入json的exception中输出出来,不打印堆栈信息。

最终结果:

2018-06-09 00:48:31,849 INFO LogAspect:65 – [V1.0.0] [223.88.53.135] [violation-mini] [TestController] [queryList] [appName=abc&authType=test&avatar=&nickName=&token=asdfasdfadsfasdf&userId=asdfasdfasdfasdf&userType=aaaaa] [] [] {"body":"结果为:ResponseResult{code='0', msg='null', errormsg='查询成功', data={}, successFlag=false}"}

相关推荐