Skip to content

Commit

Permalink
Fix: Run event processors and enrich transactions with contexts (#1430)
Browse files Browse the repository at this point in the history
  • Loading branch information
marandaneto authored Apr 26, 2021
1 parent 6c8aae1 commit 053a8ab
Show file tree
Hide file tree
Showing 21 changed files with 767 additions and 367 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Fix: Do not set free memory and is low memory fields when it's a NDK hard crash (#1399)
* Fix: Apply user from the scope to transaction (#1424)
* Fix: Pass maxBreadcrumbs config. to sentry-native (#1425)
* Fix: Run event processors and enrich transactions with contexts (#1430)
* Bump: sentry-native to 0.4.9 (#1431)

# 4.4.0-alpha.2
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,7 @@ checkFormat:
# Spotless format's code
format:
./gradlew spotlessApply

# Binary compatibility validator
api:
./gradlew apiDump
1 change: 1 addition & 0 deletions sentry-android-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,5 @@ dependencies {
testImplementation(Config.TestLibs.mockitoKotlin)
testImplementation(Config.TestLibs.mockitoInline)
testImplementation(Config.TestLibs.awaitility)
testImplementation(project(":sentry-test-support"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.sentry.DateUtils;
import io.sentry.EventProcessor;
import io.sentry.ILogger;
import io.sentry.SentryBaseEvent;
import io.sentry.SentryEvent;
import io.sentry.SentryLevel;
import io.sentry.android.core.util.ConnectivityChecker;
Expand All @@ -34,6 +35,7 @@
import io.sentry.protocol.Device;
import io.sentry.protocol.OperatingSystem;
import io.sentry.protocol.SentryThread;
import io.sentry.protocol.SentryTransaction;
import io.sentry.protocol.User;
import io.sentry.util.ApplyScopeUtils;
import io.sentry.util.Objects;
Expand Down Expand Up @@ -139,40 +141,64 @@ public DefaultAndroidEventProcessor(
@Override
public @NotNull SentryEvent process(
final @NotNull SentryEvent event, final @Nullable Object hint) {
final boolean applyScopeData = ApplyScopeUtils.shouldApplyScopeData(hint);

// we only set memory data if it's not a hard crash, when it's a hard crash the event is
// enriched on restart, so non static data might be wrong, eg lowMemory or availMem will
// be different if the App. crashes because of OOM.
final boolean applyScopeData = shouldApplyScopeData(event, hint);
if (applyScopeData) {
// we only set memory data if it's not a hard crash, when it's a hard crash the event is
// enriched on restart, so non static data might be wrong, eg lowMemory or availMem will
// be different if the App. crashes because of OOM.
processNonCachedEvent(event);
mergeDebugImages(event);
setThreads(event);
}

setCommons(event, true, applyScopeData);

return event;
}

private void setCommons(
final @NotNull SentryBaseEvent event,
final boolean errorEvent,
final boolean applyScopeData) {
mergeUser(event);
setDevice(event, errorEvent, applyScopeData);
mergeOS(event);
setSideLoadedInfo(event);
}

private boolean shouldApplyScopeData(
final @NotNull SentryBaseEvent event, final @Nullable Object hint) {
if (ApplyScopeUtils.shouldApplyScopeData(hint)) {
return true;
} else {
logger.log(
SentryLevel.DEBUG,
"Event was cached so not applying data relevant to the current app execution/version: %s",
event.getEventId());
return false;
}
}

private void mergeUser(final @NotNull SentryBaseEvent event) {
// userId should be set even if event is Cached as the userId is static and won't change anyway.
final User user = event.getUser();
if (user == null) {
event.setUser(getDefaultUser());
} else if (user.getId() == null) {
user.setId(getDeviceId());
}
}

private void setDevice(
final @NotNull SentryBaseEvent event,
final boolean errorEvent,
final boolean applyScopeData) {
if (event.getContexts().getDevice() == null) {
event.getContexts().setDevice(getDevice(applyScopeData));
event.getContexts().setDevice(getDevice(errorEvent, applyScopeData));
}

mergeOS(event);

setSideLoadedInfo(event);

return event;
}

private void mergeOS(final @NotNull SentryEvent event) {
private void mergeOS(final @NotNull SentryBaseEvent event) {
final OperatingSystem currentOS = event.getContexts().getOperatingSystem();
final OperatingSystem androidOS = getOperatingSystem();

Expand All @@ -192,34 +218,42 @@ private void mergeOS(final @NotNull SentryEvent event) {
}

// Data to be applied to events that was created in the running process
private void processNonCachedEvent(final @NotNull SentryEvent event) {
private void processNonCachedEvent(final @NotNull SentryBaseEvent event) {
App app = event.getContexts().getApp();
if (app == null) {
app = new App();
}
setAppExtras(app);

mergeDebugImages(event);

PackageInfo packageInfo = ContextUtils.getPackageInfo(context, logger);
if (packageInfo != null) {
String versionCode = ContextUtils.getVersionCode(packageInfo);

if (event.getDist() == null) {
event.setDist(versionCode);
}
setAppPackageInfo(app, packageInfo);
}
setPackageInfo(event, app);

event.getContexts().setApp(app);
}

private void setThreads(final @NotNull SentryEvent event) {
if (event.getThreads() != null) {
for (SentryThread thread : event.getThreads()) {
thread.setCurrent(MainThreadChecker.isMainThread(thread));
}
}
}

private void setPackageInfo(final @NotNull SentryBaseEvent event, final @NotNull App app) {
final PackageInfo packageInfo = ContextUtils.getPackageInfo(context, logger);
if (packageInfo != null) {
String versionCode = ContextUtils.getVersionCode(packageInfo);

setDist(event, versionCode);
setAppPackageInfo(app, packageInfo);
}
}

private void setDist(final @NotNull SentryBaseEvent event, final @NotNull String versionCode) {
if (event.getDist() == null) {
event.setDist(versionCode);
}
}

private void mergeDebugImages(final @NotNull SentryEvent event) {
final List<DebugImage> debugImages = getDebugImages();
if (debugImages == null) {
Expand Down Expand Up @@ -307,7 +341,7 @@ private void setArchitectures(final @NotNull Device device) {

// we can get some inspiration here
// https://github.com/flutter/plugins/blob/master/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java
private @NotNull Device getDevice(final boolean applyScopeData) {
private @NotNull Device getDevice(final boolean errorEvent, final boolean applyScopeData) {
// TODO: missing usable memory

Device device = new Device();
Expand All @@ -319,7 +353,45 @@ private void setArchitectures(final @NotNull Device device) {
device.setModelId(Build.ID);
setArchitectures(device);

Intent batteryIntent = getBatteryIntent();
// setting such values require IO hence we don't run for transactions
if (errorEvent) {
setDeviceIO(device, applyScopeData);
}

device.setOrientation(getOrientation());

try {
Object emulator = contextData.get().get(EMULATOR);
if (emulator != null) {
device.setSimulator((Boolean) emulator);
}
} catch (Exception e) {
logger.log(SentryLevel.ERROR, "Error getting emulator.", e);
}

DisplayMetrics displayMetrics = getDisplayMetrics();
if (displayMetrics != null) {
device.setScreenWidthPixels(displayMetrics.widthPixels);
device.setScreenHeightPixels(displayMetrics.heightPixels);
device.setScreenDensity(displayMetrics.density);
device.setScreenDpi(displayMetrics.densityDpi);
}

device.setBootTime(getBootTime());
device.setTimezone(getTimeZone());

if (device.getId() == null) {
device.setId(getDeviceId());
}
if (device.getLanguage() == null) {
device.setLanguage(Locale.getDefault().toString()); // eg en_US
}

return device;
}

private void setDeviceIO(final @NotNull Device device, final boolean applyScopeData) {
final Intent batteryIntent = getBatteryIntent();
if (batteryIntent != null) {
device.setBatteryLevel(getBatteryLevel(batteryIntent));
device.setCharging(isCharging(batteryIntent));
Expand All @@ -338,18 +410,8 @@ private void setArchitectures(final @NotNull Device device) {
connected = null;
}
device.setOnline(connected);
device.setOrientation(getOrientation());

try {
Object emulator = contextData.get().get(EMULATOR);
if (emulator != null) {
device.setSimulator((Boolean) emulator);
}
} catch (Exception e) {
logger.log(SentryLevel.ERROR, "Error getting emulator.", e);
}

ActivityManager.MemoryInfo memInfo = getMemInfo();
final ActivityManager.MemoryInfo memInfo = getMemInfo();
if (memInfo != null) {
// in bytes
device.setMemorySize(getMemorySize(memInfo));
Expand All @@ -363,45 +425,24 @@ private void setArchitectures(final @NotNull Device device) {

// this way of getting the size of storage might be problematic for storages bigger than 2GB
// check the use of https://developer.android.com/reference/java/io/File.html#getFreeSpace%28%29
File internalStorageFile = context.getExternalFilesDir(null);
final File internalStorageFile = context.getExternalFilesDir(null);
if (internalStorageFile != null) {
StatFs internalStorageStat = new StatFs(internalStorageFile.getPath());
device.setStorageSize(getTotalInternalStorage(internalStorageStat));
device.setFreeStorage(getUnusedInternalStorage(internalStorageStat));
}

StatFs externalStorageStat = getExternalStorageStat(internalStorageFile);
final StatFs externalStorageStat = getExternalStorageStat(internalStorageFile);
if (externalStorageStat != null) {
device.setExternalStorageSize(getTotalExternalStorage(externalStorageStat));
device.setExternalFreeStorage(getUnusedExternalStorage(externalStorageStat));
}

DisplayMetrics displayMetrics = getDisplayMetrics();
if (displayMetrics != null) {
device.setScreenWidthPixels(displayMetrics.widthPixels);
device.setScreenHeightPixels(displayMetrics.heightPixels);
device.setScreenDensity(displayMetrics.density);
device.setScreenDpi(displayMetrics.densityDpi);
}

device.setBootTime(getBootTime());

device.setTimezone(getTimeZone());

if (device.getId() == null) {
device.setId(getDeviceId());
}
if (device.getLanguage() == null) {
device.setLanguage(Locale.getDefault().toString()); // eg en_US
}

if (device.getConnectionType() == null) {
// wifi, ethernet or cellular, null if none
device.setConnectionType(
ConnectivityChecker.getConnectionType(context, logger, buildInfoProvider));
}

return device;
}

@SuppressWarnings("ObsoleteSdkInt")
Expand Down Expand Up @@ -959,7 +1000,7 @@ private void setAppPackageInfo(final @NotNull App app, final @NotNull PackageInf
}

@SuppressWarnings("unchecked")
private void setSideLoadedInfo(final @NotNull SentryEvent event) {
private void setSideLoadedInfo(final @NotNull SentryBaseEvent event) {
try {
final Object sideLoadedInfo = contextData.get().get(SIDE_LOADED);

Expand All @@ -973,4 +1014,18 @@ private void setSideLoadedInfo(final @NotNull SentryEvent event) {
logger.log(SentryLevel.ERROR, "Error getting side loaded info.", e);
}
}

@Override
public @NotNull SentryTransaction process(
final @NotNull SentryTransaction transaction, final @Nullable Object hint) {
final boolean applyScopeData = shouldApplyScopeData(transaction, hint);

if (applyScopeData) {
processNonCachedEvent(transaction);
}

setCommons(transaction, false, applyScopeData);

return transaction;
}
}
Loading

0 comments on commit 053a8ab

Please sign in to comment.