Skip to content

Commit 2aa3669

Browse files
committed
Add Ktor 3.0.0 support
1 parent 4497fbf commit 2aa3669

File tree

28 files changed

+1536
-1
lines changed

28 files changed

+1536
-1
lines changed

docs/supported-libraries.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ These are the supported libraries and frameworks:
9292
| [Jodd Http](https://http.jodd.org/) | 4.2+ | N/A | [HTTP Client Spans], [HTTP Client Metrics] |
9393
| [JSP](https://javaee.github.io/javaee-spec/javadocs/javax/servlet/jsp/package-summary.html) | 2.3+ | N/A | Controller Spans [3] |
9494
| [Kotlin Coroutines](https://kotlinlang.org/docs/coroutines-overview.html) | 1.0+ | N/A | Context propagation |
95-
| [Ktor](https://github.com/ktorio/ktor) | 1.0+ | [opentelemetry-ktor-1.0](../instrumentation/ktor/ktor-1.0/library),<br>[opentelemetry-ktor-2.0](../instrumentation/ktor/ktor-2.0/library) | [HTTP Client Spans], [HTTP Client Metrics], [HTTP Server Spans], [HTTP Server Metrics] |
95+
| [Ktor](https://github.com/ktorio/ktor) | 1.0+ | [opentelemetry-ktor-1.0](../instrumentation/ktor/ktor-1.0/library),<br>[opentelemetry-ktor-2.0](../instrumentation/ktor/ktor-2.0/library),<br>[opentelemetry-ktor-3.0](../instrumentation/ktor/ktor-3.0/library) | [HTTP Client Spans], [HTTP Client Metrics], [HTTP Server Spans], [HTTP Server Metrics] |
9696
| [Kubernetes Client](https://github.com/kubernetes-client/java) | 7.0+ | N/A | [HTTP Client Spans] |
9797
| [Lettuce](https://github.com/lettuce-io/lettuce-core) | 4.0+ | [opentelemetry-lettuce-5.1](../instrumentation/lettuce/lettuce-5.1/library) | [Database Client Spans] |
9898
| [Log4j 1](https://logging.apache.org/log4j/1.2/) | 1.2+ | N/A | none |
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2+
3+
plugins {
4+
id("org.jetbrains.kotlin.jvm")
5+
id("otel.javaagent-instrumentation")
6+
}
7+
8+
muzzle {
9+
pass {
10+
group.set("org.jetbrains.kotlinx")
11+
module.set("ktor-server-core")
12+
versions.set("[3.0.0,)")
13+
assertInverse.set(true)
14+
}
15+
}
16+
17+
val ktorVersion = "3.0.0"
18+
19+
dependencies {
20+
library("io.ktor:ktor-client-core:$ktorVersion")
21+
library("io.ktor:ktor-server-core:$ktorVersion")
22+
23+
implementation(project(":instrumentation:ktor:ktor-3.0:library"))
24+
25+
compileOnly("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
26+
27+
testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent"))
28+
29+
testImplementation(project(":instrumentation:ktor:ktor-3.0:testing"))
30+
testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
31+
testImplementation("io.opentelemetry:opentelemetry-extension-kotlin")
32+
33+
testLibrary("io.ktor:ktor-server-netty:$ktorVersion")
34+
testLibrary("io.ktor:ktor-client-cio:$ktorVersion")
35+
36+
latestDepTestLibrary("io.ktor:ktor-client-core:3.+")
37+
latestDepTestLibrary("io.ktor:ktor-server-core:3.+")
38+
latestDepTestLibrary("io.ktor:ktor-server-netty:3.+")
39+
latestDepTestLibrary("io.ktor:ktor-client-cio:3.+")
40+
}
41+
42+
kotlin {
43+
compilerOptions {
44+
jvmTarget.set(JvmTarget.JVM_1_8)
45+
// generate metadata for Java 1.8 reflection on method parameters, used in @WithSpan tests
46+
javaParameters = true
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.ktor.v3_0;
7+
8+
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
9+
import static net.bytebuddy.matcher.ElementMatchers.named;
10+
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
11+
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
12+
13+
import io.ktor.client.HttpClientConfig;
14+
import io.ktor.client.engine.HttpClientEngineConfig;
15+
import io.opentelemetry.api.GlobalOpenTelemetry;
16+
import io.opentelemetry.instrumentation.ktor.v3_0.client.KtorClientTracing;
17+
import io.opentelemetry.instrumentation.ktor.v3_0.client.KtorClientTracingBuilder;
18+
import io.opentelemetry.instrumentation.ktor.v3_0.internal.KtorBuilderUtil;
19+
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
20+
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
21+
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
22+
import kotlin.Unit;
23+
import kotlin.jvm.functions.Function1;
24+
import net.bytebuddy.asm.Advice;
25+
import net.bytebuddy.description.type.TypeDescription;
26+
import net.bytebuddy.matcher.ElementMatcher;
27+
28+
public class HttpClientInstrumentation implements TypeInstrumentation {
29+
@Override
30+
public ElementMatcher<TypeDescription> typeMatcher() {
31+
return named("io.ktor.client.HttpClient");
32+
}
33+
34+
@Override
35+
public void transform(TypeTransformer transformer) {
36+
transformer.applyAdviceToMethod(
37+
isConstructor()
38+
.and(takesArguments(2))
39+
.and(takesArgument(1, named("io.ktor.client.HttpClientConfig"))),
40+
this.getClass().getName() + "$ConstructorAdvice");
41+
}
42+
43+
@SuppressWarnings("unused")
44+
public static class ConstructorAdvice {
45+
46+
@Advice.OnMethodEnter
47+
public static void onEnter(
48+
@Advice.Argument(1) HttpClientConfig<HttpClientEngineConfig> httpClientConfig) {
49+
httpClientConfig.install(KtorClientTracing.Companion, new SetupFunction());
50+
}
51+
}
52+
53+
public static class SetupFunction implements Function1<KtorClientTracingBuilder, Unit> {
54+
55+
@Override
56+
public Unit invoke(KtorClientTracingBuilder builder) {
57+
builder.setOpenTelemetry(GlobalOpenTelemetry.get());
58+
KtorBuilderUtil.clientBuilderExtractor.invoke(builder).configure(AgentCommonConfig.get());
59+
return kotlin.Unit.INSTANCE;
60+
}
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.ktor.v3_0;
7+
8+
import static java.util.Collections.singletonList;
9+
10+
import com.google.auto.service.AutoService;
11+
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
12+
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
13+
import java.util.List;
14+
15+
@AutoService(InstrumentationModule.class)
16+
public class KtorClientInstrumentationModule extends InstrumentationModule {
17+
18+
public KtorClientInstrumentationModule() {
19+
super("ktor", "ktor-client", "ktor-3.0", "ktor-client-3.0");
20+
}
21+
22+
@Override
23+
public boolean isHelperClass(String className) {
24+
return className.startsWith("io.opentelemetry.extension.kotlin.");
25+
}
26+
27+
@Override
28+
public List<TypeInstrumentation> typeInstrumentations() {
29+
return singletonList(new HttpClientInstrumentation());
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.ktor.v3_0;
7+
8+
import static java.util.Collections.singletonList;
9+
10+
import com.google.auto.service.AutoService;
11+
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
12+
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
13+
import java.util.List;
14+
15+
@AutoService(InstrumentationModule.class)
16+
public class KtorServerInstrumentationModule extends InstrumentationModule {
17+
18+
public KtorServerInstrumentationModule() {
19+
super("ktor", "ktor-server", "ktor-3.0", "ktor-server-3.0");
20+
}
21+
22+
@Override
23+
public boolean isHelperClass(String className) {
24+
return className.startsWith("io.opentelemetry.extension.kotlin.");
25+
}
26+
27+
@Override
28+
public List<TypeInstrumentation> typeInstrumentations() {
29+
return singletonList(new ServerInstrumentation());
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.ktor.v3_0;
7+
8+
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
9+
import static net.bytebuddy.matcher.ElementMatchers.named;
10+
11+
import io.ktor.server.application.Application;
12+
import io.ktor.server.application.ApplicationPluginKt;
13+
import io.opentelemetry.api.GlobalOpenTelemetry;
14+
import io.opentelemetry.instrumentation.ktor.v3_0.internal.KtorBuilderUtil;
15+
import io.opentelemetry.instrumentation.ktor.v3_0.server.KtorServerTracing;
16+
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
17+
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
18+
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
19+
import kotlin.Unit;
20+
import kotlin.jvm.functions.Function1;
21+
import net.bytebuddy.asm.Advice;
22+
import net.bytebuddy.description.type.TypeDescription;
23+
import net.bytebuddy.matcher.ElementMatcher;
24+
25+
public class ServerInstrumentation implements TypeInstrumentation {
26+
@Override
27+
public ElementMatcher<TypeDescription> typeMatcher() {
28+
return named("io.ktor.server.engine.ApplicationEngineEnvironmentReloading");
29+
}
30+
31+
@Override
32+
public void transform(TypeTransformer transformer) {
33+
transformer.applyAdviceToMethod(
34+
isConstructor(), this.getClass().getName() + "$ConstructorAdvice");
35+
}
36+
37+
@SuppressWarnings("unused")
38+
public static class ConstructorAdvice {
39+
40+
@Advice.OnMethodExit
41+
public static void onExit(@Advice.FieldValue("_applicationInstance") Application application) {
42+
ApplicationPluginKt.install(application, KtorServerTracing.Feature, new SetupFunction());
43+
}
44+
}
45+
46+
public static class SetupFunction
47+
implements Function1<KtorServerTracing.Configuration, kotlin.Unit> {
48+
49+
@Override
50+
public Unit invoke(KtorServerTracing.Configuration configuration) {
51+
configuration.setOpenTelemetry(GlobalOpenTelemetry.get());
52+
KtorBuilderUtil.serverBuilderExtractor
53+
.invoke(configuration)
54+
.configure(AgentCommonConfig.get());
55+
return kotlin.Unit.INSTANCE;
56+
}
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.ktor.v3_0.client
7+
8+
import io.ktor.client.*
9+
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension
10+
import org.junit.jupiter.api.extension.RegisterExtension
11+
12+
class KtorHttpClientTest : AbstractKtorHttpClientTest() {
13+
14+
companion object {
15+
@JvmStatic
16+
@RegisterExtension
17+
private val TESTING = HttpClientInstrumentationExtension.forAgent()
18+
}
19+
20+
override fun HttpClientConfig<*>.installTracing() {
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.ktor.v3_0.server
7+
8+
import io.ktor.server.application.*
9+
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension
10+
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension
11+
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions
12+
import org.junit.jupiter.api.extension.RegisterExtension
13+
14+
class KtorHttpServerTest : AbstractKtorHttpServerTest() {
15+
16+
companion object {
17+
@JvmStatic
18+
@RegisterExtension
19+
val TESTING: InstrumentationExtension = HttpServerInstrumentationExtension.forAgent()
20+
}
21+
22+
override fun getTesting(): InstrumentationExtension {
23+
return TESTING
24+
}
25+
26+
override fun installOpenTelemetry(application: Application) {
27+
}
28+
29+
override fun configure(options: HttpServerTestOptions) {
30+
super.configure(options)
31+
options.setTestException(false)
32+
}
33+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Library Instrumentation for Ktor version 3.0 and higher
2+
3+
This package contains libraries to help instrument Ktor. Server and client instrumentations are supported.
4+
5+
## Quickstart
6+
7+
### Add these dependencies to your project
8+
9+
Replace `OPENTELEMETRY_VERSION` with the [latest
10+
release](https://search.maven.org/search?q=g:io.opentelemetry.instrumentation%20AND%20a:opentelemetry-ktor-3.0).
11+
12+
For Maven, add to your `pom.xml` dependencies:
13+
14+
```xml
15+
<dependencies>
16+
<dependency>
17+
<groupId>io.opentelemetry.instrumentation</groupId>
18+
<artifactId>opentelemetry-ktor-3.0</artifactId>
19+
<version>OPENTELEMETRY_VERSION</version>
20+
</dependency>
21+
</dependencies>
22+
```
23+
24+
For Gradle, add to your dependencies:
25+
26+
```groovy
27+
implementation("io.opentelemetry.instrumentation:opentelemetry-ktor-3.0:OPENTELEMETRY_VERSION")
28+
```
29+
30+
## Usage
31+
32+
## Initializing server instrumentation
33+
34+
Initialize instrumentation by installing the `KtorServerTracing` feature. You must set the `OpenTelemetry` to use with
35+
the feature.
36+
37+
```kotlin
38+
val openTelemetry: OpenTelemetry = ...
39+
40+
embeddedServer(Netty, 8080) {
41+
install(KtorServerTracing) {
42+
setOpenTelemetry(openTelemetry)
43+
}
44+
}
45+
```
46+
47+
## Initializing client instrumentation
48+
49+
Initialize instrumentation by installing the `KtorClientTracing` feature. You must set the `OpenTelemetry` to use with
50+
the feature.
51+
52+
```kotlin
53+
val openTelemetry: OpenTelemetry = ...
54+
55+
val client = HttpClient {
56+
install(KtorClientTracing) {
57+
setOpenTelemetry(openTelemetry)
58+
}
59+
}
60+
```

0 commit comments

Comments
 (0)