Skip to content

Commit 576789a

Browse files
committed
Tag sockets traffic originating from Sentry's HttpConnection
1 parent 084562d commit 576789a

11 files changed

Lines changed: 188 additions & 0 deletions

File tree

sentry-android-core/api/sentry-android-core.api

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ public class io/sentry/android/core/AndroidProfiler$ProfileStartData {
111111
public fun <init> (JJLjava/util/Date;)V
112112
}
113113

114+
public final class io/sentry/android/core/AndroidSocketTagger : io/sentry/ISocketTagger {
115+
public static fun getInstance ()Lio/sentry/android/core/AndroidSocketTagger;
116+
public fun tagSockets ()V
117+
public fun untagSockets ()V
118+
}
119+
114120
public final class io/sentry/android/core/AnrIntegration : io/sentry/Integration, java/io/Closeable {
115121
public fun <init> (Landroid/content/Context;)V
116122
public fun close ()V

sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.sentry.NoOpCompositePerformanceCollector;
1616
import io.sentry.NoOpConnectionStatusProvider;
1717
import io.sentry.NoOpContinuousProfiler;
18+
import io.sentry.NoOpSocketTagger;
1819
import io.sentry.NoOpTransactionProfiler;
1920
import io.sentry.NoopVersionDetector;
2021
import io.sentry.ScopeType;
@@ -238,6 +239,9 @@ static void initializeIntegrationsAndProcessors(
238239
if (options.getThreadChecker() instanceof NoOpThreadChecker) {
239240
options.setThreadChecker(AndroidThreadChecker.getInstance());
240241
}
242+
if (options.getSocketTagger() instanceof NoOpSocketTagger) {
243+
options.setSocketTagger(AndroidSocketTagger.getInstance());
244+
}
241245
if (options.getPerformanceCollectors().isEmpty()) {
242246
options.addPerformanceCollector(new AndroidMemoryCollector());
243247
options.addPerformanceCollector(new AndroidCpuCollector(options.getLogger()));
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.sentry.android.core;
2+
3+
import android.net.TrafficStats;
4+
import io.sentry.ISocketTagger;
5+
import org.jetbrains.annotations.ApiStatus;
6+
7+
@ApiStatus.Internal
8+
public final class AndroidSocketTagger implements ISocketTagger {
9+
10+
private static final AndroidSocketTagger instance = new AndroidSocketTagger();
11+
12+
private AndroidSocketTagger() {}
13+
14+
public static AndroidSocketTagger getInstance() {
15+
return instance;
16+
}
17+
18+
@Override
19+
public void tagSockets() {
20+
TrafficStats.setThreadStatsTag(1);
21+
}
22+
23+
@Override
24+
public void untagSockets() {
25+
TrafficStats.clearThreadStatsTag();
26+
}
27+
}

sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import io.sentry.DefaultCompositePerformanceCollector
1111
import io.sentry.IConnectionStatusProvider
1212
import io.sentry.IContinuousProfiler
1313
import io.sentry.ILogger
14+
import io.sentry.ISocketTagger
1415
import io.sentry.ITransactionProfiler
1516
import io.sentry.MainEventProcessor
1617
import io.sentry.NoOpContinuousProfiler
@@ -746,6 +747,13 @@ class AndroidOptionsInitializerTest {
746747
assertTrue { fixture.sentryOptions.threadChecker is AndroidThreadChecker }
747748
}
748749

750+
@Test
751+
fun `AndroidSocketTagger is set to options`() {
752+
fixture.initSut()
753+
754+
assertTrue { fixture.sentryOptions.socketTagger is AndroidSocketTagger }
755+
}
756+
749757
@Test
750758
fun `does not install ComposeGestureTargetLocator, if sentry-compose is not available`() {
751759
fixture.initSutWithClassLoader()
@@ -859,6 +867,7 @@ class AndroidOptionsInitializerTest {
859867
setModulesLoader(mock<IModulesLoader>())
860868
setDebugMetaLoader(mock<IDebugMetaLoader>())
861869
threadChecker = mock<IThreadChecker>()
870+
setSocketTagger(mock<ISocketTagger>())
862871
compositePerformanceCollector = mock<CompositePerformanceCollector>()
863872
})
864873

@@ -868,6 +877,7 @@ class AndroidOptionsInitializerTest {
868877
assertFalse { fixture.sentryOptions.modulesLoader is AssetsModulesLoader }
869878
assertFalse { fixture.sentryOptions.debugMetaLoader is AssetsDebugMetaLoader }
870879
assertFalse { fixture.sentryOptions.threadChecker is AndroidThreadChecker }
880+
assertFalse { fixture.sentryOptions.socketTagger is AndroidSocketTagger }
871881
assertFalse { fixture.sentryOptions.compositePerformanceCollector is DefaultCompositePerformanceCollector }
872882
}
873883
}

sentry/api/sentry.api

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,11 @@ public abstract interface class io/sentry/ISerializer {
10281028
public abstract fun serialize (Ljava/util/Map;)Ljava/lang/String;
10291029
}
10301030

1031+
public abstract interface class io/sentry/ISocketTagger {
1032+
public abstract fun tagSockets ()V
1033+
public abstract fun untagSockets ()V
1034+
}
1035+
10311036
public abstract interface class io/sentry/ISpan {
10321037
public abstract fun finish ()V
10331038
public abstract fun finish (Lio/sentry/SpanStatus;)V
@@ -1696,6 +1701,12 @@ public final class io/sentry/NoOpScopesStorage : io/sentry/IScopesStorage {
16961701
public fun set (Lio/sentry/IScopes;)Lio/sentry/ISentryLifecycleToken;
16971702
}
16981703

1704+
public final class io/sentry/NoOpSocketTagger : io/sentry/ISocketTagger {
1705+
public static fun getInstance ()Lio/sentry/ISocketTagger;
1706+
public fun tagSockets ()V
1707+
public fun untagSockets ()V
1708+
}
1709+
16991710
public final class io/sentry/NoOpSpan : io/sentry/ISpan {
17001711
public fun finish ()V
17011712
public fun finish (Lio/sentry/SpanStatus;)V
@@ -3105,6 +3116,7 @@ public class io/sentry/SentryOptions {
31053116
public fun getSessionReplay ()Lio/sentry/SentryReplayOptions;
31063117
public fun getSessionTrackingIntervalMillis ()J
31073118
public fun getShutdownTimeoutMillis ()J
3119+
public fun getSocketTagger ()Lio/sentry/ISocketTagger;
31083120
public fun getSpanFactory ()Lio/sentry/ISpanFactory;
31093121
public fun getSpotlightConnectionUrl ()Ljava/lang/String;
31103122
public fun getSslSocketFactory ()Ljavax/net/ssl/SSLSocketFactory;
@@ -3241,6 +3253,7 @@ public class io/sentry/SentryOptions {
32413253
public fun setSessionReplay (Lio/sentry/SentryReplayOptions;)V
32423254
public fun setSessionTrackingIntervalMillis (J)V
32433255
public fun setShutdownTimeoutMillis (J)V
3256+
public fun setSocketTagger (Lio/sentry/ISocketTagger;)V
32443257
public fun setSpanFactory (Lio/sentry/ISpanFactory;)V
32453258
public fun setSpotlightConnectionUrl (Ljava/lang/String;)V
32463259
public fun setSslSocketFactory (Ljavax/net/ssl/SSLSocketFactory;)V
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package io.sentry.benchmark;
2+
3+
import java.util.concurrent.TimeUnit;
4+
import org.jetbrains.annotations.NotNull;
5+
import org.openjdk.jmh.annotations.*;
6+
7+
@BenchmarkMode(Mode.Throughput)
8+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
9+
@State(Scope.Thread)
10+
public class StringAfterDotBenchmark {
11+
12+
@NotNull private String testString = "";
13+
14+
private char[] buf = new char[64];
15+
16+
@Setup
17+
public void setup() {
18+
testString = "com.example.deep.package.ClassName";
19+
}
20+
//
21+
// @Benchmark
22+
// public String usingSubstring() {
23+
// int idx = testString.lastIndexOf('.');
24+
// return (idx >= 0 && idx + 1 < testString.length())
25+
// ? testString.substring(idx + 1)
26+
// : testString;
27+
// }
28+
//
29+
// @Benchmark
30+
// public String usingManualCharCopy() {
31+
// int len = testString.length();
32+
// for (int i = len - 1; i >= 0; i--) {
33+
// if (testString.charAt(i) == '.') {
34+
// int newLen = len - i - 1;
35+
// char[] buf = new char[newLen];
36+
// testString.getChars(i + 1, len, buf, 0);
37+
// return new String(buf);
38+
// }
39+
// }
40+
// return testString;
41+
// }
42+
43+
@Benchmark
44+
public String usingThreadLocalBuffer() {
45+
int len = testString.length();
46+
int bufIndex = buf.length;
47+
48+
for (int i = len - 1; i >= 0; i--) {
49+
char c = testString.charAt(i);
50+
if (c == '.') {
51+
int suffixLen = buf.length - bufIndex;
52+
return new String(buf, bufIndex, suffixLen);
53+
}
54+
buf[--bufIndex] = c;
55+
}
56+
57+
// No dot found — return original
58+
return testString;
59+
}
60+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.sentry;
2+
3+
public interface ISocketTagger {
4+
/** Tags the sockets traffic originating from the Sentry HttpConnection thread. */
5+
void tagSockets();
6+
7+
/** Untags the sockets traffic originating from the Sentry HttpConnection thread. */
8+
void untagSockets();
9+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package io.sentry;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
5+
public final class NoOpSocketTagger implements ISocketTagger {
6+
7+
private static final NoOpSocketTagger instance = new NoOpSocketTagger();
8+
9+
private NoOpSocketTagger() {}
10+
11+
public static @NotNull ISocketTagger getInstance() {
12+
return instance;
13+
}
14+
15+
@Override
16+
public void tagSockets() {
17+
// No operation
18+
}
19+
20+
@Override
21+
public void untagSockets() {
22+
// No operation
23+
}
24+
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,8 @@ public class SentryOptions {
566566
*/
567567
private boolean startProfilerOnAppStart = false;
568568

569+
private @NotNull ISocketTagger socketTagger = NoOpSocketTagger.getInstance();
570+
569571
/**
570572
* Adds an event processor
571573
*
@@ -2827,6 +2829,24 @@ public boolean isCaptureOpenTelemetryEvents() {
28272829
return captureOpenTelemetryEvents;
28282830
}
28292831

2832+
/**
2833+
* Returns the SocketTagger
2834+
*
2835+
* @return the socket tagger
2836+
*/
2837+
public @NotNull ISocketTagger getSocketTagger() {
2838+
return socketTagger;
2839+
}
2840+
2841+
/**
2842+
* Sets the SocketTagger
2843+
*
2844+
* @param socketTagger the socket tagger
2845+
*/
2846+
public void setSocketTagger(final @Nullable ISocketTagger socketTagger) {
2847+
this.socketTagger = socketTagger != null ? socketTagger : NoOpSocketTagger.getInstance();
2848+
}
2849+
28302850
/**
28312851
* Load the lazy fields. Useful to load in the background, so that results are already cached. DO
28322852
* NOT CALL THIS METHOD ON THE MAIN THREAD.

sentry/src/main/java/io/sentry/transport/HttpConnection.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ HttpURLConnection open() throws IOException {
146146
}
147147

148148
public @NotNull TransportResult send(final @NotNull SentryEnvelope envelope) throws IOException {
149+
options.getSocketTagger().tagSockets();
149150
final HttpURLConnection connection = createConnection();
150151
TransportResult result;
151152

@@ -161,6 +162,7 @@ HttpURLConnection open() throws IOException {
161162
"An exception occurred while submitting the envelope to the Sentry server.");
162163
} finally {
163164
result = readAndLog(connection);
165+
options.getSocketTagger().untagSockets();
164166
}
165167
return result;
166168
}

0 commit comments

Comments
 (0)