Skip to content
This repository was archived by the owner on Aug 30, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 20 additions & 5 deletions sentry-core/src/main/java/io/sentry/core/MainEventProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,28 @@
public final class MainEventProcessor implements EventProcessor {

private final SentryOptions options;
private final SentryThreadFactory sentryThreadFactory = new SentryThreadFactory();
private final SentryStackTraceFactory sentryStackTraceFactory = new SentryStackTraceFactory();
private final SentryExceptionFactory sentryExceptionFactory =
new SentryExceptionFactory(sentryStackTraceFactory);
private final SentryThreadFactory sentryThreadFactory;
private final SentryExceptionFactory sentryExceptionFactory;

MainEventProcessor(SentryOptions options) {
MainEventProcessor(final SentryOptions options) {
this.options = Objects.requireNonNull(options, "The SentryOptions is required.");

SentryStackTraceFactory sentryStackTraceFactory =
new SentryStackTraceFactory(options.getInAppExcludes(), options.getInAppIncludes());

sentryExceptionFactory = new SentryExceptionFactory(sentryStackTraceFactory);
sentryThreadFactory = new SentryThreadFactory(sentryStackTraceFactory);
}

MainEventProcessor(
final SentryOptions options,
final SentryThreadFactory sentryThreadFactory,
final SentryExceptionFactory sentryExceptionFactory) {
this.options = Objects.requireNonNull(options, "The SentryOptions is required.");
this.sentryThreadFactory =
Objects.requireNonNull(sentryThreadFactory, "The SentryThreadFactory is required.");
this.sentryExceptionFactory =
Objects.requireNonNull(sentryExceptionFactory, "The SentryExceptionFactory is required.");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ final class SentryExceptionFactory {

private final SentryStackTraceFactory sentryStackTraceFactory;

public SentryExceptionFactory(SentryStackTraceFactory sentryStackTraceFactory) {
public SentryExceptionFactory(final SentryStackTraceFactory sentryStackTraceFactory) {
this.sentryStackTraceFactory =
Objects.requireNonNull(sentryStackTraceFactory, "The SentryStackTraceFactory is required.");
}
Expand Down
21 changes: 21 additions & 0 deletions sentry-core/src/main/java/io/sentry/core/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public final class SentryOptions {
private String environment;
private Proxy proxy;
private Double sampling;
private List<String> inAppExcludes;
private List<String> inAppIncludes;

public void addEventProcessor(EventProcessor eventProcessor) {
eventProcessors.add(eventProcessor);
Expand Down Expand Up @@ -188,6 +190,22 @@ public void setSampling(Double sampling) {
this.sampling = sampling;
}

public List<String> getInAppExcludes() {
return inAppExcludes;
}

public void setInAppExcludes(List<String> inAppExcludes) {
this.inAppExcludes = inAppExcludes;
}

public List<String> getInAppIncludes() {
return inAppIncludes;
}

public void setInAppIncludes(List<String> inAppIncludes) {
this.inAppIncludes = inAppIncludes;
}

public interface BeforeSendCallback {
SentryEvent execute(SentryEvent event);
}
Expand All @@ -197,6 +215,9 @@ public interface BeforeBreadcrumbCallback {
}

public SentryOptions() {
inAppExcludes = new ArrayList<>();
inAppExcludes.add("io.sentry");

eventProcessors.add(new MainEventProcessor(this));
integrations.add(new UncaughtExceptionHandlerIntegration());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
/** class responsible for converting Java StackTraceElements to SentryStackFrames */
final class SentryStackTraceFactory {

private final List<String> inAppExcludes;
private final List<String> inAppIncludes;

public SentryStackTraceFactory(
@Nullable final List<String> inAppExcludes, @Nullable List<String> inAppIncludes) {
this.inAppExcludes = inAppExcludes;
this.inAppIncludes = inAppIncludes;
}

/**
* convert an Array of Java StackTraceElements to a list of SentryStackFrames
*
Expand All @@ -21,17 +30,40 @@ List<SentryStackFrame> getStackFrames(@Nullable final StackTraceElement[] elemen
for (StackTraceElement item : elements) {
if (item != null) {
SentryStackFrame sentryStackFrame = new SentryStackFrame();
// https://docs.sentry.io/development/sdk-dev/features/#in-app-frames
sentryStackFrame.setInApp(isInApp(item.getClassName()));
sentryStackFrame.setModule(item.getClassName());
sentryStackFrame.setFunction(item.getMethodName());
sentryStackFrame.setFilename(item.getFileName());
sentryStackFrame.setLineno(item.getLineNumber());
sentryStackFrame.setNative(item.isNativeMethod());

sentryStackFrames.add(sentryStackFrame);
}
}
}

return sentryStackFrames;
}

private boolean isInApp(String className) {
if (className == null || className.isEmpty()) {
return true;
}

if (inAppIncludes != null) {
for (String include : inAppIncludes) {
if (className.startsWith(include)) {
return true;
}
}
}
if (inAppExcludes != null) {
for (String exclude : inAppExcludes) {
if (className.startsWith(exclude)) {
return false;
}
}
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@
import io.sentry.core.protocol.SentryStackFrame;
import io.sentry.core.protocol.SentryStackTrace;
import io.sentry.core.protocol.SentryThread;
import io.sentry.core.util.Objects;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.Nullable;

final class SentryThreadFactory {

private final SentryStackTraceFactory sentryStackTraceFactory;

public SentryThreadFactory(SentryStackTraceFactory sentryStackTraceFactory) {
this.sentryStackTraceFactory =
Objects.requireNonNull(sentryStackTraceFactory, "The SentryStackTraceFactory is required.");
}

// Assumes its being called from the crashed thread.
List<SentryThread> getCurrentThreadsForCrash() {
return getCurrentThreads(Thread.currentThread());
Expand Down Expand Up @@ -49,7 +57,6 @@ private SentryThread getSentryThread(
}
sentryThread.setCurrent(thread == currentThread);

SentryStackTraceFactory sentryStackTraceFactory = new SentryStackTraceFactory();
List<SentryStackFrame> frames = sentryStackTraceFactory.getStackFrames(stackFramesElements);

if (frames.size() > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertTrue

class SentryExceptionFactoryTest {
private val sut = SentryExceptionFactory(SentryStackTraceFactory())
private val sut = SentryExceptionFactory(SentryStackTraceFactory(listOf("io.sentry"), listOf()))

@Test
fun `when getSentryExceptions is called passing an Exception, not empty result`() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package io.sentry.core

import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class SentryStackTraceFactoryTest {
private val sut = SentryStackTraceFactory()
private val sut = SentryStackTraceFactory(listOf(), listOf())

@Test
fun `when getStackFrames is called passing a valid Array, not empty result`() {
Expand All @@ -20,13 +22,90 @@ class SentryStackTraceFactoryTest {

@Test
fun `when getStackFrames is called passing a valid array, fields should be set`() {
val element = StackTraceElement("class", "method", "fileName", -2)
val stacktraces = Array(1) { element }
val element = generateStackTrace("class")
val stacktraces = arrayOf(element)
val stackFrames = sut.getStackFrames(stacktraces)
assertEquals("class", stackFrames[0].module)
assertEquals("method", stackFrames[0].function)
assertEquals("fileName", stackFrames[0].filename)
assertEquals(-2, stackFrames[0].lineno)
assertEquals(true, stackFrames[0].isNative)
}

//region inAppExcludes
@Test
fun `when getStackFrames is called passing a valid inAppExcludes, inApp should be false if prefix matches it`() {
val element = generateStackTrace("io.sentry.MyActivity")
val elements = arrayOf(element)
val sentryStackTraceFactory = SentryStackTraceFactory(listOf("io.sentry"), null)
val sentryElements = sentryStackTraceFactory.getStackFrames(elements)

assertFalse(sentryElements.first().inApp)
}

@Test
fun `when getStackFrames is called passing a valid inAppExcludes, inApp should be true if prefix doesnt matches it`() {
val element = generateStackTrace("io.myapp.MyActivity")
val elements = arrayOf(element)
val sentryStackTraceFactory = SentryStackTraceFactory(listOf("io.sentry"), null)
val sentryElements = sentryStackTraceFactory.getStackFrames(elements)

assertTrue(sentryElements.first().inApp)
}

@Test
fun `when getStackFrames is called passing an invalid inAppExcludes, inApp should be false`() {
val element = generateStackTrace("io.sentry.MyActivity")
val elements = arrayOf(element)
val sentryStackTraceFactory = SentryStackTraceFactory(null, null)
val sentryElements = sentryStackTraceFactory.getStackFrames(elements)

assertTrue(sentryElements.first().inApp)
}
//endregion

//region inAppIncludes
@Test
fun `when getStackFrames is called passing a valid inAppIncludes, inApp should be true if prefix matches it`() {
val element = generateStackTrace("io.sentry.MyActivity")
val elements = arrayOf(element)
val sentryStackTraceFactory = SentryStackTraceFactory(null, listOf("io.sentry"))
val sentryElements = sentryStackTraceFactory.getStackFrames(elements)

assertTrue(sentryElements.first().inApp)
}

@Test
fun `when getStackFrames is called passing a valid inAppIncludes, inApp should be true if prefix doesnt matches it`() {
val element = generateStackTrace("io.myapp.MyActivity")
val elements = arrayOf(element)
val sentryStackTraceFactory = SentryStackTraceFactory(null, listOf("io.sentry"))
val sentryElements = sentryStackTraceFactory.getStackFrames(elements)

assertTrue(sentryElements.first().inApp)
}

@Test
fun `when getStackFrames is called passing an invalid inAppIncludes, inApp should be true`() {
val element = generateStackTrace("io.sentry.MyActivity")
val elements = arrayOf(element)
val sentryStackTraceFactory = SentryStackTraceFactory(null, null)
val sentryElements = sentryStackTraceFactory.getStackFrames(elements)

assertTrue(sentryElements.first().inApp)
}
//endregion

@Test
fun `when getStackFrames is called passing a valid inAppIncludes and inAppExcludes, inApp should take precedence`() {
val element = generateStackTrace("io.sentry.MyActivity")
val elements = arrayOf(element)
val sentryStackTraceFactory = SentryStackTraceFactory(listOf("io.sentry"), listOf("io.sentry"))
val sentryElements = sentryStackTraceFactory.getStackFrames(elements)

assertTrue(sentryElements.first().inApp)
}

private fun generateStackTrace(className: String?) =
StackTraceElement(className, "method", "fileName", -2)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import kotlin.test.assertTrue

class SentryThreadFactoryTest {

private val sut = SentryThreadFactory()
private val sut = SentryThreadFactory(SentryStackTraceFactory(listOf("io.sentry"), listOf()))

@Test
fun `when getCurrentThreads is called, not empty result`() {
Expand Down