We are using Java GRPC for one of our internal services and we have a server side interceptor that we use to grab information from the headers and set them up in a logging context that that uses a ThreadLocal internally.
So in our interceptor we do something similar to this:
LogMessageBuilder.setServiceName("some-service");
final String someHeaderWeWant = headers.get(HEADER_KEY);
final LoggerContext.Builder loggingContextBuilder = new LoggerContext.Builder()
.someFieldFromHeaders(someHeaderWeWant);
LoggerContext.setContext(loggingContextBuilder.build());
Then in our service call we access it like this:
LoggingContext loggingContext = LoggingContext.getCurrent()
However the current context is null some of the time.
We then tried to use the GRPC Context class like below:
LogMessageBuilder.setServiceName("some-service");
final String someHeaderWeWant = headers.get(HEADER_KEY);
final LoggerContext.Builder loggingContextBuilder = new LoggerContext.Builder()
.someFieldFromHeaders(someHeaderWeWant);
Context.current().withValue(LOGGING_CONTEXT_KEY, loggingContextBuilder.build()).attach()
Then accessing it in the service call like:
LoggingContext context = LOGGING_CONTEXT_KEY.get(Context.current())
However that is also sometimes null and if I print out the memory addresses it appears that early on the context is always the ROOT context regardless of me attaching in the interceptor, but after a few calls the contexts are correct and the logger data is there like it should.
So if anyone has any ideas or better ways to propagate data from an interceptor to the service call I would love to hear it.
Each callback can be called on a different thread, so the thread-local has to be set for each callback. It seems you may accidentally be getting Contexts intended for other RPCs.
grpc-java 0.12.0 should be released this week. Context has been partially integrated in 0.12.0, and we also added Contexts.interceptCall()
which is exactly what you need: it attaches and detaches the context for each callback.
In 0.12.0, you should now see new contexts being created for each server call (instead of ROOT) and contexts propagated from client calls to StreamObserver
callbacks.
As another note, unlike ThreadLocal
Context
is intended to be tightly scoped: after attach()
, you should generally have a try-finally to detach()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With