Skip to content

Commit

Permalink
Metrics performance improvements (#157)
Browse files Browse the repository at this point in the history
* Metrics speedup

* Optimize attributes conversions

* Add end of line to Tuple

* Attributes getter and remove old not valid tests

* Optimize attributes

* Remove debugging information and format file

* Rollback MainActivity

* Reformat file. Bring previous metrics logic

* Report data builder tests

* Move application cache to singleton

* SkipNul, remove additional unique event and make application cache thread safe

* Application metadata cache test

* Update ReportDataBuilder.java

* Pull request updates: private constructor, move singleton method, format files, remove tuple

* Simplify BacktraceAttributes business logic

---------

Co-authored-by: Konrad Dysput <[email protected]>
  • Loading branch information
konraddysput and Konrad Dysput authored Nov 13, 2024
1 parent 93221d6 commit bafe650
Show file tree
Hide file tree
Showing 19 changed files with 481 additions and 210 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package backtraceio.library;

import static org.junit.Assert.assertEquals;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import backtraceio.library.common.ApplicationMetadataCache;

@RunWith(AndroidJUnit4.class)
public class ApplicationMetadataTest {
private Context context;

@Before
public void setUp() {
context = InstrumentationRegistry.getInstrumentation().getContext();
// prepare instance
ApplicationMetadataCache.getInstance(context);
}

@Test
public void shouldCorrectlyRetrieveApplicationName() {
ApplicationMetadataCache cache = ApplicationMetadataCache.getInstance(context);
assertEquals(cache.getApplicationName(), context.getOpPackageName());
}

@Test
public void shouldCorrectlyRetrieveApplicationPackageName() {
ApplicationMetadataCache cache = ApplicationMetadataCache.getInstance(context);
assertEquals(cache.getPackageName(), context.getOpPackageName());
}

@Test
public void shouldCorrectlyRetrieveApplicationVersion() throws PackageManager.NameNotFoundException {
ApplicationMetadataCache cache = ApplicationMetadataCache.getInstance(context);
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getOpPackageName(), 0);
assertEquals(cache.getApplicationVersion(), String.valueOf(packageInfo.versionCode));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -400,48 +400,4 @@ public void uniqueEventUpdateAttributes() {

assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
}

@Test
public void uniqueEventEmptyAttributeValueShouldNotOverridePreviousValueOnUpdate() {
backtraceClient.metrics.enable(new BacktraceMetricsSettings(credentials, defaultBaseUrl, 0));

String expectedKey = "foo";
String expectedValue = "bar";

backtraceClient.attributes.put(expectedKey, expectedValue);
assertTrue(backtraceClient.metrics.addUniqueEvent(uniqueAttributeName[0]));

assertEquals(uniqueAttributeName[0], backtraceClient.metrics.getUniqueEvents().getLast().getName());
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));

backtraceClient.attributes.put(expectedKey, "");
assertEquals("", backtraceClient.attributes.get(expectedKey));

// Force update
backtraceClient.metrics.send();

assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
}

@Test
public void uniqueEventNullAttributeValueShouldNotOverridePreviousValueOnUpdate() {
backtraceClient.metrics.enable(new BacktraceMetricsSettings(credentials, defaultBaseUrl, 0));

String expectedKey = "foo";
String expectedValue = "bar";

backtraceClient.attributes.put(expectedKey, expectedValue);
assertTrue(backtraceClient.metrics.addUniqueEvent(uniqueAttributeName[0]));

assertEquals(uniqueAttributeName[0], backtraceClient.metrics.getUniqueEvents().getLast().getName());
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));

backtraceClient.attributes.put(expectedKey, null);
assertNull(backtraceClient.attributes.get(expectedKey));

// Force update
backtraceClient.metrics.send();

assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void setUp() {
@Test
public void addAttributesSummedEvent() {
SummedEvent summedEvent = new SummedEvent(summedEventName, null);
Map<String, Object> attributes = new HashMap<String, Object>() {{
Map<String, String> attributes = new HashMap<String, String>() {{
put("foo", "bar");
}};
summedEvent.addAttributes(attributes);
Expand All @@ -67,7 +67,7 @@ public void addAttributesSummedEvent() {
@Test
public void addAttributesUniqueEvent() {
UniqueEvent uniqueEvent = new UniqueEvent(uniqueAttributeName[0], null);
Map<String, Object> attributes = new HashMap<String, Object>() {{
Map<String, String> attributes = new HashMap<String, String>() {{
put("foo", "bar");
}};
uniqueEvent.update(BacktraceTimeHelper.getTimestampSeconds(), attributes);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package backtraceio.library.common;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;

import backtraceio.library.logger.BacktraceLogger;

public class ApplicationMetadataCache {

private static final transient String LOG_TAG = ApplicationMetadataCache.class.getSimpleName();

private static volatile ApplicationMetadataCache instance;

/**
* Cached application name
*/
private String applicationName;

/**
* Cached application version
*/
private String applicationVersion;

/**
* Cached package name
*/
private String packageName;

private final Context context;

private ApplicationMetadataCache(Context context) {
this.context = context;
}

/**
* Returns current application cache. This instance is a singleton since we can only operate
* in a single application scope.
*
* @param context Application context
* @return Application metadata cache
*/
public static ApplicationMetadataCache getInstance(Context context) {
if (instance == null) {
synchronized (ApplicationMetadataCache.class) {
if (instance == null) {
instance = new ApplicationMetadataCache(context);
}
}
}
return instance;
}

/**
* Retrieves application name from context. The name will be cached over checks
*
* @return application name
*/
public String getApplicationName() {
if (!BacktraceStringHelper.isNullOrEmpty(applicationName)) {
return applicationName;
}

applicationName = context.getApplicationInfo().loadLabel(context.getPackageManager()).toString();
return applicationName;
}

/**
* Retrieves application version from the context. If the version name is not defined, the version code will be used instead.
*
* @return current application version.
*/
public String getApplicationVersion() {
if (!BacktraceStringHelper.isNullOrEmpty(applicationVersion)) {
return applicationVersion;
}
try {
PackageInfo info = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
applicationVersion = BacktraceStringHelper.isNullOrEmpty(info.versionName) ? String.valueOf(info.versionCode) : info.versionName;

return applicationVersion;
} catch (PackageManager.NameNotFoundException e) {
BacktraceLogger.e(LOG_TAG, "Could not resolve application version", e);
return "";
}
}

/**
* Retrieves package name from the context.
*
* @return current package name.
*/
public String getPackageName() {
if (!BacktraceStringHelper.isNullOrEmpty(packageName)) {
return packageName;
}
packageName = context.getApplicationContext().getPackageName();

return packageName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import android.text.TextUtils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileReader;
import java.util.HashMap;
import java.util.UUID;

Expand All @@ -36,6 +36,11 @@
public class DeviceAttributesHelper {
private final Context context;

/*
* Current Device id
*/
private static String uuid;

public DeviceAttributesHelper(Context context) {
this.context = context;
}
Expand All @@ -61,15 +66,17 @@ public HashMap<String, String> getDeviceAttributes(Boolean includeDynamicAttribu
result.put("device.cpu.temperature", String.valueOf(getCpuTemperature()));
result.put("device.is_power_saving_mode", String.valueOf(isPowerSavingMode()));
result.put("device.wifi.status", getWifiStatus().toString());
result.put("system.memory.total", getMaxRamSize());
result.put("system.memory.free", getDeviceFreeRam());
result.put("system.memory.active", getDeviceActiveRam());
result.put("app.storage_used", getAppUsedStorageSize());
result.put("battery.level", String.valueOf(getBatteryLevel()));
result.put("battery.state", getBatteryState().toString());
result.put("cpu.boottime", String.valueOf(java.lang.System.currentTimeMillis() - android.os.SystemClock
.elapsedRealtime()));


ActivityManager.MemoryInfo memoryInfo = getMemoryInformation();
result.put("system.memory.total", Long.toString(memoryInfo.totalMem));
result.put("system.memory.free", Long.toString(memoryInfo.availMem));
result.put("system.memory.active", Long.toString(memoryInfo.totalMem - memoryInfo.availMem));
return result;
}

Expand Down Expand Up @@ -144,14 +151,14 @@ private BluetoothStatus isBluetoothEnabled() {
private float getCpuTemperature() {
Process p;
try {
p = Runtime.getRuntime().exec("cat sys/class/thermal/thermal_zone0/temp");
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

BufferedReader reader = new BufferedReader(new FileReader("/sys/class/thermal/thermal_zone0/temp"));
String line = reader.readLine();
if (line == null) {
return 0.0f;
}
reader.close();

return Float.parseFloat(line) / 1000.0f;
} catch (Exception e) {
return 0.0f;
Expand Down Expand Up @@ -255,33 +262,20 @@ private BatteryState getBatteryState() {
* @return unique device identifier
*/
private String generateDeviceId() {
String androidId = Settings.Secure.getString(this.context.getContentResolver(),
Settings.Secure.ANDROID_ID);

if (TextUtils.isEmpty(androidId)) {
return null;
if (!BacktraceStringHelper.isNullOrEmpty(uuid)) {
return uuid;
}

return UUID.nameUUIDFromBytes(androidId.getBytes()).toString();
}

/**
* Get RAM size of current device
* available from API 16
*
* @return device RAM size
*/
private String getMaxRamSize() {
return Long.toString(getMemoryInformation().totalMem);
}
String androidId = Settings.Secure.getString(this.context.getContentResolver(),
Settings.Secure.ANDROID_ID);

private String getDeviceFreeRam() {
return Long.toString(getMemoryInformation().availMem);
}
// if the android id is not defined we want to cache at least guid
// for the current session
uuid = TextUtils.isEmpty(androidId)
? UUID.randomUUID().toString()
: UUID.nameUUIDFromBytes(androidId.getBytes()).toString();

private String getDeviceActiveRam() {
ActivityManager.MemoryInfo mi = getMemoryInformation();
return Long.toString(mi.totalMem - mi.availMem);
return uuid;
}

private ActivityManager.MemoryInfo getMemoryInformation() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package backtraceio.library.models.attributes;

import java.util.HashMap;
import java.util.Map;

public class ReportDataAttributes {
private final Map<String, String> reportAttributes = new HashMap<>();

private final Map<String, Object> reportAnnotations = new HashMap<>();


public void addAnnotation(String key, Object value) {
reportAnnotations.put(key, value);
}

public void addAttribute(String key, String value) {
reportAttributes.put(key, value);
}

public Map<String, String> getAttributes() {
return reportAttributes;
}

public Map<String, Object> getAnnotations() {
return reportAnnotations;
}
}
Loading

0 comments on commit bafe650

Please sign in to comment.