Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't send cached envelopes when rate-limiting is active #2937

Merged
merged 13 commits into from
Sep 28, 2023
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package io.sentry.android.core;

import io.sentry.DataCategory;
import io.sentry.IConnectionStatusProvider;
import io.sentry.IHub;
import io.sentry.Integration;
import io.sentry.SendCachedEnvelopeFireAndForgetIntegration;
import io.sentry.SentryLevel;
import io.sentry.SentryOptions;
import io.sentry.transport.RateLimiter;
import io.sentry.util.LazyEvaluator;
import io.sentry.util.Objects;
import java.io.Closeable;
Expand Down Expand Up @@ -81,6 +83,15 @@ private synchronized void sendCachedEnvelopes(
return;
}

// in case there's rate limiting active, skip processing
final @Nullable RateLimiter rateLimiter = hub.getRateLimiter();
if (rateLimiter != null && rateLimiter.isActiveForCategory(DataCategory.All)) {
options
.getLogger()
.log(SentryLevel.INFO, "SendCachedEnvelopeIntegration, rate limiting active.");
return;
}

final SendCachedEnvelopeFireAndForgetIntegration.SendFireAndForget sender =
factory.create(hub, options);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import io.sentry.protocol.Mechanism
import io.sentry.protocol.SentryId
import io.sentry.protocol.User
import io.sentry.transport.ITransport
import io.sentry.transport.RateLimiter
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
Expand Down Expand Up @@ -63,6 +64,10 @@ class InternalSentrySdkTest {
override fun flush(timeoutMillis: Long) {
// no-op
}

override fun getRateLimiter(): RateLimiter? {
return null
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ public final class io/sentry/transport/apache/ApacheHttpClientTransport : io/sen
public fun <init> (Lio/sentry/SentryOptions;Lio/sentry/RequestDetails;Lorg/apache/hc/client5/http/impl/async/CloseableHttpAsyncClient;Lio/sentry/transport/RateLimiter;)V
public fun close ()V
public fun flush (J)V
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun send (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ public void flush(long timeoutMillis) {
}
}

@Override
public @NotNull RateLimiter getRateLimiter() {
return rateLimiter;
}

@Override
public void close() throws IOException {
options.getLogger().log(DEBUG, "Shutting down");
Expand Down
12 changes: 11 additions & 1 deletion sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ public final class io/sentry/Hub : io/sentry/IHub {
public fun getBaggage ()Lio/sentry/BaggageHeader;
public fun getLastEventId ()Lio/sentry/protocol/SentryId;
public fun getOptions ()Lio/sentry/SentryOptions;
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun getSpan ()Lio/sentry/ISpan;
public fun getTraceparent ()Lio/sentry/SentryTraceHeader;
public fun getTransaction ()Lio/sentry/ITransaction;
Expand Down Expand Up @@ -422,6 +423,7 @@ public final class io/sentry/HubAdapter : io/sentry/IHub {
public static fun getInstance ()Lio/sentry/HubAdapter;
public fun getLastEventId ()Lio/sentry/protocol/SentryId;
public fun getOptions ()Lio/sentry/SentryOptions;
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun getSpan ()Lio/sentry/ISpan;
public fun getTraceparent ()Lio/sentry/SentryTraceHeader;
public fun getTransaction ()Lio/sentry/ITransaction;
Expand Down Expand Up @@ -515,6 +517,7 @@ public abstract interface class io/sentry/IHub {
public abstract fun getBaggage ()Lio/sentry/BaggageHeader;
public abstract fun getLastEventId ()Lio/sentry/protocol/SentryId;
public abstract fun getOptions ()Lio/sentry/SentryOptions;
public abstract fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public abstract fun getSpan ()Lio/sentry/ISpan;
public abstract fun getTraceparent ()Lio/sentry/SentryTraceHeader;
public abstract fun getTransaction ()Lio/sentry/ITransaction;
Expand Down Expand Up @@ -608,6 +611,7 @@ public abstract interface class io/sentry/ISentryClient {
public abstract fun captureUserFeedback (Lio/sentry/UserFeedback;)V
public abstract fun close ()V
public abstract fun flush (J)V
public abstract fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public abstract fun isEnabled ()Z
}

Expand Down Expand Up @@ -910,6 +914,7 @@ public final class io/sentry/NoOpHub : io/sentry/IHub {
public static fun getInstance ()Lio/sentry/NoOpHub;
public fun getLastEventId ()Lio/sentry/protocol/SentryId;
public fun getOptions ()Lio/sentry/SentryOptions;
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun getSpan ()Lio/sentry/ISpan;
public fun getTraceparent ()Lio/sentry/SentryTraceHeader;
public fun getTransaction ()Lio/sentry/ITransaction;
Expand Down Expand Up @@ -1516,6 +1521,7 @@ public final class io/sentry/SentryClient : io/sentry/ISentryClient {
public fun captureUserFeedback (Lio/sentry/UserFeedback;)V
public fun close ()V
public fun flush (J)V
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun isEnabled ()Z
}

Expand Down Expand Up @@ -4138,6 +4144,7 @@ public final class io/sentry/transport/AsyncHttpTransport : io/sentry/transport/
public fun <init> (Lio/sentry/transport/QueuedThreadPoolExecutor;Lio/sentry/SentryOptions;Lio/sentry/transport/RateLimiter;Lio/sentry/transport/ITransportGate;Lio/sentry/transport/HttpConnection;)V
public fun close ()V
public fun flush (J)V
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun send (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V
}

Expand All @@ -4152,6 +4159,7 @@ public abstract interface class io/sentry/transport/ICurrentDateProvider {

public abstract interface class io/sentry/transport/ITransport : java/io/Closeable {
public abstract fun flush (J)V
public abstract fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun send (Lio/sentry/SentryEnvelope;)V
public abstract fun send (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V
}
Expand All @@ -4173,6 +4181,7 @@ public final class io/sentry/transport/NoOpTransport : io/sentry/transport/ITran
public fun close ()V
public fun flush (J)V
public static fun getInstance ()Lio/sentry/transport/NoOpTransport;
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun send (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V
}

Expand All @@ -4185,7 +4194,7 @@ public final class io/sentry/transport/RateLimiter {
public fun <init> (Lio/sentry/SentryOptions;)V
public fun <init> (Lio/sentry/transport/ICurrentDateProvider;Lio/sentry/SentryOptions;)V
public fun filter (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)Lio/sentry/SentryEnvelope;
public fun getRateLimitedUntilFor (Ljava/lang/String;)Ljava/util/Date;
public fun isActiveForCategory (Lio/sentry/DataCategory;)Z
public fun updateRetryAfterLimits (Ljava/lang/String;Ljava/lang/String;I)V
}

Expand All @@ -4203,6 +4212,7 @@ public final class io/sentry/transport/StdoutTransport : io/sentry/transport/ITr
public fun <init> (Lio/sentry/ISerializer;)V
public fun close ()V
public fun flush (J)V
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun send (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)V
}

Expand Down
7 changes: 7 additions & 0 deletions sentry/src/main/java/io/sentry/Hub.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.sentry.protocol.SentryId;
import io.sentry.protocol.SentryTransaction;
import io.sentry.protocol.User;
import io.sentry.transport.RateLimiter;
import io.sentry.util.ExceptionUtils;
import io.sentry.util.HintUtils;
import io.sentry.util.Objects;
Expand Down Expand Up @@ -883,4 +884,10 @@ private Scope buildLocalScope(

return null;
}

@Override
public @Nullable RateLimiter getRateLimiter() {
final StackItem item = stack.peek();
return item.getClient().getRateLimiter();
}
}
6 changes: 6 additions & 0 deletions sentry/src/main/java/io/sentry/HubAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.sentry.protocol.SentryId;
import io.sentry.protocol.SentryTransaction;
import io.sentry.protocol.User;
import io.sentry.transport.RateLimiter;
import java.util.List;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -262,4 +263,9 @@ public void reportFullyDisplayed() {
public @Nullable BaggageHeader getBaggage() {
return Sentry.getBaggage();
}

@Override
public @Nullable RateLimiter getRateLimiter() {
return Sentry.getCurrentHub().getRateLimiter();
}
}
4 changes: 4 additions & 0 deletions sentry/src/main/java/io/sentry/IHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.sentry.protocol.SentryId;
import io.sentry.protocol.SentryTransaction;
import io.sentry.protocol.User;
import io.sentry.transport.RateLimiter;
import java.util.List;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -633,4 +634,7 @@ TransactionContext continueTrace(
*/
@Nullable
BaggageHeader getBaggage();

@Nullable
RateLimiter getRateLimiter();
romtsn marked this conversation as resolved.
Show resolved Hide resolved
}
5 changes: 5 additions & 0 deletions sentry/src/main/java/io/sentry/ISentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.sentry.protocol.Message;
import io.sentry.protocol.SentryId;
import io.sentry.protocol.SentryTransaction;
import io.sentry.transport.RateLimiter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -264,4 +265,8 @@ SentryId captureTransaction(
default @NotNull SentryId captureTransaction(@NotNull SentryTransaction transaction) {
return captureTransaction(transaction, null, null, null);
}

@ApiStatus.Internal
@Nullable
RateLimiter getRateLimiter();
}
6 changes: 6 additions & 0 deletions sentry/src/main/java/io/sentry/NoOpHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.sentry.protocol.SentryId;
import io.sentry.protocol.SentryTransaction;
import io.sentry.protocol.User;
import io.sentry.transport.RateLimiter;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -215,4 +216,9 @@ public void reportFullyDisplayed() {}
public @Nullable BaggageHeader getBaggage() {
return null;
}

@Override
public @Nullable RateLimiter getRateLimiter() {
return null;
}
}
6 changes: 6 additions & 0 deletions sentry/src/main/java/io/sentry/NoOpSentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.sentry.protocol.SentryId;
import io.sentry.protocol.SentryTransaction;
import io.sentry.transport.RateLimiter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -52,4 +53,9 @@ public SentryId captureEnvelope(@NotNull SentryEnvelope envelope, @Nullable Hint
@Nullable ProfilingTraceData profilingTraceData) {
return SentryId.EMPTY_ID;
}

@Override
public @Nullable RateLimiter getRateLimiter() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion;

import io.sentry.transport.RateLimiter;
import io.sentry.util.Objects;
import java.io.Closeable;
import java.io.File;
Expand Down Expand Up @@ -112,6 +113,17 @@ private synchronized void sendCachedEnvelopes(@NotNull IHub hub, @NotNull Sentry
return;
}

// in case there's rate limiting active, skip processing
romtsn marked this conversation as resolved.
Show resolved Hide resolved
final @Nullable RateLimiter rateLimiter = hub.getRateLimiter();
if (rateLimiter != null && rateLimiter.isActiveForCategory(DataCategory.All)) {
options
.getLogger()
.log(
SentryLevel.INFO,
"SendCachedEnvelopeFireAndForgetIntegration, rate limiting active.");
return;
}

final SendFireAndForget sender = factory.create(hub, options);
if (sender == null) {
options.getLogger().log(SentryLevel.ERROR, "SendFireAndForget factory is null.");
Expand Down
6 changes: 6 additions & 0 deletions sentry/src/main/java/io/sentry/SentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.sentry.protocol.SentryId;
import io.sentry.protocol.SentryTransaction;
import io.sentry.transport.ITransport;
import io.sentry.transport.RateLimiter;
import io.sentry.util.HintUtils;
import io.sentry.util.Objects;
import io.sentry.util.TracingUtils;
Expand Down Expand Up @@ -819,6 +820,11 @@ public void flush(final long timeoutMillis) {
transport.flush(timeoutMillis);
}

@Override
public @Nullable RateLimiter getRateLimiter() {
return transport.getRateLimiter();
}

private boolean sample() {
// https://docs.sentry.io/development/sdk-dev/features/#event-sampling
if (options.getSampleRate() != null && random != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ private static QueuedThreadPoolExecutor initExecutor(
1, maxQueueSize, new AsyncConnectionThreadFactory(), storeEvents, logger);
}

@Override
public @NotNull RateLimiter getRateLimiter() {
return rateLimiter;
}

@Override
public void close() throws IOException {
executor.shutdown();
Expand Down
4 changes: 4 additions & 0 deletions sentry/src/main/java/io/sentry/transport/ITransport.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.io.Closeable;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/** A transport is in charge of sending the event to the Sentry server. */
public interface ITransport extends Closeable {
Expand All @@ -20,4 +21,7 @@ default void send(@NotNull SentryEnvelope envelope) throws IOException {
* @param timeoutMillis time in milliseconds
*/
void flush(long timeoutMillis);

@Nullable
RateLimiter getRateLimiter();
}
6 changes: 6 additions & 0 deletions sentry/src/main/java/io/sentry/transport/NoOpTransport.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.io.IOException;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@ApiStatus.Internal
public final class NoOpTransport implements ITransport {
Expand All @@ -24,6 +25,11 @@ public void send(final @NotNull SentryEnvelope envelope, final @NotNull Hint hin
@Override
public void flush(long timeoutMillis) {}

@Override
public @Nullable RateLimiter getRateLimiter() {
return null;
}

@Override
public void close() throws IOException {}
}
Loading