异步线程里的日志不好追踪?小支一招,轻松搞定!

打印 上一主题 下一主题

主题 913|帖子 913|积分 2739

众所周知,通过唯一的链路id来追踪一次请求的所有日志,对于排查生产问题来说,会是非常给力的。
这个比较容易实现。我之前的博客也有多次提及。
那么,如果涉及到异步线程处理的话,我们知道,由于异步线程与工作线程是两个不同的线程,因此,这时的线程名会发生变化。一次请求的完整日志就无法通过唯一的标识来过滤了。
 
有没有办法呢?
问题即答案。当然是有的。
 
线程是用来执行任务的,任务是一段程序代码的封装。在java中,任务通过 java.lang.Runnable 来表示。使用方面,我们可以自己定义一个实现Runnable的任务类,也可以用lambda表达式的方式直接使用Runnable,来作为线程或线程池的参数。
 
自定义实现了Runnable的类来使用异步线程,先贴demo代码。
实现了Runnable接口的类--MyTask:
  1. package com.emaxcard.test;
  2. import lombok.extern.slf4j.Slf4j;
  3. @Slf4j
  4. public class MyTask implements Runnable {
  5.     String flag;
  6.     public MyTask(String flag) {
  7.         this.flag = flag;
  8.     }
  9.     @Override
  10.     public void run() {
  11.         log.info("这是异步线程里的日志。参数flag={}", flag);
  12.     }
  13. }
复制代码
View Code主线程测试类:
  1. package com.emaxcard.test;
  2. import lombok.extern.slf4j.Slf4j;
  3. @Slf4j
  4. public class RunnableTest {
  5.     public static void main(String[] args) {
  6.         log.info("主线程begin");
  7.         new Thread(new MyTask("参数值test")).start();
  8.         log.info("主线程end");
  9.     }
  10. }
复制代码
View Code 
打印出来的log如下:
16:11:27.613 [main] INFO com.emaxcard.test.RunnableTest - 主线程begin
16:11:27.629 [main] INFO com.emaxcard.test.RunnableTest - 主线程end
16:11:27.630 [Thread-0] INFO com.emaxcard.test.MyTask - 这是异步线程里的日志。参数flag=参数值test
我们希望看到的日志是:
16:11:27.613 [main] INFO com.emaxcard.test.RunnableTest - 主线程begin
16:11:27.629 [main] INFO com.emaxcard.test.RunnableTest - 主线程end
16:11:27.630 [main] INFO com.emaxcard.test.MyTask - 这是异步线程里的日志。参数flag=参数值test
小支一招,轻松搞定。给 MyTask 加点料,代码如下。这样就能实现?是的,因为构造MyTask对象的操作发生在当前工作线程,也就是说,MyTask构造器的代码是在工作线程里执行的,正是基于这一点。
  1. package com.emaxcard.test;
  2. import lombok.extern.slf4j.Slf4j;
  3. @Slf4j
  4. public class MyTask implements Runnable {
  5.     String flag;
  6.     String threadName;
  7.     public MyTask(String flag) {
  8.         this.flag = flag;
  9.         this.threadName = Thread.currentThread().getName();
  10.     }
  11.     @Override
  12.     public void run() {
  13.         Thread.currentThread().setName(threadName);
  14.         log.info("这是异步线程里的日志。参数flag={}", flag);
  15.     }
  16. }
复制代码
 
同样,用lambda表达式使用Runnable来使用异步线程,传递线程名,也很简单。贴出来上面的 RunnableTest 的代码。
  1. package com.emaxcard.test;
  2. import lombok.extern.slf4j.Slf4j;
  3. @Slf4j
  4. public class RunnableTest {
  5.     public static void main(String[] args) {
  6.         log.info("主线程begin");
  7.         String name = Thread.currentThread().getName();
  8.         new Thread(new Runnable() {
  9.             @Override
  10.             public void run() {
  11.                 Thread.currentThread().setName(name);
  12.                 log.info("这是异步线程里的日志");
  13.             }
  14.         }).start();
  15.         log.info("主线程end");
  16.     }
  17. }
复制代码
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

美食家大橙子

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表