Instrumenting Executors - issues in Spring Cloud Sleuth and JDK16

Marcin Grzejszczak mgrzejszczak at
Fri Apr 9 17:08:14 UTC 2021

I'm decorating existing user or framework code. If they have custom behavior, i want to respect that instead of override it.

Get Outlook for iOS<>
From: forax at <forax at>
Sent: Friday, April 9, 2021 6:33:10 PM
To: Marcin Grzejszczak <mgrzejszczak at>
Cc: core-libs-dev <core-libs-dev at>
Subject: Re: Instrumenting Executors - issues in Spring Cloud Sleuth and JDK16

De: "Marcin Grzejszczak" <mgrzejszczak at>
À: "Remi Forax" <forax at>
Cc: "core-libs-dev" <core-libs-dev at>
Envoyé: Vendredi 9 Avril 2021 17:41:28
Objet: Re: Instrumenting Executors - issues in Spring Cloud Sleuth and JDK16
That's the thing, I'm not using an agent. We're doing the wrapping at runtime by instrumenting spring beans.

Apart the fact that decorateTask is a good example of why it's better to use delegation than using the template method pattern.
Why do you need to call decorateTask() directly, and not execute/submit/invoke with your wrapped Runnable ?


Pobierz aplikację Outlook dla systemu iOS<>
Od: Remi Forax <forax at>
Wysłane: Friday, April 9, 2021 5:18:11 PM
Do: Marcin Grzejszczak <mgrzejszczak at>
DW: core-libs-dev <core-libs-dev at>
Temat: Re: Instrumenting Executors - issues in Spring Cloud Sleuth and JDK16

----- Mail original -----
> De: "Marcin Grzejszczak" <mgrzejszczak at>
> À: "core-libs-dev" <core-libs-dev at>
> Envoyé: Vendredi 9 Avril 2021 16:29:32
> Objet: Instrumenting Executors - issues in Spring Cloud Sleuth and JDK16

> Hi!
> I'm the lead of Spring Cloud Sleuth [1], a project dedicated to working with
> distributed tracing. We're propagating the tracing context e.g. through
> threads. That means that when a user spawns a new thread we need to pass the
> context from the old thread to the new one. Example - if the user uses an
> Executor or an ExecutorService (e.g. via calling the execute(Runnable r)
> method) then we need to wrap the Runnable in its trace representation. That
> means that we retrieve the context from Thread A , pass it in the constructor
> of the TraceRunnable and then restore it once the run method is called in
> Thread B.
> The problem in Sleuth that we have with JDK16 is that we can't use reflection to
> ensure that we're wrapping all methods of any Executors [2]. In other words we
> want to create a proxy around an existing Executor and wrap all methods.
> Currently, we're using reflection cause Executor implementations such as
> `ScheduledThreadPoolExecutor` have quite a few protected methods that we can't
> access. What we would like to achieve is a delegation mechanism that we can
> wrap all objects that the given Executor is using within their API (such as
> Runnables, Callables, other Executors) in their trace representation and then
> delegate calls for all methods to the wrapped object. That would also mean the
> delegation to currently protected methods.
> If there's another way to achieve this other than opening the
> java.util.concurrent API then I would very much like to use it. Currently with
> JDK16 it's not possible to instrument that code so context propagation might be
> buggy when dealing with executors.

I'm not sure if you are using an agent or not, if you are using an agent, you can redefine a module,java.util.Set,java.util.Map,java.util.Map,java.util.Set,java.util.Map<>)


> Marcin Grzejszczak
> Staff Engineer, Spring Cloud

More information about the core-libs-dev mailing list