Skip to content

Commit f3c4ab7

Browse files
adinauerlbloder
andauthored
Add ignoredTransactions option to filter out transactions by name (#3871)
* Auto config for Spring Boot combined with OTel but without agent * try to cleanup otel classloader * make agent, no agent and agent without auto init work for spring boot * Fix ignored instrumentation for OTel without agent; separate sample for no agent * fix test result upload on CI * automatically detect otel and use OtelSpanFactory * POTEL 54 cleanup * fix non current span start child * consider status codes below 400 to be OK * Add ignoredTransactions option * Update sentry/src/main/java/io/sentry/util/TracingUtils.java Co-authored-by: Lukas Bloder <[email protected]> * changelog * Add test --------- Co-authored-by: Lukas Bloder <[email protected]>
1 parent f028e77 commit f3c4ab7

File tree

11 files changed

+152
-4
lines changed

11 files changed

+152
-4
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
- In this mode the SDK makes use of `GlobalOpenTelemetry`
2626
- Automatically set span factory based on presence of OpenTelemetry ([#3858](https://github.com/getsentry/sentry-java/pull/3858))
2727
- `SentrySpanFactoryHolder` has been removed as it is no longer required.
28+
- Add `ignoredTransactions` option to filter out transactions by name ([#3871](https://github.com/getsentry/sentry-java/pull/3871))
29+
- can be used via ENV vars, e.g. `SENTRY_IGNORED_TRANSACTIONS=POST /person/,GET /pers.*`
30+
- can also be set in options directly, e.g. `options.setIgnoredTransactions(...)`
31+
- can also be set in `sentry.properties`, e.g. `ignored-transactions=POST /person/,GET /pers.*`
32+
- can also be set in Spring config `application.properties`, e.g. `sentry.ignored-transactions=POST /person/,GET /pers.*`
2833
- Add a sample for showcasing Sentry with OpenTelemetry for Spring Boot 3 with our Java agent (`sentry-samples-spring-boot-jakarta-opentelemetry`) ([#3856](https://github.com/getsentry/sentry-java/pull/3828))
2934
- Add a sample for showcasing Sentry with OpenTelemetry for Spring Boot 3 without our Java agent (`sentry-samples-spring-boot-jakarta-opentelemetry-noagent`) ([#3856](https://github.com/getsentry/sentry-java/pull/3856))
3035
- Add a sample for showcasing Sentry with OpenTelemetry (`sentry-samples-console-opentelemetry-noagent`) ([#3856](https://github.com/getsentry/sentry-java/pull/3862))

sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ class SentryAutoConfigurationTest {
173173
"sentry.enabled=false",
174174
"sentry.send-modules=false",
175175
"sentry.ignored-checkins=slug1,slugB",
176+
"sentry.ignored-transactions=transactionName1,transactionNameB",
176177
"sentry.enable-backpressure-handling=false",
177178
"sentry.enable-spotlight=true",
178179
"sentry.spotlight-connection-url=http://local.sentry.io:1234",
@@ -213,6 +214,7 @@ class SentryAutoConfigurationTest {
213214
assertThat(options.isEnabled).isEqualTo(false)
214215
assertThat(options.isSendModules).isEqualTo(false)
215216
assertThat(options.ignoredCheckIns).containsOnly("slug1", "slugB")
217+
assertThat(options.ignoredTransactions).containsOnly("transactionName1", "transactionNameB")
216218
assertThat(options.isEnableBackpressureHandling).isEqualTo(false)
217219
assertThat(options.isForceInit).isEqualTo(true)
218220
assertThat(options.isGlobalHubMode).isEqualTo(true)

sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ class SentryAutoConfigurationTest {
169169
"sentry.enabled=false",
170170
"sentry.send-modules=false",
171171
"sentry.ignored-checkins=slug1,slugB",
172+
"sentry.ignored-transactions=transactionName1,transactionNameB",
172173
"sentry.enable-backpressure-handling=false",
173174
"sentry.enable-spotlight=true",
174175
"sentry.spotlight-connection-url=http://local.sentry.io:1234",
@@ -209,6 +210,7 @@ class SentryAutoConfigurationTest {
209210
assertThat(options.isEnabled).isEqualTo(false)
210211
assertThat(options.isSendModules).isEqualTo(false)
211212
assertThat(options.ignoredCheckIns).containsOnly("slug1", "slugB")
213+
assertThat(options.ignoredTransactions).containsOnly("transactionName1", "transactionNameB")
212214
assertThat(options.isEnableBackpressureHandling).isEqualTo(false)
213215
assertThat(options.isForceInit).isEqualTo(true)
214216
assertThat(options.isGlobalHubMode).isEqualTo(true)

sentry/api/sentry.api

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ public final class io/sentry/ExternalOptions {
455455
public fun getIdleTimeout ()Ljava/lang/Long;
456456
public fun getIgnoredCheckIns ()Ljava/util/List;
457457
public fun getIgnoredExceptionsForType ()Ljava/util/Set;
458+
public fun getIgnoredTransactions ()Ljava/util/List;
458459
public fun getInAppExcludes ()Ljava/util/List;
459460
public fun getInAppIncludes ()Ljava/util/List;
460461
public fun getMaxRequestBodySize ()Lio/sentry/SentryOptions$RequestSize;
@@ -492,6 +493,7 @@ public final class io/sentry/ExternalOptions {
492493
public fun setGlobalHubMode (Ljava/lang/Boolean;)V
493494
public fun setIdleTimeout (Ljava/lang/Long;)V
494495
public fun setIgnoredCheckIns (Ljava/util/List;)V
496+
public fun setIgnoredTransactions (Ljava/util/List;)V
495497
public fun setMaxRequestBodySize (Lio/sentry/SentryOptions$RequestSize;)V
496498
public fun setPrintUncaughtStackTrace (Ljava/lang/Boolean;)V
497499
public fun setProfilesSampleRate (Ljava/lang/Double;)V
@@ -2826,6 +2828,7 @@ public class io/sentry/SentryOptions {
28262828
public fun getIgnoredCheckIns ()Ljava/util/List;
28272829
public fun getIgnoredExceptionsForType ()Ljava/util/Set;
28282830
public fun getIgnoredSpanOrigins ()Ljava/util/List;
2831+
public fun getIgnoredTransactions ()Ljava/util/List;
28292832
public fun getInAppExcludes ()Ljava/util/List;
28302833
public fun getInAppIncludes ()Ljava/util/List;
28312834
public fun getInitPriority ()Lio/sentry/InitPriority;
@@ -2953,6 +2956,7 @@ public class io/sentry/SentryOptions {
29532956
public fun setIdleTimeout (Ljava/lang/Long;)V
29542957
public fun setIgnoredCheckIns (Ljava/util/List;)V
29552958
public fun setIgnoredSpanOrigins (Ljava/util/List;)V
2959+
public fun setIgnoredTransactions (Ljava/util/List;)V
29562960
public fun setInitPriority (Lio/sentry/InitPriority;)V
29572961
public fun setInstrumenter (Lio/sentry/Instrumenter;)V
29582962
public fun setLogger (Lio/sentry/ILogger;)V
@@ -6193,6 +6197,7 @@ public final class io/sentry/util/StringUtils {
61936197

61946198
public final class io/sentry/util/TracingUtils {
61956199
public fun <init> ()V
6200+
public static fun isIgnored (Ljava/util/List;Ljava/lang/String;)Z
61966201
public static fun maybeUpdateBaggage (Lio/sentry/IScope;Lio/sentry/SentryOptions;)Lio/sentry/PropagationContext;
61976202
public static fun startNewTrace (Lio/sentry/IScopes;)V
61986203
public static fun trace (Lio/sentry/IScopes;Ljava/util/List;Lio/sentry/ISpan;)Lio/sentry/util/TracingUtils$TracingHeaders;

sentry/src/main/java/io/sentry/ExternalOptions.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public final class ExternalOptions {
4848
private @Nullable String spotlightConnectionUrl;
4949

5050
private @Nullable List<String> ignoredCheckIns;
51+
private @Nullable List<String> ignoredTransactions;
5152

5253
private @Nullable Boolean sendModules;
5354
private @Nullable Boolean sendDefaultPii;
@@ -138,6 +139,7 @@ public final class ExternalOptions {
138139
options.setSendDefaultPii(propertiesProvider.getBooleanProperty("send-default-pii"));
139140

140141
options.setIgnoredCheckIns(propertiesProvider.getList("ignored-checkins"));
142+
options.setIgnoredTransactions(propertiesProvider.getList("ignored-transactions"));
141143

142144
options.setEnableBackpressureHandling(
143145
propertiesProvider.getBooleanProperty("enable-backpressure-handling"));
@@ -430,6 +432,14 @@ public void setIgnoredCheckIns(final @Nullable List<String> ignoredCheckIns) {
430432
return ignoredCheckIns;
431433
}
432434

435+
public void setIgnoredTransactions(final @Nullable List<String> ignoredTransactions) {
436+
this.ignoredTransactions = ignoredTransactions;
437+
}
438+
439+
public @Nullable List<String> getIgnoredTransactions() {
440+
return ignoredTransactions;
441+
}
442+
433443
@ApiStatus.Experimental
434444
public void setEnableBackpressureHandling(final @Nullable Boolean enableBackpressureHandling) {
435445
this.enableBackpressureHandling = enableBackpressureHandling;

sentry/src/main/java/io/sentry/SentryClient.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,23 @@ public void captureSession(final @NotNull Session session, final @Nullable Hint
774774
.getLogger()
775775
.log(SentryLevel.DEBUG, "Capturing transaction: %s", transaction.getEventId());
776776

777+
if (TracingUtils.isIgnored(options.getIgnoredTransactions(), transaction.getTransaction())) {
778+
options
779+
.getLogger()
780+
.log(
781+
SentryLevel.DEBUG,
782+
"Transaction was dropped as transaction name %s is ignored",
783+
transaction.getTransaction());
784+
options
785+
.getClientReportRecorder()
786+
.recordLostEvent(DiscardReason.EVENT_PROCESSOR, DataCategory.Transaction);
787+
options
788+
.getClientReportRecorder()
789+
.recordLostEvent(
790+
DiscardReason.EVENT_PROCESSOR, DataCategory.Span, transaction.getSpans().size() + 1);
791+
return SentryId.EMPTY_ID;
792+
}
793+
777794
SentryId sentryId = SentryId.EMPTY_ID;
778795
if (transaction.getEventId() != null) {
779796
sentryId = transaction.getEventId();
@@ -880,10 +897,9 @@ public void captureSession(final @NotNull Session session, final @Nullable Hint
880897
SentryLevel.DEBUG,
881898
"Check-in was dropped as slug %s is ignored",
882899
checkIn.getMonitorSlug());
883-
// TODO in a follow up PR with DataCategory.Monitor
884-
// options
885-
// .getClientReportRecorder()
886-
// .recordLostEvent(DiscardReason.EVENT_PROCESSOR, DataCategory.Error);
900+
options
901+
.getClientReportRecorder()
902+
.recordLostEvent(DiscardReason.EVENT_PROCESSOR, DataCategory.Monitor);
887903
return SentryId.EMPTY_ID;
888904
}
889905

sentry/src/main/java/io/sentry/SentryOptions.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,8 @@ public class SentryOptions {
465465
/** Contains a list of span origins for which spans / transactions should not be created. */
466466
@ApiStatus.Experimental private @Nullable List<String> ignoredSpanOrigins = null;
467467

468+
private @Nullable List<String> ignoredTransactions = null;
469+
468470
@ApiStatus.Experimental
469471
private @NotNull IBackpressureMonitor backpressureMonitor = NoOpBackpressureMonitor.getInstance();
470472

@@ -2186,6 +2188,26 @@ public void setIgnoredSpanOrigins(final @Nullable List<String> ignoredSpanOrigin
21862188
return ignoredCheckIns;
21872189
}
21882190

2191+
public @Nullable List<String> getIgnoredTransactions() {
2192+
return ignoredTransactions;
2193+
}
2194+
2195+
@ApiStatus.Experimental
2196+
public void setIgnoredTransactions(final @Nullable List<String> ignoredTransactions) {
2197+
if (ignoredTransactions == null) {
2198+
this.ignoredTransactions = null;
2199+
} else {
2200+
@NotNull final List<String> filtered = new ArrayList<>();
2201+
for (String transactionName : ignoredTransactions) {
2202+
if (transactionName != null && !transactionName.isEmpty()) {
2203+
filtered.add(transactionName);
2204+
}
2205+
}
2206+
2207+
this.ignoredTransactions = filtered;
2208+
}
2209+
}
2210+
21892211
/** Returns the current {@link SentryDateProvider} that is used to retrieve the current date. */
21902212
@ApiStatus.Internal
21912213
public @NotNull SentryDateProvider getDateProvider() {
@@ -2667,6 +2689,10 @@ public void merge(final @NotNull ExternalOptions options) {
26672689
final List<String> ignoredCheckIns = new ArrayList<>(options.getIgnoredCheckIns());
26682690
setIgnoredCheckIns(ignoredCheckIns);
26692691
}
2692+
if (options.getIgnoredTransactions() != null) {
2693+
final List<String> ignoredTransactions = new ArrayList<>(options.getIgnoredTransactions());
2694+
setIgnoredTransactions(ignoredTransactions);
2695+
}
26702696
if (options.isEnableBackpressureHandling() != null) {
26712697
setEnableBackpressureHandling(options.isEnableBackpressureHandling());
26722698
}

sentry/src/main/java/io/sentry/util/TracingUtils.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.sentry.SentryOptions;
1010
import io.sentry.SentryTraceHeader;
1111
import java.util.List;
12+
import org.jetbrains.annotations.ApiStatus;
1213
import org.jetbrains.annotations.NotNull;
1314
import org.jetbrains.annotations.Nullable;
1415

@@ -116,4 +117,32 @@ public TracingHeaders(
116117
return baggageHeader;
117118
}
118119
}
120+
121+
/** Checks if a transaction is to be ignored. */
122+
@ApiStatus.Internal
123+
public static boolean isIgnored(
124+
final @Nullable List<String> ignoredTransactions, final @Nullable String transactionName) {
125+
if (transactionName == null) {
126+
return false;
127+
}
128+
if (ignoredTransactions == null || ignoredTransactions.isEmpty()) {
129+
return false;
130+
}
131+
132+
for (final String ignoredSlug : ignoredTransactions) {
133+
if (ignoredSlug.equalsIgnoreCase(transactionName)) {
134+
return true;
135+
}
136+
137+
try {
138+
if (transactionName.matches(ignoredSlug)) {
139+
return true;
140+
}
141+
} catch (Throwable t) {
142+
// ignore invalid regex
143+
}
144+
}
145+
146+
return false;
147+
}
119148
}

sentry/src/test/java/io/sentry/ExternalOptionsTest.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,13 @@ class ExternalOptionsTest {
261261
}
262262
}
263263

264+
@Test
265+
fun `creates options with ignoredTransactions`() {
266+
withPropertiesFile("ignored-transactions=transactionName1,transactionName2") { options ->
267+
assertTrue(options.ignoredTransactions!!.containsAll(listOf("transactionName1", "transactionName2")))
268+
}
269+
}
270+
264271
@Test
265272
fun `creates options with enableBackpressureHandling set to false`() {
266273
withPropertiesFile("enable-backpressure-handling=false") { options ->

sentry/src/test/java/io/sentry/SentryClientTest.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,50 @@ class SentryClientTest {
819819
)
820820
}
821821

822+
@Test
823+
fun `transaction dropped by ignoredTransactions is recorded`() {
824+
fixture.sentryOptions.ignoredTransactions = listOf("a-transaction")
825+
826+
val transaction = SentryTransaction(fixture.sentryTracer)
827+
828+
val eventId =
829+
fixture.getSut().captureTransaction(transaction, fixture.sentryTracer.traceContext())
830+
831+
verify(fixture.transport, never()).send(any(), anyOrNull())
832+
833+
assertClientReport(
834+
fixture.sentryOptions.clientReportRecorder,
835+
listOf(
836+
DiscardedEvent(DiscardReason.EVENT_PROCESSOR.reason, DataCategory.Transaction.category, 1),
837+
DiscardedEvent(DiscardReason.EVENT_PROCESSOR.reason, DataCategory.Span.category, 2)
838+
)
839+
)
840+
841+
assertEquals(SentryId.EMPTY_ID, eventId)
842+
}
843+
844+
@Test
845+
fun `transaction dropped by ignoredTransactions with regex is recorded`() {
846+
fixture.sentryOptions.ignoredTransactions = listOf("a.*action")
847+
848+
val transaction = SentryTransaction(fixture.sentryTracer)
849+
850+
val eventId =
851+
fixture.getSut().captureTransaction(transaction, fixture.sentryTracer.traceContext())
852+
853+
verify(fixture.transport, never()).send(any(), anyOrNull())
854+
855+
assertClientReport(
856+
fixture.sentryOptions.clientReportRecorder,
857+
listOf(
858+
DiscardedEvent(DiscardReason.EVENT_PROCESSOR.reason, DataCategory.Transaction.category, 1),
859+
DiscardedEvent(DiscardReason.EVENT_PROCESSOR.reason, DataCategory.Span.category, 2)
860+
)
861+
)
862+
863+
assertEquals(SentryId.EMPTY_ID, eventId)
864+
}
865+
822866
@Test
823867
fun `backfillable events are only wired through backfilling processors`() {
824868
val backfillingProcessor = mock<BackfillingEventProcessor>()

0 commit comments

Comments
 (0)