9

我们将 Java GRPC 用于我们的内部服务之一,并且我们有一个服务器端拦截器,我们使用它来从标头中获取信息并将它们设置在内部使用 ThreadLocal 的日志记录上下文中。

所以在我们的拦截器中,我们做了类似的事情:

LogMessageBuilder.setServiceName("some-service");

    final String someHeaderWeWant = headers.get(HEADER_KEY);

    final LoggerContext.Builder loggingContextBuilder = new LoggerContext.Builder()
        .someFieldFromHeaders(someHeaderWeWant);
LoggerContext.setContext(loggingContextBuilder.build());

然后在我们的服务调用中,我们像这样访问它:

LoggingContext loggingContext = LoggingContext.getCurrent()

但是,当前上下文有时为空。

然后我们尝试使用 GRPC Context 类,如下所示:

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()

然后在服务调用中访问它,例如:

LoggingContext context = LOGGING_CONTEXT_KEY.get(Context.current())

然而,这有时也是空的,如果我打印出内存地址,无论我是否附加在拦截器中,上下文的早期似乎总是 ROOT 上下文,但是在几次调用之后,上下文是正确的并且记录器数据在那里它应该。

因此,如果有人有任何想法或更好的方法将数据从拦截器传播到服务调用,我很想听听。

4

1 回答 1

7

每个回调都可以在不同的线程上调用,因此必须为每个回调设置线程本地。看来您可能会意外获得用于其他RPC 的上下文。

grpc-java 0.12.0 应该在本周发布。上下文已部分集成在 0.12.0 中,我们还添加Contexts.interceptCall()了您所需要的内容:它为每个回调附加和分离上下文。

在 0.12.0 中,您现在应该看到为每个服务器调用(而不是 ROOT)创建了新的上下文,以及从客户端调用传播到StreamObserver回调的上下文。

另请注意,likeThreadLocal Context旨在严格限定范围:在 之后attach(),您通常应该有一个 try-finally to detach()

于 2016-01-20T18:32:57.597 回答