Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
```
- Fix abstract method error in `SentrySupportSQLiteDatabase` ([#4597](https://github.com/getsentry/sentry-java/pull/4597))

### Features

- Add onDiscard to enable users to track the type and amount of data discarded before reaching Sentry ([#3652](https://github.com/getsentry/sentry-java/issues/3652))

## 8.18.0

### Features
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
package io.sentry.samples.console;

import io.sentry.Breadcrumb;
import io.sentry.EventProcessor;
import io.sentry.Hint;
import io.sentry.ISpan;
import io.sentry.ITransaction;
import io.sentry.Sentry;
import io.sentry.SentryEvent;
import io.sentry.SentryLevel;
import io.sentry.SpanStatus;
import io.sentry.*;
import io.sentry.clientreport.DiscardReason;
import io.sentry.protocol.Message;
import io.sentry.protocol.User;
import java.util.Collections;

public class Main {

private static int numberOfDiscardedSpansDueToOverflow = 0;

public static void main(String[] args) throws InterruptedException {
Sentry.init(
options -> {
Expand Down Expand Up @@ -59,6 +54,18 @@ public static void main(String[] args) throws InterruptedException {
return breadcrumb;
});

// Record data being discarded, including the reason, type of data, and the number of
// items dropped
options.setOnDiscard(
(reason, category, number) -> {
// Only record the number of lost spans due to overflow conditions
if ((reason.equals(DiscardReason.CACHE_OVERFLOW.getReason())
|| reason.equals(DiscardReason.QUEUE_OVERFLOW.getReason()))
&& category.equals(DataCategory.Span.getCategory())) {
numberOfDiscardedSpansDueToOverflow += number;
}
});

// Configure the background worker which sends events to sentry:
// Wait up to 5 seconds before shutdown while there are events to send.
options.setShutdownTimeoutMillis(5000);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.sentry.samples.servlet;

import io.sentry.DataCategory;
import io.sentry.Sentry;
import io.sentry.clientreport.DiscardReason;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
Expand All @@ -9,6 +11,8 @@
@WebListener
public final class SentryInitializer implements ServletContextListener {

private static int numberOfDiscardedSpansDueToOverflow = 0;

@Override
public void contextInitialized(ServletContextEvent sce) {
Sentry.init(
Expand Down Expand Up @@ -57,6 +61,18 @@ public void contextInitialized(ServletContextEvent sce) {
return breadcrumb;
});

// Record data being discarded, including the reason, type of data, and the number of
// items dropped
options.setOnDiscard(
(reason, category, number) -> {
// Only record the number of lost spans due to overflow conditions
if ((reason.equals(DiscardReason.CACHE_OVERFLOW.getReason())
|| reason.equals(DiscardReason.QUEUE_OVERFLOW.getReason()))
&& category.equals(DataCategory.Span.getCategory())) {
numberOfDiscardedSpansDueToOverflow += number;
Comment thread
alexander-alderman-webb marked this conversation as resolved.
}
});
Comment thread
alexander-alderman-webb marked this conversation as resolved.

// Configure the background worker which sends events to sentry:
// Wait up to 5 seconds before shutdown while there are events to send.
options.setShutdownTimeoutMillis(5000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ static class HubConfiguration {
beforeSendLogsCallback,
final @NotNull ObjectProvider<SentryOptions.BeforeBreadcrumbCallback>
beforeBreadcrumbCallback,
final @NotNull ObjectProvider<SentryOptions.OnDiscardCallback> onDiscardCallback,
final @NotNull ObjectProvider<SentryOptions.TracesSamplerCallback> tracesSamplerCallback,
final @NotNull List<EventProcessor> eventProcessors,
final @NotNull List<Integration> integrations,
Expand All @@ -118,6 +119,7 @@ static class HubConfiguration {
beforeSendTransactionCallback.ifAvailable(options::setBeforeSendTransaction);
beforeSendLogsCallback.ifAvailable(callback -> options.getLogs().setBeforeSend(callback));
beforeBreadcrumbCallback.ifAvailable(options::setBeforeBreadcrumb);
onDiscardCallback.ifAvailable(options::setOnDiscard);
tracesSamplerCallback.ifAvailable(options::setTracesSampler);
eventProcessors.forEach(options::addEventProcessor);
integrations.forEach(options::addIntegration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,17 @@ class SentryAutoConfigurationTest {
}
}

@Test
fun `registers onDiscardCallback on SentryOptions`() {
contextRunner
.withPropertyValues("sentry.dsn=http://key@localhost/proj")
.withUserConfiguration(CustomOnDiscardCallbackConfiguration::class.java)
.run {
assertThat(it.getBean(SentryOptions::class.java).onDiscard)
.isInstanceOf(CustomOnDiscardCallback::class.java)
}
}

@Test
fun `registers event processor on SentryOptions`() {
contextRunner
Expand Down Expand Up @@ -1137,6 +1148,16 @@ class SentryAutoConfigurationTest {
override fun execute(breadcrumb: Breadcrumb, hint: Hint): Breadcrumb? = null
}

@Configuration(proxyBeanMethods = false)
open class CustomOnDiscardCallbackConfiguration {

@Bean open fun onDiscardCallback() = CustomOnDiscardCallback()
}

class CustomOnDiscardCallback : SentryOptions.OnDiscardCallback {
override fun execute(reason: String, category: String, countToAdd: Long) {}
}

@Configuration(proxyBeanMethods = false)
open class CustomEventProcessorConfiguration {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ static class HubConfiguration {
beforeSendLogsCallback,
final @NotNull ObjectProvider<SentryOptions.BeforeBreadcrumbCallback>
beforeBreadcrumbCallback,
final @NotNull ObjectProvider<SentryOptions.OnDiscardCallback> onDiscardCallback,
final @NotNull ObjectProvider<SentryOptions.TracesSamplerCallback> tracesSamplerCallback,
final @NotNull List<EventProcessor> eventProcessors,
final @NotNull List<Integration> integrations,
Expand All @@ -116,6 +117,7 @@ static class HubConfiguration {
beforeSendTransactionCallback.ifAvailable(options::setBeforeSendTransaction);
beforeSendLogsCallback.ifAvailable(callback -> options.getLogs().setBeforeSend(callback));
beforeBreadcrumbCallback.ifAvailable(options::setBeforeBreadcrumb);
onDiscardCallback.ifAvailable(options::setOnDiscard);
tracesSamplerCallback.ifAvailable(options::setTracesSampler);
eventProcessors.forEach(options::addEventProcessor);
integrations.forEach(options::addIntegration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,17 @@ class SentryAutoConfigurationTest {
}
}

@Test
fun `registers onDiscardCallback on SentryOptions`() {
contextRunner
.withPropertyValues("sentry.dsn=http://key@localhost/proj")
.withUserConfiguration(CustomOnDiscardCallbackConfiguration::class.java)
.run {
assertThat(it.getBean(SentryOptions::class.java).onDiscard)
.isInstanceOf(CustomOnDiscardCallback::class.java)
}
}

@Test
fun `registers event processor on SentryOptions`() {
contextRunner
Expand Down Expand Up @@ -1063,6 +1074,16 @@ class SentryAutoConfigurationTest {
override fun execute(breadcrumb: Breadcrumb, hint: Hint): Breadcrumb? = null
}

@Configuration(proxyBeanMethods = false)
open class CustomOnDiscardCallbackConfiguration {

@Bean open fun onDiscardCallback() = CustomOnDiscardCallback()
}

class CustomOnDiscardCallback : SentryOptions.OnDiscardCallback {
override fun execute(reason: String, category: String, countToAdd: Long) {}
}

@Configuration(proxyBeanMethods = false)
open class CustomEventProcessorConfiguration {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ public SentryInitBeanPostProcessor() {
applicationContext
.getBeanProvider(SentryOptions.BeforeBreadcrumbCallback.class)
.ifAvailable(options::setBeforeBreadcrumb);
applicationContext
.getBeanProvider(SentryOptions.OnDiscardCallback.class)
.ifAvailable(options::setOnDiscard);
applicationContext
.getBeansOfType(EventProcessor.class)
.values()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,11 @@ class EnableSentryTest {
@Bean fun beforeBreadcrumbCallback() = mock<SentryOptions.BeforeBreadcrumbCallback>()
}

@EnableSentry(dsn = "http://key@localhost/proj")
class AppConfigWithCustomOnDiscardCallback {
@Bean fun onDiscardCallback() = mock<SentryOptions.OnDiscardCallback>()
}

@EnableSentry(dsn = "http://key@localhost/proj")
class AppConfigWithCustomEventProcessors {
@Bean fun firstProcessor() = mock<EventProcessor>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ public SentryInitBeanPostProcessor() {
applicationContext
.getBeanProvider(SentryOptions.BeforeBreadcrumbCallback.class)
.ifAvailable(options::setBeforeBreadcrumb);
applicationContext
.getBeanProvider(SentryOptions.OnDiscardCallback.class)
.ifAvailable(options::setOnDiscard);
applicationContext
.getBeansOfType(EventProcessor.class)
.values()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,11 @@ class EnableSentryTest {
@Bean fun beforeBreadcrumbCallback() = mock<SentryOptions.BeforeBreadcrumbCallback>()
}

@EnableSentry(dsn = "http://key@localhost/proj")
class AppConfigWithCustomOnDiscardCallback {
@Bean fun onDiscardCallback() = mock<SentryOptions.OnDiscardCallback>()
}

@EnableSentry(dsn = "http://key@localhost/proj")
class AppConfigWithCustomEventProcessors {
@Bean fun firstProcessor() = mock<EventProcessor>()
Expand Down
6 changes: 6 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -3337,6 +3337,7 @@ public class io/sentry/SentryOptions {
public fun getMaxSpans ()I
public fun getMaxTraceFileSize ()J
public fun getModulesLoader ()Lio/sentry/internal/modules/IModulesLoader;
public fun getOnDiscard ()Lio/sentry/SentryOptions$OnDiscardCallback;
public fun getOpenTelemetryMode ()Lio/sentry/SentryOpenTelemetryMode;
public fun getOptionsObservers ()Ljava/util/List;
public fun getOutboxPath ()Ljava/lang/String;
Expand Down Expand Up @@ -3479,6 +3480,7 @@ public class io/sentry/SentryOptions {
public fun setMaxSpans (I)V
public fun setMaxTraceFileSize (J)V
public fun setModulesLoader (Lio/sentry/internal/modules/IModulesLoader;)V
public fun setOnDiscard (Lio/sentry/SentryOptions$OnDiscardCallback;)V
public fun setOpenTelemetryMode (Lio/sentry/SentryOpenTelemetryMode;)V
public fun setPrintUncaughtStackTrace (Z)V
public fun setProfileLifecycle (Lio/sentry/ProfileLifecycle;)V
Expand Down Expand Up @@ -3572,6 +3574,10 @@ public abstract interface class io/sentry/SentryOptions$Logs$BeforeSendLogCallba
public abstract fun execute (Lio/sentry/SentryLogEvent;)Lio/sentry/SentryLogEvent;
}

public abstract interface class io/sentry/SentryOptions$OnDiscardCallback {
public abstract fun execute (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;)V
}

public abstract interface class io/sentry/SentryOptions$ProfilesSamplerCallback {
public abstract fun sample (Lio/sentry/SamplingContext;)Ljava/lang/Double;
}
Expand Down
34 changes: 34 additions & 0 deletions sentry/src/main/java/io/sentry/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ public class SentryOptions {
*/
private @Nullable BeforeBreadcrumbCallback beforeBreadcrumb;

/** Invoked when some payload sent from the SDK is dropped before consumed by Sentry, */
private @Nullable OnDiscardCallback onDiscard;

/** The cache dir. path for caching offline events */
private @Nullable String cacheDirPath;

Expand Down Expand Up @@ -904,6 +907,24 @@ public void setBeforeBreadcrumb(@Nullable BeforeBreadcrumbCallback beforeBreadcr
this.beforeBreadcrumb = beforeBreadcrumb;
}

/**
* Returns the onDiscard callback
*
* @return the onDiscard callback or null if not set
*/
public @Nullable OnDiscardCallback getOnDiscard() {
return onDiscard;
}

/**
* Sets the onDiscard callback
*
* @param onDiscard the onDiscard callback
*/
public void setOnDiscard(@Nullable OnDiscardCallback onDiscard) {
this.onDiscard = onDiscard;
}

/**
* Returns the cache dir. path if set
*
Expand Down Expand Up @@ -2982,6 +3003,19 @@ public interface BeforeBreadcrumbCallback {
Breadcrumb execute(@NotNull Breadcrumb breadcrumb, @NotNull Hint hint);
}

/** The OnDiscard callback */
public interface OnDiscardCallback {

/**
* Best-effort record of data discarded before reaching Sentry
*
* @param reason the reason data was dropped, corresponding to a DiscardReason
* @param category the type of data discarded, corresponding to a DataCategory
* @param number the number of discarded data items
*/
void execute(@NotNull String reason, @NotNull String category, @NotNull Long number);
Comment thread
alexander-alderman-webb marked this conversation as resolved.
Outdated
}

/** The traces sampler callback. */
public interface TracesSamplerCallback {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ private void recordLostEventInternal(
@NotNull String reason, @NotNull String category, @NotNull Long countToAdd) {
Comment thread
alexander-alderman-webb marked this conversation as resolved.
Outdated
final ClientReportKey key = new ClientReportKey(reason, category);
storage.addCount(key, countToAdd);
if (options.getOnDiscard() != null) {
options.getOnDiscard().execute(reason, category, countToAdd);
}
Comment thread
alexander-alderman-webb marked this conversation as resolved.
Outdated
}

@Nullable
Expand Down
Loading
Loading