suresh
05/14/2025, 10:50 PMKtorServerTelemetry
in Ktor 3.0 using the official samples, but I’ve encountered the following error when using the plugin alongside zero-config instrumentation (the OTel Java agent)suresh
05/14/2025, 10:50 PMGlobalOpenTelemetry.get()
, which the agent should set up. What’s the proper way to configure Ktor server/client telemetry when the OTel Java agent is being used?suresh
05/14/2025, 10:51 PM2025-05-14T15:01:03.532 PDT INFO [main] Application - OTel Java agent is active
2025-05-14T15:01:03.551 PDT ERROR [main] main - Failed to start App!: Please make sure that you use unique name for the plugin and don't install it twice. Conflicting application plugin is already installed with the same key as `OpenTelemetry`
io.ktor.server.application.DuplicatePluginException: Please make sure that you use unique name for the plugin and don't install it twice. Conflicting application plugin is already installed with the same key as `OpenTelemetry`
at io.ktor.server.application.ApplicationPluginKt.install(ApplicationPlugin.kt:137) ~[ktor-server-core-jvm-3.1.3.jar:3.1.3]
at dev.suresh.plugins.OTelKt.configureOTel(OTel.kt:14) ~[jvm-0.1.0.0+bfceb6a.jar:0.1.0.0+bfceb6a]
at dev.suresh.AppKt.module(App.kt:26) ~[jvm-0.1.0.0+bfceb6a.jar:0.1.0.0+bfceb6a]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:565) ~[na:na]
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97) ~[kotlin-reflect-2.2.0-Beta2.jar:2.2.0-Beta2-release-112]
at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Static.call(CallerImpl.kt:106) ~[kotlin-reflect-2.2.0-Beta2.jar:2.2.0-Beta2-release-112]
at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflection(KCallableImpl.kt:207) ~[kotlin-reflect-2.2.0-Beta2.jar:2.2.0-Beta2-release-112]
at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:112) ~[kotlin-reflect-2.2.0-Beta2.jar:2.2.0-Beta2-release-112]
at io.ktor.server.engine.internal.CallableUtilsKt.callFunctionWithInjection(CallableUtils.kt:127) ~[ktor-server-core-jvm-3.1.3.jar:3.1.3]
at io.ktor.server.engine.internal.CallableUtilsKt.executeModuleFunction(CallableUtils.kt:40) ~[ktor-server-core-jvm-3.1.3.jar:3.1.3]
at io.ktor.server.engine.EmbeddedServer.launchModuleByName$lambda$32(EmbeddedServerJvm.kt:422) ~[ktor-server-core-jvm-3.1.3.jar:3.1.3]
at io.ktor.server.engine.EmbeddedServer.avoidingDoubleStartupFor(EmbeddedServerJvm.kt:446) ~[ktor-server-core-jvm-3.1.3.jar:3.1.3]
at io.ktor.server.engine.EmbeddedServer.launchModuleByName(EmbeddedServerJvm.kt
suresh
05/14/2025, 10:52 PMfun Application.configureOTel() {
val otelSdk = otelSdk()
install(KtorServerTelemetry) {
setOpenTelemetry(otelSdk)
spanKindExtractor {
if (httpMethod == <http://HttpMethod.Post|HttpMethod.Post>) {
SpanKind.PRODUCER
} else {
SpanKind.CLIENT
}
}
attributesExtractor {
onStart { attributes.put("start-time", Clock.System.now().toEpochMilliseconds()) }
onEnd { attributes.put("end-time", Clock.System.now().toEpochMilliseconds()) }
}
}
}
context(app: Application)
fun otelSdk(): OpenTelemetry {
val globalOtel = GlobalOpenTelemetry.get()
val isAgentActive = globalOtel !== OpenTelemetry.noop()
when(isAgentActive) {
true -> <http://app.log.info|app.log.info>("OTel Java agent is active")
else -> app.log.warn("OTel Java agent is inactive!!")
}
return globalOtel
}
suresh
05/14/2025, 10:53 PMKtor: 3.1.3
agent: 2.15.0
io.opentelemetry.instrumentation:opentelemetry-ktor-3.0:2.15.0-alpha
Aleksei Tirman [JB]
05/15/2025, 7:50 AMDuplicatePluginException
thrown on the server startup? Can you share the steps to reproduce the exception?phldavies
05/15/2025, 8:49 AMOTEL_INSTRUMENTATION_KTOR_ENABLED=false
environment variablephldavies
05/15/2025, 8:51 AMGlobalOpenTelemetry
configured as part of the agent instrumentation but it won't inject the ktor plugins (you'll need to install the appropriate plugin in your clients too should you want/need to)suresh
05/15/2025, 1:37 PM