1

我可以从以下 Spring Boot 控制器代码中看到跨度记录在 Zipkin UI 中:

@RestController
class ConcurrentController {
    @Autowired
    lateinit var restTemplate : RestTemplate
    val urls = arrayListOf<String>("http://www.google.com","http://www.facebook.com")
    private val logger = Logger.getLogger(this::class.java.getName())
    @RequestMapping("/concurrent1")
    fun endPoint1() : String {
        logger.info("/concurrent1")
        var s = ""
        runBlocking {
            val a = urls.map { url ->
                logger.info(url)
                async(CommonPool) {
                logger.info("getting $url")
                restTemplate.getForObject(url, String::class.java)
                sleep(5000)
                logger.info("got $url")
                }
            }
            val b = a.map { it.await() }
            s = b.joinToString { "" }
        }
        return s
    }
}

日志输出如下所示:

2017-10-30 20:56:04.525  INFO [coroutinesDemo,eb6fd4fedb6f3a6d,eb6fd4fedb6f3a6d,true] 13547 --- [nio-8080-exec-1] c.e.coroutines.ConcurrentController      : /concurrent1
2017-10-30 20:56:04.543  INFO [coroutinesDemo,eb6fd4fedb6f3a6d,eb6fd4fedb6f3a6d,true] 13547 --- [nio-8080-exec-1] c.e.coroutines.ConcurrentController      : http://www.google.com
2017-10-30 20:56:04.548  INFO [coroutinesDemo,eb6fd4fedb6f3a6d,eb6fd4fedb6f3a6d,true] 13547 --- [nio-8080-exec-1] c.e.coroutines.ConcurrentController      : http://www.facebook.com
2017-10-30 20:56:04.548  INFO [coroutinesDemo,,,] 13547 --- [onPool-worker-9] c.e.coroutines.ConcurrentController      : getting http://www.google.com
2017-10-30 20:56:04.549  INFO [coroutinesDemo,,,] 13547 --- [onPool-worker-2] c.e.coroutines.ConcurrentController      : getting http://www.facebook.com
2017-10-30 20:56:09.703  INFO [coroutinesDemo,,,] 13547 --- [onPool-worker-2] c.e.coroutines.ConcurrentController      : got http://www.facebook.com
2017-10-30 20:56:09.703  INFO [coroutinesDemo,,,] 13547 --- [onPool-worker-9] c.e.coroutines.ConcurrentController      : got http://www.google.com

但跟踪在 UI 中是独立的。

我希望对 Google 和 Facebook url 的两个调用同时嵌套在对/concurrent1端点的调用下。

我怀疑这是由于执行协程的线程与启动 Spring 应用程序的线程不同,但我现在不知道如何继续使用 Spring Sleuth!

4

2 回答 2

2

注意:此解决方案确实适用于记录目的,但不适用于其他 Sleuth 功能,例如检测 RestTemplates 以将跟踪标头发送到其他服务。所以不幸的是,这不是一个完全有效的解决方案。:(

在采用@Baca 的解决方案一段时间后,我发现 Kotlin Coroutines 提供与 slf4j 的直接集成,这是 Spring Sleuth 的基础。Sleuth 将属性、、、X-B3-TraceIdtraceId添加X-B3-SpanIdspanId线程的 MDC。

您可以使用如下所示的代码为协程保留父线程的 MDC。协程框架将负责在协程执行/恢复时恢复工作线程上的 MDC 上下文。这是迄今为止我能发现的最简单的解决方案。:)

// add your own properties or use the ones already added by Sleuth
MDC.put("someLoggerProperty", "someValue")

GlobalScope.launch(MDCContext()) {
    // your code goes here
}

启动方法采用可选的 CoroutineContext,coroutine-slf4j 集成实现了 MDCContext。此类捕获调用线程的 MDC 上下文(创建一个副本)并将其用于协程执行。

将此依赖项添加到您的 build.gradle:

implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-slf4j', version: '1.3.9'

项目:https ://github.com/Kotlin/kotlinx.coroutines/tree/master/integration/kotlinx-coroutines-slf4j 文档:https ://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-slf4j/index .html

于 2020-10-20T05:41:48.797 回答
0

我使用“ spring-cloud- sleuth”库中的“TraceCallable”类在我的代码中解决它。

我的代码示例是:

@Component
class TracingCallableSupplier(
    private val tracing: Tracing,
    private val spanNamer: SpanNamer
) {

    /**
     * Supply callable which will use tracing from parent while performing jobs.
     */
    fun <T : Any?> supply(function: () -> T): Callable<T> {
        return TraceCallable(tracing, spanNamer, Callable(function))
    }
}

@Service
class MyBean{
    @Autowired
    lateinit var traceSupplier : TracingCallableSupplier

    fun myMethod {
        val callable = tracingCallableSupplier.supply {
            // ... some code to be called asynchronous...
        }

        // simplest coroutine...
        GlobalScope.launch {
            callable.call()
        }

        // more advanced coroutine usage...
        val deferred = (0 until 10).map {
            async {
                callable.call()
            }
        }

        runBlocking {
            deferred.map {
                val result = it.await()
                // ... some processing ...
            }
        }
    }
}
于 2018-10-01T06:37:07.617 回答