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
讓它輸出traceid
跟spanid
,將如下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日誌中生成了跟蹤資訊
為traceid
為spanid
向介面新增新執行緒以建立執行緒。
@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
原始碼是在我們使用threadlocal
之set()
方法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
資訊輸出,原因是,ddtrace
右logback
之ge***cpropertymap()
跟ge***c()
方法並新增跟蹤資訊put
自mdc
中間。
@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 支援許多執行緒元件框架的鏈結傳遞,例如:forkjointask
forkjoinpool
timertask
futuretask
threadpoolexecutor
等一會。
springboot-ddtrace-server