操作符#lift:用于MDC记录的好主意吗?

4

Project Reactor文档建议使用以下模式记录MDC日志:

.doOnEach(logOnNext(r -> LOG.debug("found restaurant {} for ${}", r.getName(), r.getPricePerPerson())))

为避免每次都要包装每个日志调用,是否可以使用自定义的订阅者,在每个信号之前从当前上下文填充MDC,并使用Hooks.onEachOperator(Operators.lift(...))添加?我的主要关注点是:
1.) 即使没有任何日志记录,每个信号之前填充MDC的成本如何。
2.) 运算符融合:每个运算符上的Operators.lift(...)是否有效地禁用了运算符融合?尝试使用StepVerifier#expectFusion进行快速测试似乎表明是这样的。如果这是真的,那么实际上会受到多大性能影响?
感谢您的任何建议!
1个回答

3
这是Sleuth最初采用的方法,通过Hooks.onEachOperator实现。然而,如果你只需要在响应式流管道的一部分操作中进行日志记录/MDC,这种方式非常昂贵,可能并不值得。更不用说,这种方法不仅影响了你定义的响应式步骤,还影响了任何其他库/框架。
建议有其原因:更好的控制、更少的影响和更明确的方法。

1
有没有使用MDC进行成本效益的登录方式? - namila007
1
Reactor中的线程可以并且将被多个Flux同时重复使用(例如,使用Schedulers.parallel()的两个不同的Flux),因此在每个onNext信号周围设置和清除任何ThreadLocal(基于MDC)非常重要。您可以编写一个帮助方法,在doOnEach操作符中填充MDC、执行日志记录并清除MDC。 - Simon Baslé
@SimonBaslé 有没有不使用transformDeferredContextual来创建自定义的flatMap实现并使用可用的上下文设置MDC的原因?这似乎类似于在此处讨论的方法,而不会影响每个管道。 - mowwwalker
这是一个Spring Webflux应用程序,主要作为代理。我认为Hooks.onEachOperator也不会成为问题,因为我们的反应链受网络操作的性能限制。但是,如果使用该钩子影响其他库和框架,那么很难确信它不会对它们的内部操作产生重大影响。 - mowwwalker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接