In the old days, we had ThreadLocal for programs for transferring data along with the request path, since all request processing was performed on this thread, and things like Logback used this with MDC.put("requestId", getNewRequestId());
Then came Scala and functional programming, as well as Future and Local.scala (at least I know that Future has this class on Twitter). Future.scala knows about Local.scala and passes the context through all map / flatMap , etc. Etc., So that I can still do Local.set("requestId", getNewRequestId()); and then downstream after it went through many threads, I can still access it with Local.get(...)
Soooo, my question is in Java, can I do the same with the new CompletableFuture somewhere with a LocalContext or some object (not sure about the name), and so I can change the MDC Logback context to store it in that context instead ThreadLocal in such a way that I do not lose the request identifier and all my logs through thenApply , thenAccept , etc. etc., still work fine with logging and the -XrequestId flag in the Logback configuration.
EDIT:
As an example. If you have a request and you use Log4j or Logback, in the filter you set MDC.put("requestId", requestId) and then in your application you will register many log statements in the following line:
log.info("request came in for url="+url); log.info("request is complete");
Now the output of the log will show the following:
INFO {time}: requestId425 request came in for url=/mypath INFO {time}: requestId425 request is complete
This uses the ThreadLocal trick to achieve this. On Twitter, we use Scala and Twitter Future in Scala along with the Local.scala class. Local.scala and Future.scala are interconnected by the fact that we can achieve the scenario described above, which is very nice, and all our log statements can register the request identifier, so the developer will never have to remember the request identifier, and you can follow through one cycle customer request with this identifier.
I do not see this in Java :(, which is very unfortunate, since there are many use cases for this. Perhaps there is something that I do not see?