Skip to content

Commit a23a379

Browse files
authored
Merge pull request #5183 from getsentry/feat/cache-tracing-all-samples
feat(samples): [Cache Tracing 7] Add cache tracing to all Spring Boot 4 samples
2 parents a3b5eb4 + dbb2998 commit a23a379

File tree

22 files changed

+378
-2
lines changed

22 files changed

+378
-2
lines changed

sentry-jcache/api/sentry-jcache.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ public final class io/sentry/jcache/BuildConfig {
44
}
55

66
public final class io/sentry/jcache/SentryJCacheWrapper : javax/cache/Cache {
7+
public fun <init> (Ljavax/cache/Cache;)V
78
public fun <init> (Ljavax/cache/Cache;Lio/sentry/IScopes;)V
89
public fun clear ()V
910
public fun close ()V

sentry-jcache/src/main/java/io/sentry/jcache/SentryJCacheWrapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.sentry.IScopes;
44
import io.sentry.ISpan;
5+
import io.sentry.ScopesAdapter;
56
import io.sentry.SpanDataConvention;
67
import io.sentry.SpanOptions;
78
import io.sentry.SpanStatus;
@@ -36,6 +37,10 @@ public final class SentryJCacheWrapper<K, V> implements Cache<K, V> {
3637
private final @NotNull Cache<K, V> delegate;
3738
private final @NotNull IScopes scopes;
3839

40+
public SentryJCacheWrapper(final @NotNull Cache<K, V> delegate) {
41+
this(delegate, ScopesAdapter.getInstance());
42+
}
43+
3944
public SentryJCacheWrapper(final @NotNull Cache<K, V> delegate, final @NotNull IScopes scopes) {
4045
this.delegate = delegate;
4146
this.scopes = scopes;

sentry-samples/sentry-samples-console/src/main/java/io/sentry/samples/console/Main.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ private static void demonstrateCacheTracing() {
211211
Cache<String, String> rawCache = cacheManager.createCache("myCache", config);
212212

213213
// Wrap with SentryJCacheWrapper to enable cache tracing
214-
Cache<String, String> cache = new SentryJCacheWrapper<>(rawCache, Sentry.getCurrentScopes());
214+
Cache<String, String> cache = new SentryJCacheWrapper<>(rawCache);
215215

216216
// All cache operations inside a transaction produce child spans
217217
ITransaction transaction = Sentry.startTransaction("cache-demo", "demo");

sentry-samples/sentry-samples-spring-boot-4-opentelemetry/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ dependencies {
5959
implementation(projects.sentryAsyncProfiler)
6060
implementation(libs.otel)
6161

62+
// cache tracing
63+
implementation(libs.springboot4.starter.cache)
64+
implementation(libs.caffeine)
65+
6266
// database query tracing
6367
implementation(projects.sentryJdbc)
6468
runtimeOnly(libs.hsqldb)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.sentry.samples.spring.boot4;
2+
3+
import org.springframework.web.bind.annotation.DeleteMapping;
4+
import org.springframework.web.bind.annotation.GetMapping;
5+
import org.springframework.web.bind.annotation.PathVariable;
6+
import org.springframework.web.bind.annotation.PostMapping;
7+
import org.springframework.web.bind.annotation.RequestBody;
8+
import org.springframework.web.bind.annotation.RequestMapping;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
@RestController
12+
@RequestMapping("/cache/")
13+
public class CacheController {
14+
private final TodoService todoService;
15+
16+
public CacheController(TodoService todoService) {
17+
this.todoService = todoService;
18+
}
19+
20+
@GetMapping("{id}")
21+
Todo get(@PathVariable Long id) {
22+
return todoService.get(id);
23+
}
24+
25+
@PostMapping
26+
Todo save(@RequestBody Todo todo) {
27+
return todoService.save(todo);
28+
}
29+
30+
@DeleteMapping("{id}")
31+
void delete(@PathVariable Long id) {
32+
todoService.delete(id);
33+
}
34+
}

sentry-samples/sentry-samples-spring-boot-4-opentelemetry/src/main/java/io/sentry/samples/spring/boot4/SentryDemoApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.springframework.boot.SpringApplication;
1212
import org.springframework.boot.autoconfigure.SpringBootApplication;
1313
import org.springframework.boot.restclient.RestTemplateBuilder;
14+
import org.springframework.cache.annotation.EnableCaching;
1415
import org.springframework.context.annotation.Bean;
1516
import org.springframework.scheduling.annotation.EnableScheduling;
1617
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
@@ -21,6 +22,7 @@
2122
import org.springframework.web.reactive.function.client.WebClient;
2223

2324
@SpringBootApplication
25+
@EnableCaching
2426
@EnableScheduling
2527
public class SentryDemoApplication {
2628
public static void main(String[] args) {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.sentry.samples.spring.boot4;
2+
3+
import java.util.Map;
4+
import java.util.concurrent.ConcurrentHashMap;
5+
import org.springframework.cache.annotation.CacheEvict;
6+
import org.springframework.cache.annotation.CachePut;
7+
import org.springframework.cache.annotation.Cacheable;
8+
import org.springframework.stereotype.Service;
9+
10+
@Service
11+
public class TodoService {
12+
private final Map<Long, Todo> store = new ConcurrentHashMap<>();
13+
14+
@Cacheable(value = "todos", key = "#id")
15+
public Todo get(Long id) {
16+
return store.get(id);
17+
}
18+
19+
@CachePut(value = "todos", key = "#todo.id")
20+
public Todo save(Todo todo) {
21+
store.put(todo.getId(), todo);
22+
return todo;
23+
}
24+
25+
@CacheEvict(value = "todos", key = "#id")
26+
public void delete(Long id) {
27+
store.remove(id);
28+
}
29+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ sentry.in-app-includes="io.sentry.samples"
2020
sentry.profile-session-sample-rate=1.0
2121
sentry.profiling-traces-dir-path=tmp/sentry/profiling-traces
2222
sentry.profile-lifecycle=TRACE
23+
sentry.enable-cache-tracing=true
24+
spring.cache.cache-names=todos
25+
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
2326

2427
# Uncomment and set to true to enable aot compatibility
2528
# This flag disables all AOP related features (i.e. @SentryTransaction, @SentrySpan)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package io.sentry.systemtest
2+
3+
import io.sentry.systemtest.util.TestHelper
4+
import kotlin.test.Test
5+
import kotlin.test.assertEquals
6+
import org.junit.Before
7+
8+
class CacheSystemTest {
9+
lateinit var testHelper: TestHelper
10+
11+
@Before
12+
fun setup() {
13+
testHelper = TestHelper("http://localhost:8080")
14+
testHelper.reset()
15+
}
16+
17+
@Test
18+
fun `cache put and get produce spans`() {
19+
val restClient = testHelper.restClient
20+
21+
// Save a todo (triggers @CachePut -> cache.put span)
22+
val todo = Todo(1L, "test-todo", false)
23+
restClient.saveCachedTodo(todo)
24+
assertEquals(200, restClient.lastKnownStatusCode)
25+
26+
testHelper.ensureTransactionReceived { transaction, _ ->
27+
testHelper.doesTransactionContainSpanWithOp(transaction, "cache.put")
28+
}
29+
30+
testHelper.reset()
31+
32+
// Get the todo (triggers @Cacheable -> cache.get span, should be a hit)
33+
restClient.getCachedTodo(1L)
34+
assertEquals(200, restClient.lastKnownStatusCode)
35+
36+
testHelper.ensureTransactionReceived { transaction, _ ->
37+
testHelper.doesTransactionContainSpanWithOp(transaction, "cache.get")
38+
}
39+
}
40+
41+
@Test
42+
fun `cache evict produces span`() {
43+
val restClient = testHelper.restClient
44+
45+
restClient.deleteCachedTodo(1L)
46+
47+
testHelper.ensureTransactionReceived { transaction, _ ->
48+
testHelper.doesTransactionContainSpanWithOp(transaction, "cache.remove")
49+
}
50+
}
51+
}

sentry-samples/sentry-samples-spring-boot-4-otlp/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ dependencies {
5858
implementation(projects.sentryAsyncProfiler)
5959
implementation(projects.sentryOpentelemetry.sentryOpentelemetryOtlpSpring)
6060

61+
// cache tracing
62+
implementation(libs.springboot4.starter.cache)
63+
implementation(libs.caffeine)
64+
6165
// database query tracing
6266
implementation(projects.sentryJdbc)
6367
runtimeOnly(libs.hsqldb)

0 commit comments

Comments
 (0)