Skip to content

Commit

Permalink
Load sentry-debug-meta.properties (#2734)
Browse files Browse the repository at this point in the history
  • Loading branch information
adinauer authored May 30, 2023
1 parent b056859 commit 9dddfbf
Show file tree
Hide file tree
Showing 14 changed files with 456 additions and 94 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
### Features

- Add SentryWrapper for Callable and Supplier Interface ([#2720](https://github.com/getsentry/sentry-java/pull/2720))
- Load sentry-debug-meta.properties ([#2734](https://github.com/getsentry/sentry-java/pull/2734))
- This enables source context for Java
- For more information on how to enable source context, please refer to [#633](https://github.com/getsentry/sentry-java/issues/633#issuecomment-1465599120)

### Fixes

- Finish WebFlux transaction before popping scope ([#2724](https://github.com/getsentry/sentry-java/pull/2724))

### Fixes

Expand Down Expand Up @@ -33,7 +40,6 @@
### Fixes

- Base64 encode internal Apollo3 Headers ([#2707](https://github.com/getsentry/sentry-java/pull/2707))
- Finish WebFlux transaction before popping scope ([#2724](https://github.com/getsentry/sentry-java/pull/2724))
- Fix `SentryTracer` crash when scheduling auto-finish of a transaction, but the timer has already been cancelled ([#2731](https://github.com/getsentry/sentry-java/pull/2731))
- Fix `AndroidTransactionProfiler` crash when finishing a profile that happened due to race condition ([#2731](https://github.com/getsentry/sentry-java/pull/2731))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.res.AssetManager;
import android.os.Build;
import io.sentry.DefaultTransactionPerformanceCollector;
import io.sentry.ILogger;
import io.sentry.SendFireAndForgetEnvelopeSender;
import io.sentry.SendFireAndForgetOutboxSender;
import io.sentry.SentryLevel;
import io.sentry.android.core.cache.AndroidEnvelopeCache;
import io.sentry.android.core.internal.debugmeta.AssetsDebugMetaLoader;
import io.sentry.android.core.internal.gestures.AndroidViewGestureTargetLocator;
import io.sentry.android.core.internal.modules.AssetsModulesLoader;
import io.sentry.android.core.internal.util.AndroidMainThreadChecker;
Expand All @@ -27,16 +27,10 @@
import io.sentry.internal.viewhierarchy.ViewHierarchyExporter;
import io.sentry.transport.NoOpEnvelopeCache;
import io.sentry.util.Objects;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;

/**
Expand Down Expand Up @@ -153,6 +147,7 @@ static void initializeIntegrationsAndProcessors(
options.setTransactionProfiler(
new AndroidTransactionProfiler(context, options, buildInfoProvider, frameMetricsCollector));
options.setModulesLoader(new AssetsModulesLoader(context, options.getLogger()));
options.setDebugMetaLoader(new AssetsDebugMetaLoader(context, options.getLogger()));

final boolean isAndroidXScrollViewAvailable =
loadClass.isClassAvailable("androidx.core.view.ScrollingView", options);
Expand Down Expand Up @@ -303,52 +298,6 @@ private static void readDefaultOptionValues(
options.getLogger().log(SentryLevel.ERROR, "Could not generate distinct Id.", e);
}
}

final @Nullable Properties debugMetaProperties =
loadDebugMetaProperties(context, options.getLogger());

if (debugMetaProperties != null) {
if (options.getProguardUuid() == null) {
final @Nullable String proguardUuid =
debugMetaProperties.getProperty("io.sentry.ProguardUuids");
options.getLogger().log(SentryLevel.DEBUG, "Proguard UUID found: %s", proguardUuid);
options.setProguardUuid(proguardUuid);
}

if (options.getBundleIds().isEmpty()) {
final @Nullable String bundleIdStrings =
debugMetaProperties.getProperty("io.sentry.bundle-ids");
options.getLogger().log(SentryLevel.DEBUG, "Bundle IDs found: %s", bundleIdStrings);
if (bundleIdStrings != null) {
final @NotNull String[] bundleIds = bundleIdStrings.split(",", -1);
for (final String bundleId : bundleIds) {
options.addBundleId(bundleId);
}
}
}
}
}

private static @Nullable Properties loadDebugMetaProperties(
final @NotNull Context context, final @NotNull ILogger logger) {
final AssetManager assets = context.getAssets();
// one may have thousands of asset files and looking up this list might slow down the SDK init.
// quite a bit, for this reason, we try to open the file directly and take care of errors
// like FileNotFoundException
try (final InputStream is =
new BufferedInputStream(assets.open("sentry-debug-meta.properties"))) {
final Properties properties = new Properties();
properties.load(is);
return properties;
} catch (FileNotFoundException e) {
logger.log(SentryLevel.INFO, "sentry-debug-meta.properties file was not found.");
} catch (IOException e) {
logger.log(SentryLevel.ERROR, "Error getting Proguard UUIDs.", e);
} catch (RuntimeException e) {
logger.log(SentryLevel.ERROR, "sentry-debug-meta.properties file is malformed.", e);
}

return null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.sentry.android.core.internal.debugmeta;

import static io.sentry.util.DebugMetaPropertiesApplier.DEBUG_META_PROPERTIES_FILENAME;

import android.content.Context;
import android.content.res.AssetManager;
import io.sentry.ILogger;
import io.sentry.SentryLevel;
import io.sentry.internal.debugmeta.IDebugMetaLoader;
import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@ApiStatus.Internal
public final class AssetsDebugMetaLoader implements IDebugMetaLoader {
private final @NotNull Context context;
private final @NotNull ILogger logger;

public AssetsDebugMetaLoader(final @NotNull Context context, final @NotNull ILogger logger) {
this.context = context;
this.logger = logger;
}

@Override
public @Nullable Properties loadDebugMeta() {
final AssetManager assets = context.getAssets();
// one may have thousands of asset files and looking up this list might slow down the SDK init.
// quite a bit, for this reason, we try to open the file directly and take care of errors
// like FileNotFoundException
try (final InputStream is =
new BufferedInputStream(assets.open(DEBUG_META_PROPERTIES_FILENAME))) {
final Properties properties = new Properties();
properties.load(is);
return properties;
} catch (FileNotFoundException e) {
logger.log(SentryLevel.INFO, e, "%s file was not found.", DEBUG_META_PROPERTIES_FILENAME);
} catch (IOException e) {
logger.log(SentryLevel.ERROR, "Error getting Proguard UUIDs.", e);
} catch (RuntimeException e) {
logger.log(SentryLevel.ERROR, e, "%s file is malformed.", DEBUG_META_PROPERTIES_FILENAME);
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -280,46 +280,6 @@ class AndroidOptionsInitializerTest {
assertEquals("proguard-uuid", fixture.sentryOptions.proguardUuid)
}

@Test
fun `init should set proguard uuid from properties id on start`() {
val assets = mock<AssetManager>()

whenever(assets.open("sentry-debug-meta.properties")).thenReturn(
"""
io.sentry.ProguardUuids=12ea7a02-46ac-44c0-a5bb-6d1fd9586411
""".trimIndent().byteInputStream()
)

fixture.initSut(
Bundle(),
hasAppContext = false,
assets = assets
)

assertNotNull(fixture.sentryOptions.proguardUuid)
assertEquals("12ea7a02-46ac-44c0-a5bb-6d1fd9586411", fixture.sentryOptions.proguardUuid)
}

@Test
fun `init should set bundle IDs id on start`() {
val assets = mock<AssetManager>()

whenever(assets.open("sentry-debug-meta.properties")).thenReturn(
"""
io.sentry.bundle-ids=12ea7a02-46ac-44c0-a5bb-6d1fd9586411, faa3ab42-b1bd-4659-af8e-1682324aa744
""".trimIndent().byteInputStream()
)

fixture.initSut(
Bundle(),
hasAppContext = false,
assets = assets
)

assertTrue(fixture.sentryOptions.bundleIds.size == 2)
assertTrue(fixture.sentryOptions.bundleIds.containsAll(listOf("12ea7a02-46ac-44c0-a5bb-6d1fd9586411", "faa3ab42-b1bd-4659-af8e-1682324aa744")))
}

@Test
fun `init should set Android transport gate`() {
fixture.initSut()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package io.sentry.android.core.internal.debugmeta

import android.content.Context
import android.content.res.AssetManager
import io.sentry.ILogger
import io.sentry.SentryOptions
import io.sentry.util.DebugMetaPropertiesApplier
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import java.io.FileNotFoundException
import java.nio.charset.Charset
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

class AssetsDebugMetaLoaderTest {

class Fixture {
val context = mock<Context>()
val assets = mock<AssetManager>()
val logger = mock<ILogger>()

fun getSut(
fileName: String = "sentry-debug-meta.properties",
content: String? = null,
throws: Boolean = false
): AssetsDebugMetaLoader {
if (content != null) {
whenever(assets.open(fileName)).thenReturn(
content.byteInputStream(Charset.defaultCharset())
)
}
if (throws) {
whenever(assets.open(fileName)).thenThrow(FileNotFoundException())
}
whenever(context.assets).thenReturn(assets)
return AssetsDebugMetaLoader(context, logger)
}
}

private val fixture = Fixture()

@Test
fun `reads from assets into properties and can be applied to options`() {
val sut = fixture.getSut(
content =
"""
#Generated by sentry-maven-plugin
#Wed May 17 15:33:34 CEST 2023
io.sentry.ProguardUuids=34077988-a0e5-4839-9618-7400e1616d1b
io.sentry.bundle-ids=88ba82db-cd26-4c09-8b31-21461d286b68
io.sentry.build-tool=maven
""".trimIndent()
)

val options = SentryOptions()

assertNotNull(sut.loadDebugMeta()) {
DebugMetaPropertiesApplier.applyToOptions(options, it)
}

assertEquals(options.bundleIds, setOf("88ba82db-cd26-4c09-8b31-21461d286b68"))
assertEquals(options.proguardUuid, "34077988-a0e5-4839-9618-7400e1616d1b")
}

@Test
fun `reads multiple bundle IDs from assets into properties and can be applied to options`() {
val sut = fixture.getSut(
content =
"""
#Generated by sentry-maven-plugin
#Wed May 17 15:33:34 CEST 2023
io.sentry.ProguardUuids=34077988-a0e5-4839-9618-7400e1616d1b
io.sentry.bundle-ids=88ba82db-cd26-4c09-8b31-21461d286b68,8d11a44a-facd-46c1-a49b-87d256227101
io.sentry.build-tool=maven
""".trimIndent()
)

val options = SentryOptions()

assertNotNull(sut.loadDebugMeta()) {
DebugMetaPropertiesApplier.applyToOptions(options, it)
}

assertEquals(options.bundleIds, setOf("88ba82db-cd26-4c09-8b31-21461d286b68", "8d11a44a-facd-46c1-a49b-87d256227101"))
assertEquals(options.proguardUuid, "34077988-a0e5-4839-9618-7400e1616d1b")
}

@Test
fun `when file does not exist, swallows exception and returns null`() {
val sut = fixture.getSut(throws = true)

assertNull(sut.loadDebugMeta())
}
}
22 changes: 22 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -1648,6 +1648,7 @@ public class io/sentry/SentryOptions {
public fun getConnectionTimeoutMillis ()I
public fun getContextTags ()Ljava/util/List;
public fun getDateProvider ()Lio/sentry/SentryDateProvider;
public fun getDebugMetaLoader ()Lio/sentry/internal/debugmeta/IDebugMetaLoader;
public fun getDiagnosticLevel ()Lio/sentry/SentryLevel;
public fun getDist ()Ljava/lang/String;
public fun getDistinctId ()Ljava/lang/String;
Expand Down Expand Up @@ -1740,6 +1741,7 @@ public class io/sentry/SentryOptions {
public fun setConnectionTimeoutMillis (I)V
public fun setDateProvider (Lio/sentry/SentryDateProvider;)V
public fun setDebug (Z)V
public fun setDebugMetaLoader (Lio/sentry/internal/debugmeta/IDebugMetaLoader;)V
public fun setDiagnosticLevel (Lio/sentry/SentryLevel;)V
public fun setDist (Ljava/lang/String;)V
public fun setDistinctId (Ljava/lang/String;)V
Expand Down Expand Up @@ -2653,6 +2655,20 @@ public final class io/sentry/instrumentation/file/SentryFileWriter : java/io/Out
public fun <init> (Ljava/lang/String;Z)V
}

public abstract interface class io/sentry/internal/debugmeta/IDebugMetaLoader {
public abstract fun loadDebugMeta ()Ljava/util/Properties;
}

public final class io/sentry/internal/debugmeta/NoOpDebugMetaLoader : io/sentry/internal/debugmeta/IDebugMetaLoader {
public static fun getInstance ()Lio/sentry/internal/debugmeta/NoOpDebugMetaLoader;
public fun loadDebugMeta ()Ljava/util/Properties;
}

public final class io/sentry/internal/debugmeta/ResourcesDebugMetaLoader : io/sentry/internal/debugmeta/IDebugMetaLoader {
public fun <init> (Lio/sentry/ILogger;)V
public fun loadDebugMeta ()Ljava/util/Properties;
}

public abstract interface class io/sentry/internal/gestures/GestureTargetLocator {
public abstract fun locate (Ljava/lang/Object;FFLio/sentry/internal/gestures/UiElement$Type;)Lio/sentry/internal/gestures/UiElement;
}
Expand Down Expand Up @@ -4006,6 +4022,12 @@ public abstract interface class io/sentry/util/CollectionUtils$Predicate {
public abstract fun test (Ljava/lang/Object;)Z
}

public final class io/sentry/util/DebugMetaPropertiesApplier {
public static field DEBUG_META_PROPERTIES_FILENAME Ljava/lang/String;
public fun <init> ()V
public static fun applyToOptions (Lio/sentry/SentryOptions;Ljava/util/Properties;)V
}

public final class io/sentry/util/ExceptionUtils {
public fun <init> ()V
public static fun findRootCause (Ljava/lang/Throwable;)Ljava/lang/Throwable;
Expand Down
10 changes: 10 additions & 0 deletions sentry/src/main/java/io/sentry/Sentry.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import io.sentry.cache.EnvelopeCache;
import io.sentry.cache.IEnvelopeCache;
import io.sentry.config.PropertiesProviderFactory;
import io.sentry.internal.debugmeta.NoOpDebugMetaLoader;
import io.sentry.internal.debugmeta.ResourcesDebugMetaLoader;
import io.sentry.internal.modules.CompositeModulesLoader;
import io.sentry.internal.modules.IModulesLoader;
import io.sentry.internal.modules.ManifestModulesLoader;
Expand All @@ -11,6 +13,7 @@
import io.sentry.protocol.SentryId;
import io.sentry.protocol.User;
import io.sentry.transport.NoOpEnvelopeCache;
import io.sentry.util.DebugMetaPropertiesApplier;
import io.sentry.util.FileUtils;
import io.sentry.util.thread.IMainThreadChecker;
import io.sentry.util.thread.MainThreadChecker;
Expand All @@ -19,6 +22,7 @@
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.RejectedExecutionException;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -363,6 +367,12 @@ private static boolean initConfigurations(final @NotNull SentryOptions options)
options.getLogger()));
}

if (options.getDebugMetaLoader() instanceof NoOpDebugMetaLoader) {
options.setDebugMetaLoader(new ResourcesDebugMetaLoader(options.getLogger()));
}
final @Nullable Properties properties = options.getDebugMetaLoader().loadDebugMeta();
DebugMetaPropertiesApplier.applyToOptions(options, properties);

final IMainThreadChecker mainThreadChecker = options.getMainThreadChecker();
// only override the MainThreadChecker if it's not already set by Android
if (mainThreadChecker instanceof NoOpMainThreadChecker) {
Expand Down
Loading

0 comments on commit 9dddfbf

Please sign in to comment.