跟踪在多线程异步系统中传递

小夏 科技 更新 2024-01-29

j**a 线程异步的常见实现有:

new thread

executorservice

当然,还有其他的,例如:fork-join下面会提到这些,下面主要针对这两个场景结合ddtrace和springboot练习。

1.8 1.21.0 com.datadoghq dd-trace-api $ io.opentracing opentracing-api 0.33.0 io.opentracing opentracing-mock 0.33.0 io.opentracing opentracing-util 0.33.0 ..
有关如何使用 DDTtrace SDK 的文档,请参阅文档ddtrace-api使用说明。

配置logback让它输出traceidspanid,将如下pattern适用于所有人appender中间。

如果生成了链路,则会在日志中输出跟踪信息。 

实现一个简单的接口来使用logback输出日志信息并观察日志输出。

@requestmapping("/thread") @responsebody public string threadtest()
请求后,日志如下。

2023-10-23 11:33:09.983 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.calcfilter - dofilter,28] springboot-server 7209831467195902001 958235974016818257 - start /threadhost localhost:8086connection keep-aliveuser-agent apache-httpclient/4.5.14 (j**a/17.0.7)accept-encoding br,deflate,gzip,x-gzip2023-10-23 11:33:10.009 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,277] springboot-server 7209831467195902001 2587871298938674772 - this func is threadtest.2023-10-23 11:33:10.022 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.calcfilter - dofilter,34] springboot-server 7209831467195902001 958235974016818257 - 结束: 线程时间: 39
日志中生成了跟踪信息traceidspanid向接口添加新线程以创建线程。

@requestmapping("/thread") @responsebody public string threadtest())start();return "success"; }
通过请求相应的 URL 来观察日志输出。

2023-10-23 11:40:00.994 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,277] springboot-server 319673369251953601 5380270359912403278 - this func is threadtest.2023-10-23 11:40:00.995 [thread-10] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,279] springboot-server - this is new thread.
通过日志输出发现,new thread方式,并且无法输出trace信息,即trace它没有通过。

如果我们显示看跌期权trace可以把信息传进来吗,就去做吧。

threadlocal当前线程唯一的局部线程变量。

为了便于使用,让我们创建一个实用程序类threadlocalutil

public static final threadlocal thread_local = new threadlocal<>(
然后,将当前跨度信息存储到threadlocal

@requestmapping("/thread") @responsebody public string threadtest()",globaltracer.get().activespan().context().totraceid())new thread(()",threadlocalutil.getvalue())start();return "success"; }
通过请求相应的 URL 来观察日志输出。

2023-10-23 14:14:02.339 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,278] springboot-server 4492960774800816442 4097884453719637622 - this func is threadtest.2023-10-23 14:14:02.340 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,280] springboot-server 4492960774800816442 4097884453719637622 - current traceid:44929607748008164422023-10-23 14:14:02.341 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,283] springboot-server - this is new thread.2023-10-23 14:14:02.342 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,284] springboot-server - new thread get span:null
在新线程中获取外部线程threadlocal,得到的值为null通过分析threadlocal源代码是在我们使用threadlocalset()方法threadlocal我在内部使用它thread.currentthread()原来如此threadlocal数据存储key,即从新线程获取变量信息时,key有一个变化,所以我不能接受一个值。

public class threadlocal else }public t get() return setinitialvalue();
inheritablethreadlocal扩大threadlocal提供从父线程到子线程的值继承: 创建子线程时,子线程将接收父线程具有值的所有可继承线程局部变量的初始值。

官方解释:

this class extends threadlocal to provide inheritance of values from parent thread to child thread: when a child thread is created, the child receives initial values for all inheritable thread-local variables for which the parent has values. normally the child's values will be identical to the parent's; however, the child's value can be made an arbitrary function of the parent's by overriding the childvalue method in this class.inheritable thread-local variables are used in preference to ordinary thread-local variables when the per-thread-attribute being maintained in the variable (e.g., user id, transaction id) must be automatically transmitted to any child threads that are created.note: during the creation of a new thread, it is possible to opt out of receiving initial values for inheritable thread-local variables.
为了便于使用,让我们创建一个实用程序类inheritablethreadlocalutil.j**a存储跨度信息。

public static final inheritablethreadlocal thread_local = new inheritablethreadlocal<>(
threadlocalutil将其替换为inheritablethreadlocalutil

@requestmapping("/thread") @responsebody public string threadtest()",globaltracer.get().activespan().context().totraceid())new thread(()",inheritablethreadlocalutil.getvalue())start();return "success"; }
通过请求相应的 URL 来观察日志输出。

2023-10-23 14:37:05.415 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,278] springboot-server 8754268856419787293 5276611939997441402 - this func is threadtest.2023-10-23 14:37:05.416 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,280] springboot-server 8754268856419787293 5276611939997441402 - current traceid:87542688564197872932023-10-23 14:37:05.416 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,283] springboot-server - this is new thread.2023-10-23 14:37:05.417 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,284] springboot-server - new thread get span:datadog.trace.instrumentation.opentracing32.otspan@712ad7e2
通过观察上述日志信息,线程已经获取到了span对象地址,但日志pattern部分不是trace信息输出,原因是,ddtracelogbackge***cpropertymap()ge***c()方法并添加跟踪信息putmdc中间。

@advice.onmethodexit(suppress = throwable.class) public static void onexit( @advice.this iloggingevent event, @advice.return(typing = assigner.typing.dynamic, readonly = false) map mdc) agentspan.context context = instrumentationcontext.get(iloggingevent.class, agentspan.context.class).get(event); // nothing to add so return early if (context == null &&agenttracer.traceconfig().islogsinjectionenabled())map correlationvalues = new hashmap<>(8); if (context != null) else } string servicename = config.get().getservicename();if (null != servicename &&servicename.isempty())string env = config.get().getenv();if (null != env &&env.isempty())string version = config.get().getversion();if (null != version &&version.isempty())mdc = null != mdc ? new unionmap<>(mdc, correlationvalues) :correlationvalues; }
为了允许新创建的线程的日志也获取父线程的跟踪信息,可以通过创建它来实现span来实现这一目标span需要是父线程的子线程span完成串联。

new thread(()",inheritablethreadlocalutil.getvalue())span span = null; try ",span.context().totraceid())finally }start();
通过请求相应的 URL 来观察日志输出。

2023-10-23 14:51:28.969 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,278] springboot-server 2303424716416355903 7690232490489894572 - this func is threadtest.2023-10-23 14:51:28.969 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,280] springboot-server 2303424716416355903 7690232490489894572 - current traceid:23034247164163559032023-10-23 14:51:28.970 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,283] springboot-server - this is new thread.2023-10-23 14:51:28.971 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,284] springboot-server - new thread get span:datadog.trace.instrumentation.opentracing32.otspan@c3a1aae2023-10-23 14:51:28.971 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,292] springboot-server - thread:23034247164163559032023-10-23 14:51:28.971 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,294] springboot-server 2303424716416355903 5766505477412800739 - thread:2303424716416355903
为什么线程中有两个日志pattern没有跟踪信息输出?原因在于当前线程的内部结构span它是在日志输出之后创建的,只需要放入span只需创建以下内容即可。

new thread(()",inheritablethreadlocalutil.getvalue())logger.info("thread:{}",span.context().totraceid())finally }start();
通过请求相应的 URL 来观察日志输出。

2023-10-23 15:01:00.490 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,278] springboot-server 472828375731745486 6076606716618097397 - this func is threadtest.2023-10-23 15:01:00.491 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,280] springboot-server 472828375731745486 6076606716618097397 - current traceid:4728283757317454862023-10-23 15:01:00.492 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,291] springboot-server 472828375731745486 9214366589561638347 - this is new thread.2023-10-23 15:01:00.492 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,292] springboot-server 472828375731745486 9214366589561638347 - new thread get span:datadog.trace.instrumentation.opentracing32.otspan@12fd40f02023-10-23 15:01:00.493 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,293] springboot-server 472828375731745486 9214366589561638347 - thread:472828375731745486
创建 API 并直通executors创造executorservice对象。

@requestmapping("/execthread") @responsebody public string executorservicetest())return "executorservice"; }
通过请求相应的 URL 来观察日志输出。

2023-10-23 15:24:41.828 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - executorservicetest,309] springboot-server 2170215511602500482 4370366221958823908 - this func is executorservicetest.2023-10-23 15:24:41.832 [pool-2-thread-1] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$executorservicetest$2,311] springboot-server 2170215511602500482 4370366221958823908 - this is executor thread.
executorservice线程池模式自动传递跟踪信息,该信息派生自相应组件掩埋操作的 DDTRACE 实现。

J**A 支持许多线程组件框架的链接传递,例如:forkjointaskforkjoinpooltimertaskfuturetaskthreadpoolexecutor等一会。

springboot-ddtrace-server

相似文章

    以色列正处于多管齐下的困境中

    名称 The Pain of History!中东战争再度火燃,以色列陷入多线困境,伊朗争夺全球霸权,你的祖国也岌岌可危 标题 中东战争 历史之痛再次袭来,让我们站在一起!在中东这片土地上,历史似乎总是与紧张和冲突密切相关。最近,该地区再次成为全球关注的焦点,原因无非是以色列与其邻国 巴勒斯坦 黎巴...

    以色列继续在多条战线上作战 联合国驻黎巴嫩设施遭到袭击

    新华社北京月日电 记者 张旭 日,以色列 黎巴嫩边境紧张局势仍在继续 以色列遭到来自黎巴嫩方向的导弹和自杀式无人机袭击,以色列还动用了空袭和炮击。联合国驻黎巴嫩临时部队 联黎部队 设施遭到不确定的炮火袭击 路透社援引以色列军方消息人士的话报道说,以色列军队出动多架战机对黎巴嫩境内的若干安拉目标进行密...

    以色列发动了多线作战,联合国设施遭到袭击

    以色列和黎巴嫩之间的紧张局势依然存在。最近,以色列遭到来自黎巴嫩方向的导弹和自杀式无人机袭击,以色列对此作出回应。联合国在黎巴嫩边界的军事设施也遭到袭击。此外,黎巴嫩真主在一份声明中说,它发射了武装无人机袭击了以色列的一个 指挥所 并对黎巴嫩边境城镇纳古拉附近的以色列军队贾尔阿拉姆哨所发动了袭击。据...

    擅自不上门罚款3万元? 聆听一线快递员的心声

    近日,交通运输部听取了关于年交通运输更贴近民生的汇报,并审议了 快递市场管理办法 快递市场管理办法 修订草案 征求意见稿 已于年月日由国家邮政局发布,向社会公开征求意见。我不知道到底收到了多少意见,但该法规中的许多规定都有些苛刻。对于草根网点和一线快递员来说,最受诟病的一件事是 未经用户同意,不得代...

    振动清洗筛在油脂生产线中起什么作用?

    菜籽油是从菜籽中提取的食用植物油,菜籽是我国主要的食用油之一,其产量占国内食用油的 以上,深受中国消费者的喜爱。菜籽油又称菜籽油,主要产于长江流域 我国西南和西北地区,富含脂肪 蛋白质 不饱和脂肪酸 酚类 肽类等营养成分,具有抗炎护肤 清肝和健胆等功能和功效。油菜籽作为我国主要的食用油料种子之一,为...