Rename ktor tracing to ktor telemetry (#12855)
This commit is contained in:
parent
b08d272e23
commit
9865c17db8
|
|
@ -1,6 +1,7 @@
|
|||
# Library Instrumentation for Ktor version 1.x
|
||||
|
||||
This package contains libraries to help instrument Ktor. Currently, only server instrumentation is supported.
|
||||
This package contains libraries to help instrument Ktor.
|
||||
Currently, only server instrumentation is supported.
|
||||
|
||||
## Quickstart
|
||||
|
||||
|
|
@ -29,14 +30,14 @@ implementation("io.opentelemetry.instrumentation:opentelemetry-ktor-1.0:OPENTELE
|
|||
|
||||
## Usage
|
||||
|
||||
Initialize instrumentation by installing the `KtorServerTracing` feature. You must set the `OpenTelemetry` to use with
|
||||
the feature.
|
||||
Initialize instrumentation by installing the `KtorServerTelemetry` feature.
|
||||
You must set the `OpenTelemetry` to use with the feature.
|
||||
|
||||
```kotlin
|
||||
OpenTelemetry openTelemetry = ...
|
||||
|
||||
embeddedServer(Netty, 8080) {
|
||||
install(KtorServerTracing) {
|
||||
install(KtorServerTelemetry) {
|
||||
setOpenTelemetry(openTelemetry)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v1_0
|
||||
|
||||
import io.ktor.application.*
|
||||
import io.ktor.request.*
|
||||
import io.ktor.response.*
|
||||
import io.ktor.routing.*
|
||||
import io.ktor.util.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import io.opentelemetry.api.OpenTelemetry
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.extension.kotlin.asContextElement
|
||||
import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor
|
||||
import io.opentelemetry.instrumentation.api.internal.InstrumenterUtil
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class KtorServerTelemetry private constructor(
|
||||
private val instrumenter: Instrumenter<ApplicationRequest, ApplicationResponse>,
|
||||
) {
|
||||
|
||||
class Configuration {
|
||||
internal lateinit var builder: DefaultHttpServerInstrumenterBuilder<ApplicationRequest, ApplicationResponse>
|
||||
|
||||
internal var spanKindExtractor:
|
||||
(SpanKindExtractor<ApplicationRequest>) -> SpanKindExtractor<ApplicationRequest> = { a -> a }
|
||||
|
||||
fun setOpenTelemetry(openTelemetry: OpenTelemetry) {
|
||||
this.builder =
|
||||
DefaultHttpServerInstrumenterBuilder.create(
|
||||
INSTRUMENTATION_NAME,
|
||||
openTelemetry,
|
||||
KtorHttpServerAttributesGetter.INSTANCE
|
||||
)
|
||||
}
|
||||
|
||||
fun setStatusExtractor(
|
||||
extractor: (SpanStatusExtractor<in ApplicationRequest, in ApplicationResponse>) -> SpanStatusExtractor<in ApplicationRequest, in ApplicationResponse>
|
||||
) {
|
||||
builder.setStatusExtractor { prevExtractor ->
|
||||
SpanStatusExtractor { spanStatusBuilder: SpanStatusBuilder,
|
||||
request: ApplicationRequest,
|
||||
response: ApplicationResponse?,
|
||||
throwable: Throwable? ->
|
||||
extractor(prevExtractor).extract(spanStatusBuilder, request, response, throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setSpanKindExtractor(extractor: (SpanKindExtractor<ApplicationRequest>) -> SpanKindExtractor<ApplicationRequest>) {
|
||||
this.spanKindExtractor = extractor
|
||||
}
|
||||
|
||||
fun addAttributesExtractor(extractor: AttributesExtractor<in ApplicationRequest, in ApplicationResponse>) {
|
||||
builder.addAttributesExtractor(extractor)
|
||||
}
|
||||
|
||||
fun setCapturedRequestHeaders(requestHeaders: List<String>) {
|
||||
builder.setCapturedRequestHeaders(requestHeaders)
|
||||
}
|
||||
|
||||
fun setCapturedResponseHeaders(responseHeaders: List<String>) {
|
||||
builder.setCapturedResponseHeaders(responseHeaders)
|
||||
}
|
||||
|
||||
fun setKnownMethods(knownMethods: Set<String>) {
|
||||
builder.setKnownMethods(knownMethods)
|
||||
}
|
||||
|
||||
internal fun isOpenTelemetryInitialized(): Boolean = this::builder.isInitialized
|
||||
}
|
||||
|
||||
private fun start(call: ApplicationCall): Context? {
|
||||
val parentContext = Context.current()
|
||||
if (!instrumenter.shouldStart(parentContext, call.request)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return instrumenter.start(parentContext, call.request)
|
||||
}
|
||||
|
||||
private fun end(context: Context, call: ApplicationCall, error: Throwable?) {
|
||||
instrumenter.end(context, call.request, call.response, error)
|
||||
}
|
||||
|
||||
companion object Feature : ApplicationFeature<Application, Configuration, KtorServerTelemetry> {
|
||||
private const val INSTRUMENTATION_NAME = "io.opentelemetry.ktor-1.0"
|
||||
|
||||
private val contextKey = AttributeKey<Context>("OpenTelemetry")
|
||||
private val errorKey = AttributeKey<Throwable>("OpenTelemetryException")
|
||||
|
||||
override val key: AttributeKey<KtorServerTelemetry> = AttributeKey("OpenTelemetry")
|
||||
|
||||
override fun install(pipeline: Application, configure: Configuration.() -> Unit): KtorServerTelemetry {
|
||||
val configuration = Configuration().apply(configure)
|
||||
|
||||
if (!configuration.isOpenTelemetryInitialized()) {
|
||||
throw IllegalArgumentException("OpenTelemetry must be set")
|
||||
}
|
||||
|
||||
val instrumenter = InstrumenterUtil.buildUpstreamInstrumenter(
|
||||
configuration.builder.instrumenterBuilder(),
|
||||
ApplicationRequestGetter,
|
||||
configuration.spanKindExtractor(SpanKindExtractor.alwaysServer())
|
||||
)
|
||||
|
||||
val feature = KtorServerTelemetry(instrumenter)
|
||||
|
||||
val startPhase = PipelinePhase("OpenTelemetry")
|
||||
pipeline.insertPhaseBefore(ApplicationCallPipeline.Monitoring, startPhase)
|
||||
pipeline.intercept(startPhase) {
|
||||
val context = feature.start(call)
|
||||
|
||||
if (context != null) {
|
||||
call.attributes.put(contextKey, context)
|
||||
withContext(context.asContextElement()) {
|
||||
try {
|
||||
proceed()
|
||||
} catch (err: Throwable) {
|
||||
// Stash error for reporting later since need ktor to finish setting up the response
|
||||
call.attributes.put(errorKey, err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
proceed()
|
||||
}
|
||||
}
|
||||
|
||||
val postSendPhase = PipelinePhase("OpenTelemetryPostSend")
|
||||
pipeline.sendPipeline.insertPhaseAfter(ApplicationSendPipeline.After, postSendPhase)
|
||||
pipeline.sendPipeline.intercept(postSendPhase) {
|
||||
val context = call.attributes.getOrNull(contextKey)
|
||||
if (context != null) {
|
||||
var error: Throwable? = call.attributes.getOrNull(errorKey)
|
||||
try {
|
||||
proceed()
|
||||
} catch (t: Throwable) {
|
||||
error = t
|
||||
throw t
|
||||
} finally {
|
||||
feature.end(context, call, error)
|
||||
}
|
||||
} else {
|
||||
proceed()
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.environment.monitor.subscribe(Routing.RoutingCallStarted) { call ->
|
||||
val context = call.attributes.getOrNull(contextKey)
|
||||
if (context != null) {
|
||||
HttpServerRoute.update(context, HttpServerRouteSource.SERVER, { _, arg -> arg.route.parent.toString() }, call)
|
||||
}
|
||||
}
|
||||
|
||||
return feature
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute
|
|||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Deprecated("Use KtorServerTelemetry instead", ReplaceWith("KtorServerTelemetry"))
|
||||
class KtorServerTracing private constructor(
|
||||
private val instrumenter: Instrumenter<ApplicationRequest, ApplicationResponse>,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v1_0
|
||||
|
||||
import io.ktor.application.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.request.*
|
||||
import io.ktor.response.*
|
||||
import io.ktor.routing.*
|
||||
import io.ktor.server.engine.*
|
||||
import io.ktor.server.netty.*
|
||||
import io.opentelemetry.api.trace.Span
|
||||
import io.opentelemetry.api.trace.SpanKind
|
||||
import io.opentelemetry.api.trace.StatusCode
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.extension.kotlin.asContextElement
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||
import io.opentelemetry.semconv.ServerAttributes
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class KtorHttpServerOldTest : AbstractHttpServerTest<ApplicationEngine>() {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@RegisterExtension
|
||||
val testing = HttpServerInstrumentationExtension.forLibrary()
|
||||
}
|
||||
|
||||
override fun setupServer(): ApplicationEngine {
|
||||
return embeddedServer(Netty, port = port) {
|
||||
KtorOldTestUtil.installOpenTelemetry(this, testing.openTelemetry)
|
||||
|
||||
routing {
|
||||
get(ServerEndpoint.SUCCESS.path) {
|
||||
controller(ServerEndpoint.SUCCESS) {
|
||||
call.respondText(ServerEndpoint.SUCCESS.body, status = HttpStatusCode.fromValue(ServerEndpoint.SUCCESS.status))
|
||||
}
|
||||
}
|
||||
|
||||
get(ServerEndpoint.REDIRECT.path) {
|
||||
controller(ServerEndpoint.REDIRECT) {
|
||||
call.respondRedirect(ServerEndpoint.REDIRECT.body)
|
||||
}
|
||||
}
|
||||
|
||||
get(ServerEndpoint.ERROR.path) {
|
||||
controller(ServerEndpoint.ERROR) {
|
||||
call.respondText(ServerEndpoint.ERROR.body, status = HttpStatusCode.fromValue(ServerEndpoint.ERROR.status))
|
||||
}
|
||||
}
|
||||
|
||||
get(ServerEndpoint.EXCEPTION.path) {
|
||||
controller(ServerEndpoint.EXCEPTION) {
|
||||
throw IllegalStateException(ServerEndpoint.EXCEPTION.body)
|
||||
}
|
||||
}
|
||||
|
||||
get("/query") {
|
||||
controller(ServerEndpoint.QUERY_PARAM) {
|
||||
call.respondText("some=${call.request.queryParameters["some"]}", status = HttpStatusCode.fromValue(ServerEndpoint.QUERY_PARAM.status))
|
||||
}
|
||||
}
|
||||
|
||||
get("/path/{id}/param") {
|
||||
controller(ServerEndpoint.PATH_PARAM) {
|
||||
call.respondText(
|
||||
call.parameters["id"]
|
||||
?: "",
|
||||
status = HttpStatusCode.fromValue(ServerEndpoint.PATH_PARAM.status),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
get("/child") {
|
||||
controller(ServerEndpoint.INDEXED_CHILD) {
|
||||
ServerEndpoint.INDEXED_CHILD.collectSpanAttributes { call.request.queryParameters[it] }
|
||||
call.respondText(ServerEndpoint.INDEXED_CHILD.body, status = HttpStatusCode.fromValue(ServerEndpoint.INDEXED_CHILD.status))
|
||||
}
|
||||
}
|
||||
|
||||
get("/captureHeaders") {
|
||||
controller(ServerEndpoint.CAPTURE_HEADERS) {
|
||||
call.response.header("X-Test-Response", call.request.header("X-Test-Request") ?: "")
|
||||
call.respondText(ServerEndpoint.CAPTURE_HEADERS.body, status = HttpStatusCode.fromValue(ServerEndpoint.CAPTURE_HEADERS.status))
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
override fun stopServer(server: ApplicationEngine) {
|
||||
server.stop(0, 10, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
// Copy in HttpServerTest.controller but make it a suspending function
|
||||
private suspend fun controller(endpoint: ServerEndpoint, wrapped: suspend () -> Unit) {
|
||||
assert(Span.current().spanContext.isValid, { "Controller should have a parent span. " })
|
||||
if (endpoint == ServerEndpoint.NOT_FOUND) {
|
||||
wrapped()
|
||||
}
|
||||
val span = testing.openTelemetry.getTracer("test").spanBuilder("controller").setSpanKind(SpanKind.INTERNAL).startSpan()
|
||||
try {
|
||||
withContext(Context.current().with(span).asContextElement()) {
|
||||
wrapped()
|
||||
}
|
||||
span.end()
|
||||
} catch (e: Exception) {
|
||||
span.setStatus(StatusCode.ERROR)
|
||||
span.recordException(if (e is ExecutionException) e.cause ?: e else e)
|
||||
span.end()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
override fun configure(options: HttpServerTestOptions) {
|
||||
options.setTestPathParam(true)
|
||||
|
||||
options.setHttpAttributes {
|
||||
HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES - ServerAttributes.SERVER_PORT
|
||||
}
|
||||
|
||||
options.setExpectedHttpRoute { endpoint, method ->
|
||||
when (endpoint) {
|
||||
ServerEndpoint.PATH_PARAM -> "/path/{id}/param"
|
||||
else -> expectedHttpRoute(endpoint, method)
|
||||
}
|
||||
}
|
||||
// ktor does not have a controller lifecycle so the server span ends immediately when the
|
||||
// response is sent, which is before the controller span finishes.
|
||||
options.setVerifyServerSpanEndTime(false)
|
||||
|
||||
options.setResponseCodeOnNonStandardHttpMethod(404)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v1_0
|
||||
|
||||
import io.ktor.application.*
|
||||
import io.opentelemetry.api.OpenTelemetry
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest
|
||||
|
||||
class KtorOldTestUtil {
|
||||
companion object {
|
||||
fun installOpenTelemetry(application: Application, openTelemetry: OpenTelemetry) {
|
||||
application.install(KtorServerTracing) {
|
||||
setOpenTelemetry(openTelemetry)
|
||||
setCapturedRequestHeaders(listOf(AbstractHttpServerTest.TEST_REQUEST_HEADER))
|
||||
setCapturedResponseHeaders(listOf(AbstractHttpServerTest.TEST_RESPONSE_HEADER))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ class KtorServerSpanKindExtractorTest : AbstractHttpServerUsingTest<ApplicationE
|
|||
|
||||
override fun setupServer(): ApplicationEngine {
|
||||
return embeddedServer(Netty, port = port) {
|
||||
install(KtorServerTracing) {
|
||||
install(KtorServerTelemetry) {
|
||||
setOpenTelemetry(testing.openTelemetry)
|
||||
setSpanKindExtractor {
|
||||
SpanKindExtractor { req ->
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTes
|
|||
class KtorTestUtil {
|
||||
companion object {
|
||||
fun installOpenTelemetry(application: Application, openTelemetry: OpenTelemetry) {
|
||||
application.install(KtorServerTracing) {
|
||||
application.install(KtorServerTelemetry) {
|
||||
setOpenTelemetry(openTelemetry)
|
||||
setCapturedRequestHeaders(listOf(AbstractHttpServerTest.TEST_REQUEST_HEADER))
|
||||
setCapturedResponseHeaders(listOf(AbstractHttpServerTest.TEST_RESPONSE_HEADER))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common
|
||||
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.context.propagation.ContextPropagators
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter
|
||||
|
||||
abstract class AbstractKtorClientTelemetry(
|
||||
private val instrumenter: Instrumenter<HttpRequestData, HttpResponse>,
|
||||
private val propagators: ContextPropagators,
|
||||
) {
|
||||
|
||||
internal fun createSpan(requestBuilder: HttpRequestBuilder): Context? {
|
||||
val parentContext = Context.current()
|
||||
val requestData = requestBuilder.build()
|
||||
|
||||
return if (instrumenter.shouldStart(parentContext, requestData)) {
|
||||
instrumenter.start(parentContext, requestData)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
internal fun populateRequestHeaders(requestBuilder: HttpRequestBuilder, context: Context) {
|
||||
propagators.textMapPropagator.inject(context, requestBuilder, KtorHttpHeadersSetter)
|
||||
}
|
||||
|
||||
internal fun endSpan(context: Context, call: HttpClientCall, error: Throwable?) {
|
||||
endSpan(context, HttpRequestBuilder().takeFrom(call.request), call.response, error)
|
||||
}
|
||||
|
||||
internal fun endSpan(context: Context, requestBuilder: HttpRequestBuilder, response: HttpResponse?, error: Throwable?) {
|
||||
instrumenter.end(context, requestBuilder.build(), response, error)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common
|
||||
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import io.opentelemetry.api.OpenTelemetry
|
||||
import io.opentelemetry.api.common.AttributesBuilder
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil
|
||||
import java.util.function.Function
|
||||
|
||||
abstract class AbstractKtorClientTelemetryBuilder(
|
||||
private val instrumentationName: String
|
||||
) {
|
||||
companion object {
|
||||
init {
|
||||
KtorBuilderUtil.clientBuilderExtractor = { it.builder }
|
||||
}
|
||||
}
|
||||
|
||||
internal lateinit var openTelemetry: OpenTelemetry
|
||||
protected lateinit var builder: DefaultHttpClientInstrumenterBuilder<HttpRequestData, HttpResponse>
|
||||
|
||||
internal fun builder(): DefaultHttpClientInstrumenterBuilder<HttpRequestData, HttpResponse> {
|
||||
return builder
|
||||
}
|
||||
|
||||
fun setOpenTelemetry(openTelemetry: OpenTelemetry) {
|
||||
this.openTelemetry = openTelemetry
|
||||
this.builder = DefaultHttpClientInstrumenterBuilder.create(
|
||||
instrumentationName,
|
||||
openTelemetry,
|
||||
KtorHttpClientAttributesGetter
|
||||
)
|
||||
}
|
||||
|
||||
protected fun getOpenTelemetry(): OpenTelemetry {
|
||||
return openTelemetry
|
||||
}
|
||||
|
||||
fun capturedRequestHeaders(vararg headers: String) = capturedRequestHeaders(headers.asIterable())
|
||||
|
||||
fun capturedRequestHeaders(headers: Iterable<String>) {
|
||||
builder.setCapturedRequestHeaders(headers.toList())
|
||||
}
|
||||
|
||||
fun capturedResponseHeaders(vararg headers: String) = capturedResponseHeaders(headers.asIterable())
|
||||
|
||||
fun capturedResponseHeaders(headers: Iterable<String>) {
|
||||
builder.setCapturedResponseHeaders(headers.toList())
|
||||
}
|
||||
|
||||
fun knownMethods(vararg methods: String) = knownMethods(methods.asIterable())
|
||||
|
||||
fun knownMethods(vararg methods: HttpMethod) = knownMethods(methods.asIterable())
|
||||
|
||||
@JvmName("knownMethodsJvm")
|
||||
fun knownMethods(methods: Iterable<HttpMethod>) = knownMethods(methods.map { it.value })
|
||||
|
||||
fun knownMethods(methods: Iterable<String>) {
|
||||
builder.setKnownMethods(methods.toSet())
|
||||
}
|
||||
|
||||
fun attributesExtractor(extractorBuilder: ExtractorBuilder.() -> Unit = {}) {
|
||||
val builder = ExtractorBuilder().apply(extractorBuilder).build()
|
||||
this.builder.addAttributesExtractor(object : AttributesExtractor<HttpRequestData, HttpResponse> {
|
||||
override fun onStart(attributes: AttributesBuilder, parentContext: Context, request: HttpRequestData) {
|
||||
builder.onStart(OnStartData(attributes, parentContext, request))
|
||||
}
|
||||
|
||||
override fun onEnd(attributes: AttributesBuilder, context: Context, request: HttpRequestData, response: HttpResponse?, error: Throwable?) {
|
||||
builder.onEnd(OnEndData(attributes, context, request, response, error))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun spanNameExtractor(spanNameExtractorTransformer: Function<SpanNameExtractor<in HttpRequestData>, out SpanNameExtractor<in HttpRequestData>>) {
|
||||
builder.setSpanNameExtractor(spanNameExtractorTransformer)
|
||||
}
|
||||
|
||||
class ExtractorBuilder {
|
||||
private var onStart: OnStartData.() -> Unit = {}
|
||||
private var onEnd: OnEndData.() -> Unit = {}
|
||||
|
||||
fun onStart(block: OnStartData.() -> Unit) {
|
||||
onStart = block
|
||||
}
|
||||
|
||||
fun onEnd(block: OnEndData.() -> Unit) {
|
||||
onEnd = block
|
||||
}
|
||||
|
||||
internal fun build(): Extractor {
|
||||
return Extractor(onStart, onEnd)
|
||||
}
|
||||
}
|
||||
|
||||
internal class Extractor(val onStart: OnStartData.() -> Unit, val onEnd: OnEndData.() -> Unit)
|
||||
|
||||
data class OnStartData(
|
||||
val attributes: AttributesBuilder,
|
||||
val parentContext: Context,
|
||||
val request: HttpRequestData
|
||||
)
|
||||
|
||||
data class OnEndData(
|
||||
val attributes: AttributesBuilder,
|
||||
val parentContext: Context,
|
||||
val request: HttpRequestData,
|
||||
val response: HttpResponse?,
|
||||
val error: Throwable?
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.opentelemetry.api.OpenTelemetry
|
||||
import io.opentelemetry.api.common.AttributesBuilder
|
||||
import io.opentelemetry.api.trace.SpanKind
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil
|
||||
import java.util.function.Function
|
||||
|
||||
abstract class AbstractKtorServerTelemetryBuilder(private val instrumentationName: String) {
|
||||
companion object {
|
||||
init {
|
||||
KtorBuilderUtil.serverBuilderExtractor = { it.builder }
|
||||
}
|
||||
}
|
||||
|
||||
internal lateinit var builder: DefaultHttpServerInstrumenterBuilder<ApplicationRequest, ApplicationResponse>
|
||||
|
||||
internal var spanKindExtractor:
|
||||
(SpanKindExtractor<ApplicationRequest>) -> SpanKindExtractor<ApplicationRequest> = { a -> a }
|
||||
|
||||
fun setOpenTelemetry(openTelemetry: OpenTelemetry) {
|
||||
this.builder =
|
||||
DefaultHttpServerInstrumenterBuilder.create(
|
||||
instrumentationName,
|
||||
openTelemetry,
|
||||
KtorHttpServerAttributesGetter.INSTANCE
|
||||
)
|
||||
}
|
||||
|
||||
fun spanStatusExtractor(extract: SpanStatusData.(SpanStatusExtractor<in ApplicationRequest, in ApplicationResponse>) -> Unit) {
|
||||
builder.setStatusExtractor { prevExtractor ->
|
||||
SpanStatusExtractor { spanStatusBuilder: SpanStatusBuilder,
|
||||
request: ApplicationRequest,
|
||||
response: ApplicationResponse?,
|
||||
throwable: Throwable? ->
|
||||
extract(
|
||||
SpanStatusData(spanStatusBuilder, request, response, throwable),
|
||||
prevExtractor
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class SpanStatusData(
|
||||
val spanStatusBuilder: SpanStatusBuilder,
|
||||
val request: ApplicationRequest,
|
||||
val response: ApplicationResponse?,
|
||||
val error: Throwable?
|
||||
)
|
||||
|
||||
fun spanKindExtractor(extract: ApplicationRequest.(SpanKindExtractor<ApplicationRequest>) -> SpanKind) {
|
||||
spanKindExtractor = { prevExtractor ->
|
||||
SpanKindExtractor<ApplicationRequest> { request: ApplicationRequest ->
|
||||
extract(request, prevExtractor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun attributesExtractor(extractorBuilder: ExtractorBuilder.() -> Unit = {}) {
|
||||
val builder = ExtractorBuilder().apply(extractorBuilder).build()
|
||||
this.builder.addAttributesExtractor(
|
||||
object : AttributesExtractor<ApplicationRequest, ApplicationResponse> {
|
||||
override fun onStart(attributes: AttributesBuilder, parentContext: Context, request: ApplicationRequest) {
|
||||
builder.onStart(OnStartData(attributes, parentContext, request))
|
||||
}
|
||||
|
||||
override fun onEnd(attributes: AttributesBuilder, context: Context, request: ApplicationRequest, response: ApplicationResponse?, error: Throwable?) {
|
||||
builder.onEnd(OnEndData(attributes, context, request, response, error))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun spanNameExtractor(spanNameExtractorTransformer: Function<SpanNameExtractor<in ApplicationRequest>, out SpanNameExtractor<in ApplicationRequest>>) {
|
||||
builder.setSpanNameExtractor(spanNameExtractorTransformer)
|
||||
}
|
||||
|
||||
class ExtractorBuilder {
|
||||
private var onStart: OnStartData.() -> Unit = {}
|
||||
private var onEnd: OnEndData.() -> Unit = {}
|
||||
|
||||
fun onStart(block: OnStartData.() -> Unit) {
|
||||
onStart = block
|
||||
}
|
||||
|
||||
fun onEnd(block: OnEndData.() -> Unit) {
|
||||
onEnd = block
|
||||
}
|
||||
|
||||
internal fun build(): Extractor {
|
||||
return Extractor(onStart, onEnd)
|
||||
}
|
||||
}
|
||||
|
||||
internal class Extractor(val onStart: OnStartData.() -> Unit, val onEnd: OnEndData.() -> Unit)
|
||||
|
||||
data class OnStartData(
|
||||
val attributes: AttributesBuilder,
|
||||
val parentContext: Context,
|
||||
val request: ApplicationRequest
|
||||
)
|
||||
|
||||
data class OnEndData(
|
||||
val attributes: AttributesBuilder,
|
||||
val parentContext: Context,
|
||||
val request: ApplicationRequest,
|
||||
val response: ApplicationResponse?,
|
||||
val error: Throwable?
|
||||
)
|
||||
|
||||
fun capturedRequestHeaders(vararg headers: String) = capturedRequestHeaders(headers.asIterable())
|
||||
|
||||
fun capturedRequestHeaders(headers: Iterable<String>) {
|
||||
builder.setCapturedRequestHeaders(headers.toList())
|
||||
}
|
||||
|
||||
fun capturedResponseHeaders(vararg headers: String) = capturedResponseHeaders(headers.asIterable())
|
||||
|
||||
fun capturedResponseHeaders(headers: Iterable<String>) {
|
||||
builder.setCapturedResponseHeaders(headers.toList())
|
||||
}
|
||||
|
||||
fun knownMethods(vararg methods: String) = knownMethods(methods.asIterable())
|
||||
|
||||
fun knownMethods(vararg methods: HttpMethod) = knownMethods(methods.asIterable())
|
||||
|
||||
@JvmName("knownMethodsJvm")
|
||||
fun knownMethods(methods: Iterable<HttpMethod>) = knownMethods(methods.map { it.value })
|
||||
|
||||
fun knownMethods(methods: Iterable<String>) {
|
||||
methods.toSet().apply {
|
||||
builder.setKnownMethods(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link #setOpenTelemetry(OpenTelemetry)} sets the serverBuilder to a non-null value.
|
||||
*/
|
||||
fun isOpenTelemetryInitialized(): Boolean = this::builder.isInitialized
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.server
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common
|
||||
|
||||
import io.ktor.server.request.*
|
||||
import io.opentelemetry.context.propagation.TextMapGetter
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.client
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common
|
||||
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
|
|
@ -3,9 +3,9 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.client
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common
|
||||
|
||||
import io.ktor.client.request.HttpRequestBuilder
|
||||
import io.ktor.client.request.*
|
||||
import io.opentelemetry.context.propagation.TextMapSetter
|
||||
|
||||
internal object KtorHttpHeadersSetter : TextMapSetter<HttpRequestBuilder> {
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.server
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common
|
||||
|
||||
import io.ktor.server.plugins.*
|
||||
import io.ktor.server.request.*
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.client
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.client
|
||||
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
|
|
@ -11,7 +11,9 @@ import io.ktor.client.statement.*
|
|||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.context.propagation.ContextPropagators
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.KtorHttpHeadersSetter
|
||||
|
||||
@Deprecated("Use AbstractKtorClientTelemetry instead", ReplaceWith("AbstractKtorClientTelemetry"))
|
||||
abstract class AbstractKtorClientTracing(
|
||||
private val instrumenter: Instrumenter<HttpRequestData, HttpResponse>,
|
||||
private val propagators: ContextPropagators,
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.client
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.client
|
||||
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
|
|
@ -14,15 +14,17 @@ import io.opentelemetry.context.Context
|
|||
import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.KtorHttpClientAttributesGetter
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtilOld
|
||||
import java.util.function.Function
|
||||
|
||||
@Deprecated("Use AbstractKtorClientTelemetryBuilder instead", ReplaceWith("AbstractKtorClientTelemetryBuilder"))
|
||||
abstract class AbstractKtorClientTracingBuilder(
|
||||
private val instrumentationName: String
|
||||
) {
|
||||
companion object {
|
||||
init {
|
||||
KtorBuilderUtil.clientBuilderExtractor = { it.clientBuilder }
|
||||
KtorBuilderUtilOld.clientBuilderExtractor = { it.clientBuilder }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,13 +163,14 @@ abstract class AbstractKtorClientTracingBuilder(
|
|||
*
|
||||
* @param emitExperimentalHttpClientMetrics `true` if the experimental HTTP client metrics are to be emitted.
|
||||
*/
|
||||
@Deprecated("Please use method `emitExperimentalHttpClientMetrics`")
|
||||
@Deprecated("Please use method `Experimental.emitExperimentalTelemetry`")
|
||||
fun setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientMetrics: Boolean) {
|
||||
if (emitExperimentalHttpClientMetrics) {
|
||||
emitExperimentalHttpClientMetrics()
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Please use method `Experimental.emitExperimentalTelemetry`")
|
||||
fun emitExperimentalHttpClientMetrics() {
|
||||
clientBuilder.setEmitExperimentalHttpClientMetrics(true)
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.internal
|
||||
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorClientTelemetryBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorServerTelemetryBuilder
|
||||
|
||||
class Experimental private constructor() {
|
||||
|
||||
companion object {
|
||||
fun emitExperimentalTelemetry(builder: AbstractKtorClientTelemetryBuilder) {
|
||||
builder.builder().setEmitExperimentalHttpClientMetrics(true)
|
||||
}
|
||||
|
||||
fun emitExperimentalTelemetry(builder: AbstractKtorServerTelemetryBuilder) {
|
||||
builder.builder.setEmitExperimentalHttpServerMetrics(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.internal
|
||||
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder
|
||||
import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorClientTelemetryBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorServerTelemetryBuilder
|
||||
|
||||
/**
|
||||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
* any time.
|
||||
*/
|
||||
object KtorBuilderUtil {
|
||||
lateinit var clientBuilderExtractor: (AbstractKtorClientTelemetryBuilder) -> DefaultHttpClientInstrumenterBuilder<HttpRequestData, HttpResponse>
|
||||
lateinit var serverBuilderExtractor: (
|
||||
AbstractKtorServerTelemetryBuilder
|
||||
) -> DefaultHttpServerInstrumenterBuilder<ApplicationRequest, ApplicationResponse>
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.internal
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.internal
|
||||
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
|
|
@ -11,14 +11,15 @@ import io.ktor.server.request.*
|
|||
import io.ktor.server.response.*
|
||||
import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder
|
||||
import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpServerInstrumenterBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTracingBuilder
|
||||
|
||||
/**
|
||||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
* any time.
|
||||
*/
|
||||
object KtorBuilderUtil {
|
||||
@Deprecated("Use KtorBuilderUtil instead", ReplaceWith("KtorBuilderUtil"))
|
||||
object KtorBuilderUtilOld {
|
||||
lateinit var clientBuilderExtractor: (AbstractKtorClientTracingBuilder) -> DefaultHttpClientInstrumenterBuilder<HttpRequestData, HttpResponse>
|
||||
lateinit var serverBuilderExtractor: (
|
||||
AbstractKtorServerTracingBuilder
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.internal
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.util.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.extension.kotlin.asContextElement
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientRequestResendCount
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorClientTelemetry
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
* any time.
|
||||
*/
|
||||
object KtorClientTelemetryUtil {
|
||||
private val openTelemetryContextKey = AttributeKey<Context>("OpenTelemetry")
|
||||
|
||||
fun install(plugin: AbstractKtorClientTelemetry, scope: HttpClient) {
|
||||
installSpanCreation(plugin, scope)
|
||||
installSpanEnd(plugin, scope)
|
||||
}
|
||||
|
||||
private fun installSpanCreation(plugin: AbstractKtorClientTelemetry, scope: HttpClient) {
|
||||
val initializeRequestPhase = PipelinePhase("OpenTelemetryInitializeRequest")
|
||||
scope.requestPipeline.insertPhaseAfter(HttpRequestPipeline.State, initializeRequestPhase)
|
||||
|
||||
scope.requestPipeline.intercept(initializeRequestPhase) {
|
||||
val openTelemetryContext = HttpClientRequestResendCount.initialize(Context.current())
|
||||
withContext(openTelemetryContext.asContextElement()) { proceed() }
|
||||
}
|
||||
|
||||
val createSpanPhase = PipelinePhase("OpenTelemetryCreateSpan")
|
||||
scope.sendPipeline.insertPhaseAfter(HttpSendPipeline.State, createSpanPhase)
|
||||
|
||||
scope.sendPipeline.intercept(createSpanPhase) {
|
||||
val requestBuilder = context
|
||||
val openTelemetryContext = plugin.createSpan(requestBuilder)
|
||||
|
||||
if (openTelemetryContext != null) {
|
||||
try {
|
||||
requestBuilder.attributes.put(openTelemetryContextKey, openTelemetryContext)
|
||||
plugin.populateRequestHeaders(requestBuilder, openTelemetryContext)
|
||||
|
||||
withContext(openTelemetryContext.asContextElement()) { proceed() }
|
||||
} catch (e: Throwable) {
|
||||
plugin.endSpan(openTelemetryContext, requestBuilder, null, e)
|
||||
throw e
|
||||
}
|
||||
} else {
|
||||
proceed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(InternalCoroutinesApi::class)
|
||||
private fun installSpanEnd(plugin: AbstractKtorClientTelemetry, scope: HttpClient) {
|
||||
val endSpanPhase = PipelinePhase("OpenTelemetryEndSpan")
|
||||
scope.receivePipeline.insertPhaseBefore(HttpReceivePipeline.State, endSpanPhase)
|
||||
|
||||
scope.receivePipeline.intercept(endSpanPhase) {
|
||||
val openTelemetryContext = it.call.attributes.getOrNull(openTelemetryContextKey)
|
||||
openTelemetryContext ?: return@intercept
|
||||
|
||||
scope.launch {
|
||||
val job = it.call.coroutineContext.job
|
||||
job.join()
|
||||
val cause = if (!job.isCancelled) {
|
||||
null
|
||||
} else {
|
||||
kotlin.runCatching { job.getCancellationException() }.getOrNull()
|
||||
}
|
||||
|
||||
plugin.endSpan(openTelemetryContext, it.call, cause)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.internal
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.internal
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.request.*
|
||||
|
|
@ -13,7 +13,7 @@ import io.ktor.util.pipeline.*
|
|||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.extension.kotlin.asContextElement
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientRequestResendCount
|
||||
import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracing
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracing
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.job
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -23,6 +23,7 @@ import kotlinx.coroutines.withContext
|
|||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
* any time.
|
||||
*/
|
||||
@Deprecated("Use KtorClientTelemetryUtil instead", ReplaceWith("KtorClientTelemetryUtil"))
|
||||
object KtorClientTracingUtil {
|
||||
private val openTelemetryContextKey = AttributeKey<Context>("OpenTelemetry")
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.internal
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.util.*
|
||||
import io.ktor.util.pipeline.*
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.extension.kotlin.asContextElement
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor
|
||||
import io.opentelemetry.instrumentation.api.internal.InstrumenterUtil
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorServerTelemetryBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.ApplicationRequestGetter
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
* any time.
|
||||
*/
|
||||
object KtorServerTelemetryUtil {
|
||||
|
||||
fun configureTelemetry(builder: AbstractKtorServerTelemetryBuilder, application: Application) {
|
||||
val contextKey = AttributeKey<Context>("OpenTelemetry")
|
||||
val errorKey = AttributeKey<Throwable>("OpenTelemetryException")
|
||||
|
||||
val instrumenter = instrumenter(builder)
|
||||
val tracer = KtorServerTracer(instrumenter)
|
||||
val startPhase = PipelinePhase("OpenTelemetry")
|
||||
|
||||
application.insertPhaseBefore(ApplicationCallPipeline.Monitoring, startPhase)
|
||||
application.intercept(startPhase) {
|
||||
val context = tracer.start(call)
|
||||
|
||||
if (context != null) {
|
||||
call.attributes.put(contextKey, context)
|
||||
withContext(context.asContextElement()) {
|
||||
try {
|
||||
proceed()
|
||||
} catch (err: Throwable) {
|
||||
// Stash error for reporting later since need ktor to finish setting up the response
|
||||
call.attributes.put(errorKey, err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
proceed()
|
||||
}
|
||||
}
|
||||
|
||||
val postSendPhase = PipelinePhase("OpenTelemetryPostSend")
|
||||
application.sendPipeline.insertPhaseAfter(ApplicationSendPipeline.After, postSendPhase)
|
||||
application.sendPipeline.intercept(postSendPhase) {
|
||||
val context = call.attributes.getOrNull(contextKey)
|
||||
if (context != null) {
|
||||
var error: Throwable? = call.attributes.getOrNull(errorKey)
|
||||
try {
|
||||
proceed()
|
||||
} catch (t: Throwable) {
|
||||
error = t
|
||||
throw t
|
||||
} finally {
|
||||
tracer.end(context, call, error)
|
||||
}
|
||||
} else {
|
||||
proceed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun instrumenter(builder: AbstractKtorServerTelemetryBuilder): Instrumenter<ApplicationRequest, ApplicationResponse> {
|
||||
return InstrumenterUtil.buildUpstreamInstrumenter(
|
||||
builder.builder.instrumenterBuilder(),
|
||||
ApplicationRequestGetter,
|
||||
builder.spanKindExtractor(SpanKindExtractor.alwaysServer())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.internal
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.internal
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.request.*
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.internal
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.internal
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.request.*
|
||||
|
|
@ -15,14 +15,15 @@ import io.opentelemetry.extension.kotlin.asContextElement
|
|||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor
|
||||
import io.opentelemetry.instrumentation.api.internal.InstrumenterUtil
|
||||
import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.server.ApplicationRequestGetter
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.ApplicationRequestGetter
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTracingBuilder
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
|
||||
* any time.
|
||||
*/
|
||||
@Deprecated("Use KtorServerTelemetryUtil instead", ReplaceWith("KtorServerTelemetryUtil"))
|
||||
object KtorServerTracingUtil {
|
||||
|
||||
fun configureTracing(builder: AbstractKtorServerTracingBuilder, application: Application) {
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.server
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.common.server
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.request.*
|
||||
|
|
@ -18,13 +18,15 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor
|
|||
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusBuilder
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.KtorHttpServerAttributesGetter
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtilOld
|
||||
import java.util.function.Function
|
||||
|
||||
@Deprecated("Use AbstractKtorServerTelemetryBuilder instead", ReplaceWith("AbstractKtorServerTelemetryBuilder"))
|
||||
abstract class AbstractKtorServerTracingBuilder(private val instrumentationName: String) {
|
||||
companion object {
|
||||
init {
|
||||
KtorBuilderUtil.serverBuilderExtractor = { it.serverBuilder }
|
||||
KtorBuilderUtilOld.serverBuilderExtractor = { it.serverBuilder }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -13,9 +13,9 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import io.ktor.client.HttpClientConfig;
|
||||
import io.ktor.client.engine.HttpClientEngineConfig;
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.client.KtorClientTracing;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.client.KtorClientTracingBuilder;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.KtorClientTelemetry;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.KtorClientTelemetryBuilder;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
|
|
@ -46,14 +46,14 @@ public class HttpClientInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodEnter
|
||||
public static void onEnter(
|
||||
@Advice.Argument(1) HttpClientConfig<HttpClientEngineConfig> httpClientConfig) {
|
||||
httpClientConfig.install(KtorClientTracing.Companion, new SetupFunction());
|
||||
httpClientConfig.install(KtorClientTelemetry.Companion, new SetupFunction());
|
||||
}
|
||||
}
|
||||
|
||||
public static class SetupFunction implements Function1<KtorClientTracingBuilder, Unit> {
|
||||
public static class SetupFunction implements Function1<KtorClientTelemetryBuilder, Unit> {
|
||||
|
||||
@Override
|
||||
public Unit invoke(KtorClientTracingBuilder builder) {
|
||||
public Unit invoke(KtorClientTelemetryBuilder builder) {
|
||||
builder.setOpenTelemetry(GlobalOpenTelemetry.get());
|
||||
KtorBuilderUtil.clientBuilderExtractor.invoke(builder).configure(AgentCommonConfig.get());
|
||||
return kotlin.Unit.INSTANCE;
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import io.ktor.server.application.Application;
|
||||
import io.ktor.server.application.ApplicationPluginKt;
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil;
|
||||
import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.server.KtorServerTracingBuilderKt;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.KtorServerTelemetryBuilderKt;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorServerTelemetryBuilder;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
|
|
@ -41,15 +41,15 @@ public class ServerInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodExit
|
||||
public static void onExit(@Advice.FieldValue("_applicationInstance") Application application) {
|
||||
ApplicationPluginKt.install(
|
||||
application, KtorServerTracingBuilderKt.getKtorServerTracing(), new SetupFunction());
|
||||
application, KtorServerTelemetryBuilderKt.getKtorServerTelemetry(), new SetupFunction());
|
||||
}
|
||||
}
|
||||
|
||||
public static class SetupFunction
|
||||
implements Function1<AbstractKtorServerTracingBuilder, kotlin.Unit> {
|
||||
implements Function1<AbstractKtorServerTelemetryBuilder, kotlin.Unit> {
|
||||
|
||||
@Override
|
||||
public Unit invoke(AbstractKtorServerTracingBuilder builder) {
|
||||
public Unit invoke(AbstractKtorServerTelemetryBuilder builder) {
|
||||
builder.setOpenTelemetry(GlobalOpenTelemetry.get());
|
||||
KtorBuilderUtil.serverBuilderExtractor.invoke(builder).configure(AgentCommonConfig.get());
|
||||
return kotlin.Unit.INSTANCE;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.client
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0.server
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
# Library Instrumentation for Ktor version 2.x
|
||||
|
||||
This package contains libraries to help instrument Ktor. Server and client instrumentations are supported.
|
||||
This package contains libraries to help instrument Ktor.
|
||||
Server and client instrumentations are supported.
|
||||
|
||||
## Quickstart
|
||||
|
||||
|
|
@ -31,14 +32,14 @@ implementation("io.opentelemetry.instrumentation:opentelemetry-ktor-2.0:OPENTELE
|
|||
|
||||
## Initializing server instrumentation
|
||||
|
||||
Initialize instrumentation by installing the `KtorServerTracing` feature. You must set the `OpenTelemetry` to use with
|
||||
the feature.
|
||||
Initialize instrumentation by installing the `KtorServerTelemetry` feature.
|
||||
You must set the `OpenTelemetry` to use with the feature.
|
||||
|
||||
```kotlin
|
||||
val openTelemetry: OpenTelemetry = ...
|
||||
|
||||
embeddedServer(Netty, 8080) {
|
||||
install(KtorServerTracing) {
|
||||
install(KtorServerTelemetry) {
|
||||
setOpenTelemetry(openTelemetry)
|
||||
}
|
||||
}
|
||||
|
|
@ -46,14 +47,15 @@ embeddedServer(Netty, 8080) {
|
|||
|
||||
## Initializing client instrumentation
|
||||
|
||||
Initialize instrumentation by installing the `KtorClientTracing` feature. You must set the `OpenTelemetry` to use with
|
||||
Initialize instrumentation by installing the `KtorClientTelemetry` feature. You must set the
|
||||
`OpenTelemetry` to use with
|
||||
the feature.
|
||||
|
||||
```kotlin
|
||||
val openTelemetry: OpenTelemetry = ...
|
||||
|
||||
val client = HttpClient {
|
||||
install(KtorClientTracing) {
|
||||
install(KtorClientTelemetry) {
|
||||
setOpenTelemetry(openTelemetry)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.plugins.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.util.*
|
||||
import io.opentelemetry.context.propagation.ContextPropagators
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorClientTelemetry
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorClientTelemetryUtil
|
||||
|
||||
class KtorClientTelemetry internal constructor(
|
||||
instrumenter: Instrumenter<HttpRequestData, HttpResponse>,
|
||||
propagators: ContextPropagators
|
||||
) : AbstractKtorClientTelemetry(instrumenter, propagators) {
|
||||
|
||||
companion object : HttpClientPlugin<KtorClientTelemetryBuilder, KtorClientTelemetry> {
|
||||
|
||||
override val key = AttributeKey<KtorClientTelemetry>("OpenTelemetry")
|
||||
|
||||
override fun prepare(block: KtorClientTelemetryBuilder.() -> Unit) = KtorClientTelemetryBuilder().apply(block).build()
|
||||
|
||||
override fun install(plugin: KtorClientTelemetry, scope: HttpClient) {
|
||||
KtorClientTelemetryUtil.install(plugin, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.InstrumentationProperties.INSTRUMENTATION_NAME
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorClientTelemetryBuilder
|
||||
|
||||
class KtorClientTelemetryBuilder : AbstractKtorClientTelemetryBuilder(INSTRUMENTATION_NAME) {
|
||||
|
||||
internal fun build(): KtorClientTelemetry = KtorClientTelemetry(
|
||||
instrumenter = builder.build(),
|
||||
propagators = getOpenTelemetry().propagators,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.InstrumentationProperties.INSTRUMENTATION_NAME
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorServerTelemetryBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorServerTelemetryUtil
|
||||
|
||||
class KtorServerTelemetryBuilder internal constructor(
|
||||
instrumentationName: String
|
||||
) : AbstractKtorServerTelemetryBuilder(instrumentationName)
|
||||
|
||||
val KtorServerTelemetry = createRouteScopedPlugin("OpenTelemetry", { KtorServerTelemetryBuilder(INSTRUMENTATION_NAME) }) {
|
||||
require(pluginConfig.isOpenTelemetryInitialized()) { "OpenTelemetry must be set" }
|
||||
|
||||
KtorServerTelemetryUtil.configureTelemetry(pluginConfig, application)
|
||||
|
||||
application.environment.monitor.subscribe(Routing.RoutingCallStarted) { call ->
|
||||
HttpServerRoute.update(Context.current(), HttpServerRouteSource.SERVER, { _, arg -> arg.route.parent.toString() }, call)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,9 +12,10 @@ import io.ktor.client.statement.*
|
|||
import io.ktor.util.*
|
||||
import io.opentelemetry.context.propagation.ContextPropagators
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter
|
||||
import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracing
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorClientTracingUtil
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracing
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorClientTracingUtil
|
||||
|
||||
@Deprecated("Use KtorClientTelemetry instead", ReplaceWith("KtorClientTelemetry"))
|
||||
class KtorClientTracing internal constructor(
|
||||
instrumenter: Instrumenter<HttpRequestData, HttpResponse>,
|
||||
propagators: ContextPropagators
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.client
|
||||
|
||||
import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.InstrumentationProperties.INSTRUMENTATION_NAME
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracingBuilder
|
||||
|
||||
@Deprecated("Use KtorClientTelemetryBuilder instead", ReplaceWith("KtorClientTelemetryBuilder"))
|
||||
class KtorClientTracingBuilder : AbstractKtorClientTracingBuilder(INSTRUMENTATION_NAME) {
|
||||
|
||||
internal fun build(): KtorClientTracing = KtorClientTracing(
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@ import io.ktor.server.routing.*
|
|||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorServerTracingUtil
|
||||
import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.InstrumentationProperties.INSTRUMENTATION_NAME
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorServerTracingUtil
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTracingBuilder
|
||||
|
||||
@Deprecated("Use KtorServerTelemetryBuilder instead", ReplaceWith("KtorServerTelemetryBuilder"))
|
||||
class KtorServerTracingBuilder internal constructor(
|
||||
instrumentationName: String
|
||||
) : AbstractKtorServerTracingBuilder(instrumentationName)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.client.KtorClientTracing
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
|
||||
class KtorHttpClientOldTest : AbstractKtorHttpClientTest() {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@RegisterExtension
|
||||
private val TESTING = HttpClientInstrumentationExtension.forLibrary()
|
||||
}
|
||||
|
||||
override fun HttpClientConfig<*>.installTracing() {
|
||||
install(KtorClientTracing) {
|
||||
setOpenTelemetry(TESTING.openTelemetry)
|
||||
capturedRequestHeaders(TEST_REQUEST_HEADER)
|
||||
capturedResponseHeaders(TEST_RESPONSE_HEADER)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0.client
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension
|
||||
|
|
@ -18,7 +18,7 @@ class KtorHttpClientTest : AbstractKtorHttpClientTest() {
|
|||
}
|
||||
|
||||
override fun HttpClientConfig<*>.installTracing() {
|
||||
install(KtorClientTracing) {
|
||||
install(KtorClientTelemetry) {
|
||||
setOpenTelemetry(TESTING.openTelemetry)
|
||||
capturedRequestHeaders(TEST_REQUEST_HEADER)
|
||||
capturedResponseHeaders(TEST_RESPONSE_HEADER)
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
|
||||
class KtorHttpServerOldTest : AbstractKtorHttpServerTest() {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@RegisterExtension
|
||||
val TESTING: InstrumentationExtension = HttpServerInstrumentationExtension.forLibrary()
|
||||
}
|
||||
|
||||
override fun getTesting(): InstrumentationExtension {
|
||||
return TESTING
|
||||
}
|
||||
|
||||
override fun installOpenTelemetry(application: Application) {
|
||||
KtorOldTestUtil.installOpenTelemetry(application, TESTING.openTelemetry)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.server
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.opentelemetry.api.OpenTelemetry
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.server.KtorServerTracing
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest
|
||||
|
||||
class KtorOldTestUtil {
|
||||
companion object {
|
||||
fun installOpenTelemetry(application: Application, openTelemetry: OpenTelemetry) {
|
||||
application.install(KtorServerTracing) {
|
||||
setOpenTelemetry(openTelemetry)
|
||||
capturedRequestHeaders(AbstractHttpServerTest.TEST_REQUEST_HEADER)
|
||||
capturedResponseHeaders(AbstractHttpServerTest.TEST_RESPONSE_HEADER)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.server
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
|
|
@ -13,6 +13,7 @@ import io.ktor.server.request.*
|
|||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.opentelemetry.api.trace.SpanKind
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.server.KtorServerTracing
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerUsingTest
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.server
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.opentelemetry.api.OpenTelemetry
|
||||
|
|
@ -12,7 +12,7 @@ import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTes
|
|||
class KtorTestUtil {
|
||||
companion object {
|
||||
fun installOpenTelemetry(application: Application, openTelemetry: OpenTelemetry) {
|
||||
application.install(KtorServerTracing) {
|
||||
application.install(KtorServerTelemetry) {
|
||||
setOpenTelemetry(openTelemetry)
|
||||
capturedRequestHeaders(AbstractHttpServerTest.TEST_REQUEST_HEADER)
|
||||
capturedResponseHeaders(AbstractHttpServerTest.TEST_RESPONSE_HEADER)
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.client
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.cio.*
|
||||
|
|
@ -17,7 +17,10 @@ import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult
|
|||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions.DEFAULT_HTTP_ATTRIBUTES
|
||||
import io.opentelemetry.semconv.NetworkAttributes
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.jupiter.api.AfterAll
|
||||
import java.net.URI
|
||||
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.server
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
|
|
@ -3,10 +3,9 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.client
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.cio.*
|
||||
import io.ktor.client.request.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
|
@ -13,9 +13,9 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
|||
import io.ktor.client.HttpClientConfig;
|
||||
import io.ktor.client.engine.HttpClientEngineConfig;
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil;
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.client.KtorClientTracing;
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.client.KtorClientTracingBuilder;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil;
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.KtorClientTelemetry;
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.KtorClientTelemetryBuilder;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
|
|
@ -46,14 +46,14 @@ public class HttpClientInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodEnter
|
||||
public static void onEnter(
|
||||
@Advice.Argument(1) HttpClientConfig<HttpClientEngineConfig> httpClientConfig) {
|
||||
httpClientConfig.install(KtorClientTracing.Companion, new SetupFunction());
|
||||
httpClientConfig.install(KtorClientTelemetry.Companion, new SetupFunction());
|
||||
}
|
||||
}
|
||||
|
||||
public static class SetupFunction implements Function1<KtorClientTracingBuilder, Unit> {
|
||||
public static class SetupFunction implements Function1<KtorClientTelemetryBuilder, Unit> {
|
||||
|
||||
@Override
|
||||
public Unit invoke(KtorClientTracingBuilder builder) {
|
||||
public Unit invoke(KtorClientTelemetryBuilder builder) {
|
||||
builder.setOpenTelemetry(GlobalOpenTelemetry.get());
|
||||
KtorBuilderUtil.clientBuilderExtractor.invoke(builder).configure(AgentCommonConfig.get());
|
||||
return Unit.INSTANCE;
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import io.ktor.server.application.Application;
|
||||
import io.ktor.server.application.ApplicationPluginKt;
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorBuilderUtil;
|
||||
import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder;
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.server.KtorServerTracingBuilderKt;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorServerTelemetryBuilder;
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil;
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.KtorServerTelemetryBuilderKt;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
|
|
@ -41,14 +41,14 @@ public class ServerInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodExit
|
||||
public static void onExit(@Advice.FieldValue("_applicationInstance") Application application) {
|
||||
ApplicationPluginKt.install(
|
||||
application, KtorServerTracingBuilderKt.getKtorServerTracing(), new SetupFunction());
|
||||
application, KtorServerTelemetryBuilderKt.getKtorServerTelemetry(), new SetupFunction());
|
||||
}
|
||||
}
|
||||
|
||||
public static class SetupFunction implements Function1<AbstractKtorServerTracingBuilder, Unit> {
|
||||
public static class SetupFunction implements Function1<AbstractKtorServerTelemetryBuilder, Unit> {
|
||||
|
||||
@Override
|
||||
public Unit invoke(AbstractKtorServerTracingBuilder builder) {
|
||||
public Unit invoke(AbstractKtorServerTelemetryBuilder builder) {
|
||||
builder.setOpenTelemetry(GlobalOpenTelemetry.get());
|
||||
KtorBuilderUtil.serverBuilderExtractor.invoke(builder).configure(AgentCommonConfig.get());
|
||||
return Unit.INSTANCE;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0.client
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.server
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
# Library Instrumentation for Ktor version 3.0 and higher
|
||||
|
||||
This package contains libraries to help instrument Ktor. Server and client instrumentations are supported.
|
||||
This package contains libraries to help instrument Ktor.
|
||||
Server and client instrumentations are supported.
|
||||
|
||||
## Quickstart
|
||||
|
||||
|
|
@ -31,14 +32,14 @@ implementation("io.opentelemetry.instrumentation:opentelemetry-ktor-3.0:OPENTELE
|
|||
|
||||
## Initializing server instrumentation
|
||||
|
||||
Initialize instrumentation by installing the `KtorServerTracing` feature. You must set the `OpenTelemetry` to use with
|
||||
the feature.
|
||||
Initialize instrumentation by installing the `KtorServerTelemetry` feature.
|
||||
You must set the `OpenTelemetry` to use with the feature.
|
||||
|
||||
```kotlin
|
||||
val openTelemetry: OpenTelemetry = ...
|
||||
|
||||
embeddedServer(Netty, 8080) {
|
||||
install(KtorServerTracing) {
|
||||
install(KtorServerTelemetry) {
|
||||
setOpenTelemetry(openTelemetry)
|
||||
}
|
||||
}
|
||||
|
|
@ -46,14 +47,15 @@ embeddedServer(Netty, 8080) {
|
|||
|
||||
## Initializing client instrumentation
|
||||
|
||||
Initialize instrumentation by installing the `KtorClientTracing` feature. You must set the `OpenTelemetry` to use with
|
||||
Initialize instrumentation by installing the `KtorClientTelemetry` feature. You must set the
|
||||
`OpenTelemetry` to use with
|
||||
the feature.
|
||||
|
||||
```kotlin
|
||||
val openTelemetry: OpenTelemetry = ...
|
||||
|
||||
val client = HttpClient {
|
||||
install(KtorClientTracing) {
|
||||
install(KtorClientTelemetry) {
|
||||
setOpenTelemetry(openTelemetry)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.plugins.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.util.*
|
||||
import io.opentelemetry.context.propagation.ContextPropagators
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorClientTelemetry
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorClientTelemetryUtil
|
||||
|
||||
class KtorClientTelemetry internal constructor(
|
||||
instrumenter: Instrumenter<HttpRequestData, HttpResponse>,
|
||||
propagators: ContextPropagators
|
||||
) : AbstractKtorClientTelemetry(instrumenter, propagators) {
|
||||
|
||||
companion object : HttpClientPlugin<KtorClientTelemetryBuilder, KtorClientTelemetry> {
|
||||
|
||||
override val key = AttributeKey<KtorClientTelemetry>("OpenTelemetry")
|
||||
|
||||
override fun prepare(block: KtorClientTelemetryBuilder.() -> Unit) = KtorClientTelemetryBuilder().apply(block).build()
|
||||
|
||||
override fun install(plugin: KtorClientTelemetry, scope: HttpClient) {
|
||||
KtorClientTelemetryUtil.install(plugin, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorClientTelemetryBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.InstrumentationProperties.INSTRUMENTATION_NAME
|
||||
|
||||
class KtorClientTelemetryBuilder : AbstractKtorClientTelemetryBuilder(INSTRUMENTATION_NAME) {
|
||||
|
||||
internal fun build(): KtorClientTelemetry = KtorClientTelemetry(
|
||||
instrumenter = builder.build(),
|
||||
propagators = getOpenTelemetry().propagators,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.routing.*
|
||||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorServerTelemetryBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorServerTelemetryUtil
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.InstrumentationProperties.INSTRUMENTATION_NAME
|
||||
|
||||
class KtorServerTelemetryBuilder internal constructor(
|
||||
instrumentationName: String
|
||||
) : AbstractKtorServerTelemetryBuilder(instrumentationName)
|
||||
|
||||
val KtorServerTelemetry = createRouteScopedPlugin("OpenTelemetry", { KtorServerTelemetryBuilder(INSTRUMENTATION_NAME) }) {
|
||||
require(pluginConfig.isOpenTelemetryInitialized()) { "OpenTelemetry must be set" }
|
||||
|
||||
KtorServerTelemetryUtil.configureTelemetry(pluginConfig, application)
|
||||
|
||||
application.monitor.subscribe(RoutingRoot.RoutingCallStarted) { call ->
|
||||
HttpServerRoute.update(Context.current(), HttpServerRouteSource.SERVER, { _, arg -> arg.route.parent.toString() }, call)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,9 +12,10 @@ import io.ktor.client.statement.*
|
|||
import io.ktor.util.*
|
||||
import io.opentelemetry.context.propagation.ContextPropagators
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter
|
||||
import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracing
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorClientTracingUtil
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracing
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorClientTracingUtil
|
||||
|
||||
@Deprecated("Use KtorClientTelemetry instead", ReplaceWith("KtorClientTelemetry"))
|
||||
class KtorClientTracing internal constructor(
|
||||
instrumenter: Instrumenter<HttpRequestData, HttpResponse>,
|
||||
propagators: ContextPropagators
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0.client
|
||||
|
||||
import io.opentelemetry.instrumentation.ktor.client.AbstractKtorClientTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.client.AbstractKtorClientTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.InstrumentationProperties.INSTRUMENTATION_NAME
|
||||
|
||||
@Deprecated("Use KtorClientTelemetryBuilder instead", ReplaceWith("KtorClientTelemetryBuilder"))
|
||||
class KtorClientTracingBuilder : AbstractKtorClientTracingBuilder(INSTRUMENTATION_NAME) {
|
||||
|
||||
internal fun build(): KtorClientTracing = KtorClientTracing(
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@ import io.ktor.server.routing.*
|
|||
import io.opentelemetry.context.Context
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource
|
||||
import io.opentelemetry.instrumentation.ktor.internal.KtorServerTracingUtil
|
||||
import io.opentelemetry.instrumentation.ktor.server.AbstractKtorServerTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorServerTracingUtil
|
||||
import io.opentelemetry.instrumentation.ktor.v2_0.common.server.AbstractKtorServerTracingBuilder
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.InstrumentationProperties.INSTRUMENTATION_NAME
|
||||
|
||||
@Deprecated("Use KtorServerTelemetryBuilder instead", ReplaceWith("KtorServerTelemetryBuilder"))
|
||||
class KtorServerTracingBuilder internal constructor(
|
||||
instrumentationName: String
|
||||
) : AbstractKtorServerTracingBuilder(instrumentationName)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.client.KtorClientTracing
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
|
||||
class KtorHttpClientOldTest : AbstractKtorHttpClientTest() {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@RegisterExtension
|
||||
private val TESTING = HttpClientInstrumentationExtension.forLibrary()
|
||||
}
|
||||
|
||||
override fun HttpClientConfig<*>.installTracing() {
|
||||
install(KtorClientTracing) {
|
||||
setOpenTelemetry(TESTING.openTelemetry)
|
||||
capturedRequestHeaders(TEST_REQUEST_HEADER)
|
||||
capturedResponseHeaders(TEST_RESPONSE_HEADER)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v2_0.client
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension
|
||||
|
|
@ -18,7 +18,7 @@ class KtorHttpClientTest : AbstractKtorHttpClientTest() {
|
|||
}
|
||||
|
||||
override fun HttpClientConfig<*>.installTracing() {
|
||||
install(KtorClientTracing) {
|
||||
install(KtorClientTelemetry) {
|
||||
setOpenTelemetry(TESTING.openTelemetry)
|
||||
capturedRequestHeaders(TEST_REQUEST_HEADER)
|
||||
capturedResponseHeaders(TEST_RESPONSE_HEADER)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.opentelemetry.instrumentation.ktor.v3_0.server.KtorServerTracing
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
|
||||
class KtorHttpServerOldTest : AbstractKtorHttpServerTest() {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@RegisterExtension
|
||||
val TESTING: InstrumentationExtension = HttpServerInstrumentationExtension.forLibrary()
|
||||
}
|
||||
|
||||
override fun getTesting(): InstrumentationExtension {
|
||||
return TESTING
|
||||
}
|
||||
|
||||
override fun installOpenTelemetry(application: Application) {
|
||||
application.apply {
|
||||
install(KtorServerTracing) {
|
||||
setOpenTelemetry(TESTING.openTelemetry)
|
||||
capturedRequestHeaders(TEST_REQUEST_HEADER)
|
||||
capturedResponseHeaders(TEST_RESPONSE_HEADER)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0.server
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.server.application.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension
|
||||
|
|
@ -24,7 +24,7 @@ class KtorHttpServerTest : AbstractKtorHttpServerTest() {
|
|||
|
||||
override fun installOpenTelemetry(application: Application) {
|
||||
application.apply {
|
||||
install(KtorServerTracing) {
|
||||
install(KtorServerTelemetry) {
|
||||
setOpenTelemetry(TESTING.openTelemetry)
|
||||
capturedRequestHeaders(TEST_REQUEST_HEADER)
|
||||
capturedResponseHeaders(TEST_RESPONSE_HEADER)
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0.client
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.cio.*
|
||||
|
|
@ -17,7 +17,10 @@ import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult
|
|||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions.DEFAULT_HTTP_ATTRIBUTES
|
||||
import io.opentelemetry.semconv.NetworkAttributes
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.jupiter.api.AfterAll
|
||||
import java.net.URI
|
||||
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0.server
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
|
|
@ -3,10 +3,9 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0.client
|
||||
package io.opentelemetry.instrumentation.ktor.v3_0
|
||||
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.engine.cio.*
|
||||
import io.ktor.client.request.*
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
||||
import kotlinx.coroutines.runBlocking
|
||||
Loading…
Reference in New Issue