Skip to content

feat(spring): [Cache Tracing 12] Add db.operation.name attribute to cache spans#5201

Draft
adinauer wants to merge 1 commit intofix/cache-tracing-noop-spanfrom
feat/cache-tracing-db-operation-name
Draft

feat(spring): [Cache Tracing 12] Add db.operation.name attribute to cache spans#5201
adinauer wants to merge 1 commit intofix/cache-tracing-noop-spanfrom
feat/cache-tracing-db-operation-name

Conversation

@adinauer
Copy link
Member

@adinauer adinauer commented Mar 17, 2026

PR Stack (Cache Tracing)

  • #5172 — Add SentryCacheWrapper and SentryCacheManagerWrapper
  • #5173 — Add enableCacheTracing option
  • #5174 — Add BeanPostProcessor and auto-configuration
  • #5175 — Add cache tracing e2e sample
  • #5179 — Add SentryJCacheWrapper for JCache (JSR-107)
  • #5182 — Add JCache console sample
  • #5183 — Add cache tracing to all Spring Boot 4 samples
  • #5184 — Add retrieve() overrides for reactive/async cache support
  • #5190 — Port cache tracing to Spring Boot 3 Jakarta + samples
  • #5191 — Port cache tracing to Spring Boot 2 + samples
  • #5192 — Skip cache span data when child span is NoOp
  • #5201 — Add db.operation.name attribute to cache spans
  • #5202 — Instrument putIfAbsent, replace, and getAndReplace

📜 Description

Add a db.operation.name span data attribute to every instrumented cache operation. The value is the name of the cache method being invoked (e.g. get, put, evict, retrieve, getAll, removeAll), allowing Sentry to distinguish between operations that share the same span op (e.g. evict vs evictIfPresent both use cache.remove).

Each wrapper class defines its own private static final String OPERATION_ATTRIBUTE = "db.operation.name" constant. The attribute is set centrally in the startSpan() / startSpanForKeys() helper methods via an added operationName parameter.

Modules changed:

  • sentry-spring — 8 call sites
  • sentry-spring-7 — 10 call sites (includes retrieve)
  • sentry-spring-jakarta — 10 call sites (includes retrieve)
  • sentry-jcache — 13 call sites

💡 Motivation and Context

The db.operation.name attribute enables more granular cache operation visibility in the Sentry UI. Without it, evict and evictIfPresent are indistinguishable (both cache.remove), and clear vs invalidate are indistinguishable (both cache.flush).

💚 How did you test it?

Added assertEquals("methodName", span.getData("db.operation.name")) assertions to all existing span tests across all 4 test files. All tests pass.

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

🔮 Next steps

None — this is a self-contained enhancement.

⚠️ Merge this PR using a merge commit (not squash). Only the collection branch is squash-merged into main.

#skip-changelog

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 17, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


This PR will not appear in the changelog.


🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 17, 2026

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 5d8a445

@adinauer
Copy link
Member Author

@sentry review

@adinauer
Copy link
Member Author

cursor review

@sentry
Copy link

sentry bot commented Mar 17, 2026

Sentry Build Distribution

App Name App ID Version Configuration Install Page
SDK Size io.sentry.tests.size 8.34.1 (1) release Install Build

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Duplicated constant belongs in shared SpanDataConvention interface
    • Added DB_OPERATION_NAME_KEY to SpanDataConvention and updated all cache wrappers to use it instead of duplicated local constants.

Create PR

Or push these changes by commenting:

@cursor push eebc04ec98
Preview (eebc04ec98)
diff --git a/sentry-jcache/src/main/java/io/sentry/jcache/SentryJCacheWrapper.java b/sentry-jcache/src/main/java/io/sentry/jcache/SentryJCacheWrapper.java
--- a/sentry-jcache/src/main/java/io/sentry/jcache/SentryJCacheWrapper.java
+++ b/sentry-jcache/src/main/java/io/sentry/jcache/SentryJCacheWrapper.java
@@ -33,7 +33,6 @@
 public final class SentryJCacheWrapper<K, V> implements Cache<K, V> {
 
   private static final String TRACE_ORIGIN = "auto.cache.jcache";
-  private static final String OPERATION_ATTRIBUTE = "db.operation.name";
 
   private final @NotNull Cache<K, V> delegate;
   private final @NotNull IScopes scopes;
@@ -424,7 +423,7 @@
     if (keyString != null) {
       span.setData(SpanDataConvention.CACHE_KEY_KEY, Arrays.asList(keyString));
     }
-    span.setData(OPERATION_ATTRIBUTE, operationName);
+    span.setData(SpanDataConvention.DB_OPERATION_NAME_KEY, operationName);
     return span;
   }
 
@@ -450,7 +449,7 @@
     span.setData(
         SpanDataConvention.CACHE_KEY_KEY,
         keys.stream().map(String::valueOf).collect(Collectors.toList()));
-    span.setData(OPERATION_ATTRIBUTE, operationName);
+    span.setData(SpanDataConvention.DB_OPERATION_NAME_KEY, operationName);
     return span;
   }
 }

diff --git a/sentry-spring-7/src/main/java/io/sentry/spring7/cache/SentryCacheWrapper.java b/sentry-spring-7/src/main/java/io/sentry/spring7/cache/SentryCacheWrapper.java
--- a/sentry-spring-7/src/main/java/io/sentry/spring7/cache/SentryCacheWrapper.java
+++ b/sentry-spring-7/src/main/java/io/sentry/spring7/cache/SentryCacheWrapper.java
@@ -20,7 +20,6 @@
 public final class SentryCacheWrapper implements Cache {
 
   private static final String TRACE_ORIGIN = "auto.cache.spring";
-  private static final String OPERATION_ATTRIBUTE = "db.operation.name";
 
   private final @NotNull Cache delegate;
   private final @NotNull IScopes scopes;
@@ -305,7 +304,7 @@
     if (keyString != null) {
       span.setData(SpanDataConvention.CACHE_KEY_KEY, Arrays.asList(keyString));
     }
-    span.setData(OPERATION_ATTRIBUTE, operationName);
+    span.setData(SpanDataConvention.DB_OPERATION_NAME_KEY, operationName);
     return span;
   }
 }

diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/cache/SentryCacheWrapper.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/cache/SentryCacheWrapper.java
--- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/cache/SentryCacheWrapper.java
+++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/cache/SentryCacheWrapper.java
@@ -20,7 +20,6 @@
 public final class SentryCacheWrapper implements Cache {
 
   private static final String TRACE_ORIGIN = "auto.cache.spring";
-  private static final String OPERATION_ATTRIBUTE = "db.operation.name";
 
   private final @NotNull Cache delegate;
   private final @NotNull IScopes scopes;
@@ -305,7 +304,7 @@
     if (keyString != null) {
       span.setData(SpanDataConvention.CACHE_KEY_KEY, Arrays.asList(keyString));
     }
-    span.setData(OPERATION_ATTRIBUTE, operationName);
+    span.setData(SpanDataConvention.DB_OPERATION_NAME_KEY, operationName);
     return span;
   }
 }

diff --git a/sentry-spring/src/main/java/io/sentry/spring/cache/SentryCacheWrapper.java b/sentry-spring/src/main/java/io/sentry/spring/cache/SentryCacheWrapper.java
--- a/sentry-spring/src/main/java/io/sentry/spring/cache/SentryCacheWrapper.java
+++ b/sentry-spring/src/main/java/io/sentry/spring/cache/SentryCacheWrapper.java
@@ -18,7 +18,6 @@
 public final class SentryCacheWrapper implements Cache {
 
   private static final String TRACE_ORIGIN = "auto.cache.spring";
-  private static final String OPERATION_ATTRIBUTE = "db.operation.name";
 
   private final @NotNull Cache delegate;
   private final @NotNull IScopes scopes;
@@ -233,7 +232,7 @@
     if (keyString != null) {
       span.setData(SpanDataConvention.CACHE_KEY_KEY, Arrays.asList(keyString));
     }
-    span.setData(OPERATION_ATTRIBUTE, operationName);
+    span.setData(SpanDataConvention.DB_OPERATION_NAME_KEY, operationName);
     return span;
   }
 }

diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api
--- a/sentry/api/sentry.api
+++ b/sentry/api/sentry.api
@@ -4348,6 +4348,7 @@
 	public static final field CONTRIBUTES_TTFD Ljava/lang/String;
 	public static final field CONTRIBUTES_TTID Ljava/lang/String;
 	public static final field DB_NAME_KEY Ljava/lang/String;
+	public static final field DB_OPERATION_NAME_KEY Ljava/lang/String;
 	public static final field DB_SYSTEM_KEY Ljava/lang/String;
 	public static final field FRAMES_DELAY Ljava/lang/String;
 	public static final field FRAMES_FROZEN Ljava/lang/String;

diff --git a/sentry/src/main/java/io/sentry/SpanDataConvention.java b/sentry/src/main/java/io/sentry/SpanDataConvention.java
--- a/sentry/src/main/java/io/sentry/SpanDataConvention.java
+++ b/sentry/src/main/java/io/sentry/SpanDataConvention.java
@@ -8,6 +8,7 @@
   //  https://develop.sentry.dev/sdk/performance/span-data-conventions/
   String DB_SYSTEM_KEY = "db.system";
   String DB_NAME_KEY = "db.name";
+  String DB_OPERATION_NAME_KEY = "db.operation.name";
   String HTTP_QUERY_KEY = "http.query";
   String HTTP_FRAGMENT_KEY = "http.fragment";
   String HTTP_METHOD_KEY = "http.request.method";

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

public final class SentryJCacheWrapper<K, V> implements Cache<K, V> {

private static final String TRACE_ORIGIN = "auto.cache.jcache";
private static final String OPERATION_ATTRIBUTE = "db.operation.name";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated constant belongs in shared SpanDataConvention interface

Low Severity

The OPERATION_ATTRIBUTE = "db.operation.name" constant is independently defined as a private static final in four separate wrapper classes. All four files already import and use SpanDataConvention for CACHE_HIT_KEY and CACHE_KEY_KEY. Adding a DB_OPERATION_NAME_KEY constant to SpanDataConvention would follow the established pattern, eliminate the duplication, and ensure a single source of truth for this attribute name.

Additional Locations (2)
Fix in Cursor Fix in Web

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As db.operation.name does not match any keys listed in the sentry span data convention here: https://develop.sentry.dev/sdk/performance/span-data-conventions/. I think it is fine as is. @adinauer wdyt?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can move the constant but I first have to clarify internally what the attribute key should be.

@github-actions
Copy link
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 330.20 ms 383.47 ms 53.27 ms
Size 0 B 0 B 0 B

Baseline results on branch: fix/cache-tracing-noop-span

Startup times

Revision Plain With Sentry Diff
d06a074 325.98 ms 412.96 ms 86.98 ms

App size

Revision Plain With Sentry Diff
d06a074 0 B 0 B 0 B

Copy link
Collaborator

@lbloder lbloder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One open cursor question. LGTM otherwise

public final class SentryJCacheWrapper<K, V> implements Cache<K, V> {

private static final String TRACE_ORIGIN = "auto.cache.jcache";
private static final String OPERATION_ATTRIBUTE = "db.operation.name";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As db.operation.name does not match any keys listed in the sentry span data convention here: https://develop.sentry.dev/sdk/performance/span-data-conventions/. I think it is fine as is. @adinauer wdyt?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants