You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin协程结合OpenTelemetry与Spring WebFlux时上下文丢失致NPE

Kotlin协程+Spring WebFlux+OpenTelemetry日志NPE问题解决

问题核心

挂起函数恢复时协程上下文丢失,导致kotlin.coroutines.jvm.internal.ContinuationImpl.getContext触发空指针异常,仅在使用协程挂起操作(如delay、coroutineScope)时出现,无协程或用runBlocking时正常。

解决方案

1. 修复依赖版本兼容性

当前Kotlin协程1.9.0与Kotlin 2.0.20存在兼容性冲突,同时OpenTelemetry扩展版本需与BOM保持一致。调整build.gradle.kts依赖:

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-webflux")

    implementation("io.github.oshai:kotlin-logging:7.0.0")

    implementation("io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter")
    runtimeOnly("io.opentelemetry.instrumentation:opentelemetry-logback-mdc-1.0:2.6.0-alpha")

    implementation("io.micrometer:micrometer-tracing-bridge-otel")
    implementation("io.micrometer:micrometer-registry-prometheus")
    implementation("io.opentelemetry:opentelemetry-exporter-zipkin")
    implementation("org.springframework.boot:spring-boot-starter-actuator")

    // 适配Kotlin 2.0.20的协程稳定版本
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.8.1")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.1")
    // 与OpenTelemetry BOM版本对齐
    implementation("io.opentelemetry:opentelemetry-extension-kotlin:2.6.0")
    implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
    
    testImplementation(kotlin("test"))
}

2. 强制绑定OpenTelemetry上下文到协程

手动将OpenTelemetry上下文注入协程上下文,确保挂起恢复时上下文不丢失:

import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import io.opentelemetry.extension.kotlin.asContextElement
import io.opentelemetry.api.GlobalOpenTelemetry
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class MyReactiveController  {

    private val logger = KotlinLogging.logger {}
    private val otel = GlobalOpenTelemetry.get()

    @GetMapping("/hello")
    suspend fun hello(): String {
        logger.info { "Log from controller" }
        
        // 绑定当前OpenTelemetry上下文到协程
        withContext(otel.currentContext().asContextElement()) {
            delay(50)
            logger.info { "Log from controller 2" }
        }
        return "Hello World"
    }
}

3. 临时禁用OpenTelemetry MDC集成

若上述方案无效,可临时切换到Micrometer Tracing的MDC传递:

  • 移除runtimeOnly("io.opentelemetry.instrumentation:opentelemetry-logback-mdc-1.0:2.6.0-alpha")
  • 依赖micrometer-tracing-bridge-otel自动传递traceId到MDC

验证

启动应用后调用/hello接口,确认日志正常输出且无NPE,同时检查所有日志的traceId一致,说明上下文传递正常。

内容的提问来源于stack exchange,提问作者Alexander

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 21:34:55