Skip to content

Commit 6ae87ad

Browse files
authored
okhttp auto config for spring boot 2 and 3 (#6139)
1 parent cddf3fa commit 6ae87ad

22 files changed

Lines changed: 1051 additions & 4 deletions

File tree

‎sentry-samples/sentry-samples-spring-boot-jakarta/build.gradle.kts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ dependencies {
7373
// OpenFeature SDK
7474
implementation(libs.openfeature)
7575

76+
// okhttp client instrumentation
77+
implementation(projects.sentryOkhttp)
78+
implementation(libs.okhttp)
79+
7680
// database query tracing
7781
implementation(projects.sentryJdbc)
7882
runtimeOnly(libs.hsqldb)

‎sentry-samples/sentry-samples-spring-boot-jakarta/src/main/java/io/sentry/samples/spring/boot/jakarta/SentryDemoApplication.java‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import io.sentry.samples.spring.boot.jakarta.quartz.SampleJob;
66
import java.util.Collections;
7+
import okhttp3.OkHttpClient;
78
import org.quartz.JobDetail;
89
import org.quartz.SimpleTrigger;
910
import org.springframework.boot.SpringApplication;
@@ -42,6 +43,12 @@ RestClient restClient(RestClient.Builder builder) {
4243
return builder.build();
4344
}
4445

46+
@Bean
47+
OkHttpClient okHttpClient() {
48+
// automatically instrumented by Sentry via sentry.clients.ok-http-enabled=true
49+
return new OkHttpClient.Builder().build();
50+
}
51+
4552
@Bean
4653
public JobDetailFactoryBean jobDetail() {
4754
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();

‎sentry-samples/sentry-samples-spring-boot-jakarta/src/main/java/io/sentry/samples/spring/boot/jakarta/TodoController.java‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package io.sentry.samples.spring.boot.jakarta;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
34
import io.sentry.reactor.SentryReactorUtils;
5+
import java.io.IOException;
6+
import java.io.UncheckedIOException;
7+
import okhttp3.OkHttpClient;
8+
import okhttp3.Request;
9+
import okhttp3.Response;
410
import org.springframework.web.bind.annotation.GetMapping;
511
import org.springframework.web.bind.annotation.PathVariable;
612
import org.springframework.web.bind.annotation.RestController;
@@ -16,11 +22,20 @@ public class TodoController {
1622
private final RestTemplate restTemplate;
1723
private final WebClient webClient;
1824
private final RestClient restClient;
25+
private final OkHttpClient okHttpClient;
26+
private final ObjectMapper objectMapper;
1927

20-
public TodoController(RestTemplate restTemplate, WebClient webClient, RestClient restClient) {
28+
public TodoController(
29+
RestTemplate restTemplate,
30+
WebClient webClient,
31+
RestClient restClient,
32+
OkHttpClient okHttpClient,
33+
ObjectMapper objectMapper) {
2134
this.restTemplate = restTemplate;
2235
this.webClient = webClient;
2336
this.restClient = restClient;
37+
this.okHttpClient = okHttpClient;
38+
this.objectMapper = objectMapper;
2439
}
2540

2641
@GetMapping("/todo/{id}")
@@ -54,4 +69,15 @@ Todo todoRestClient(@PathVariable Long id) {
5469
.retrieve()
5570
.body(Todo.class);
5671
}
72+
73+
@GetMapping("/todo-okhttp/{id}")
74+
Todo todoOkHttp(@PathVariable Long id) {
75+
final Request request =
76+
new Request.Builder().url("https://jsonplaceholder.typicode.com/todos/" + id).build();
77+
try (Response response = okHttpClient.newCall(request).execute()) {
78+
return objectMapper.readValue(response.body().byteStream(), Todo.class);
79+
} catch (IOException e) {
80+
throw new UncheckedIOException(e);
81+
}
82+
}
5783
}

‎sentry-samples/sentry-samples-spring-boot-jakarta/src/main/resources/application.properties‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ spring.quartz.job-store-type=memory
3737

3838
# Cache tracing
3939
sentry.enable-cache-tracing=true
40+
# Automatically instrument Spring-managed OkHttpClient beans
41+
sentry.clients.ok-http-enabled=true
4042

4143
spring.cache.cache-names=todos
4244
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s

‎sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,20 @@ class TodoSystemTest {
5858
)
5959
}
6060
}
61+
62+
@Test
63+
fun `get todo okhttp works`() {
64+
val restClient = testHelper.restClient
65+
restClient.getTodoOkHttp(1L)
66+
assertEquals(200, restClient.lastKnownStatusCode)
67+
68+
testHelper.ensureTransactionReceived { transaction, envelopeHeader ->
69+
transaction.transaction == "GET /todo-okhttp/{id}" &&
70+
testHelper.doesTransactionContainSpanWithOpAndDescription(
71+
transaction,
72+
"http.client",
73+
"GET https://jsonplaceholder.typicode.com/todos/1",
74+
)
75+
}
76+
}
6177
}

‎sentry-samples/sentry-samples-spring-boot/build.gradle.kts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ dependencies {
7777
implementation(projects.sentryQuartz)
7878
implementation(projects.sentryAsyncProfiler)
7979

80+
// okhttp client instrumentation
81+
implementation(projects.sentryOkhttp)
82+
implementation(libs.okhttp)
83+
8084
// database query tracing
8185
implementation(projects.sentryJdbc)
8286
runtimeOnly(libs.hsqldb)

‎sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/SentryDemoApplication.java‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import io.sentry.samples.spring.boot.quartz.SampleJob;
66
import java.util.Collections;
7+
import okhttp3.OkHttpClient;
78
import org.quartz.JobDetail;
89
import org.quartz.SimpleTrigger;
910
import org.springframework.boot.SpringApplication;
@@ -36,6 +37,12 @@ WebClient webClient(WebClient.Builder builder) {
3637
return builder.build();
3738
}
3839

40+
@Bean
41+
OkHttpClient okHttpClient() {
42+
// automatically instrumented by Sentry via sentry.clients.ok-http-enabled=true
43+
return new OkHttpClient.Builder().build();
44+
}
45+
3946
@Bean
4047
public JobDetailFactoryBean jobDetail() {
4148
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();

‎sentry-samples/sentry-samples-spring-boot/src/main/java/io/sentry/samples/spring/boot/TodoController.java‎

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package io.sentry.samples.spring.boot;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import java.io.IOException;
5+
import java.io.UncheckedIOException;
6+
import okhttp3.OkHttpClient;
7+
import okhttp3.Request;
8+
import okhttp3.Response;
39
import org.springframework.web.bind.annotation.GetMapping;
410
import org.springframework.web.bind.annotation.PathVariable;
511
import org.springframework.web.bind.annotation.RestController;
@@ -10,10 +16,18 @@
1016
public class TodoController {
1117
private final RestTemplate restTemplate;
1218
private final WebClient webClient;
19+
private final OkHttpClient okHttpClient;
20+
private final ObjectMapper objectMapper;
1321

14-
public TodoController(RestTemplate restTemplate, WebClient webClient) {
22+
public TodoController(
23+
RestTemplate restTemplate,
24+
WebClient webClient,
25+
OkHttpClient okHttpClient,
26+
ObjectMapper objectMapper) {
1527
this.restTemplate = restTemplate;
1628
this.webClient = webClient;
29+
this.okHttpClient = okHttpClient;
30+
this.objectMapper = objectMapper;
1731
}
1832

1933
@GetMapping("/todo/{id}")
@@ -31,4 +45,15 @@ Todo todoWebClient(@PathVariable Long id) {
3145
.bodyToMono(Todo.class)
3246
.block();
3347
}
48+
49+
@GetMapping("/todo-okhttp/{id}")
50+
Todo todoOkHttp(@PathVariable Long id) {
51+
final Request request =
52+
new Request.Builder().url("https://jsonplaceholder.typicode.com/todos/" + id).build();
53+
try (Response response = okHttpClient.newCall(request).execute()) {
54+
return objectMapper.readValue(response.body().byteStream(), Todo.class);
55+
} catch (IOException e) {
56+
throw new UncheckedIOException(e);
57+
}
58+
}
3459
}

‎sentry-samples/sentry-samples-spring-boot/src/main/resources/application.properties‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ sentry.profile-lifecycle=TRACE
2222

2323
# Cache tracing
2424
sentry.enable-cache-tracing=true
25+
# Automatically instrument Spring-managed OkHttpClient beans
26+
sentry.clients.ok-http-enabled=true
2527
spring.cache.cache-names=todos
2628
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
2729

‎sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,20 @@ class TodoSystemTest {
4343
)
4444
}
4545
}
46+
47+
@Test
48+
fun `get todo okhttp works`() {
49+
val restClient = testHelper.restClient
50+
restClient.getTodoOkHttp(1L)
51+
assertEquals(200, restClient.lastKnownStatusCode)
52+
53+
testHelper.ensureTransactionReceived { transaction, envelopeHeader ->
54+
transaction.transaction == "GET /todo-okhttp/{id}" &&
55+
testHelper.doesTransactionContainSpanWithOpAndDescription(
56+
transaction,
57+
"http.client",
58+
"GET https://jsonplaceholder.typicode.com/todos/1",
59+
)
60+
}
61+
}
4662
}

0 commit comments

Comments
 (0)