Skip to content

Commit bafe650

Browse files
konraddysputKonrad Dysput
andauthored
Metrics performance improvements (#157)
* 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 <konrad.dysput@saucelabs.com>
1 parent 93221d6 commit bafe650

File tree

19 files changed

+481
-210
lines changed

19 files changed

+481
-210
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package backtraceio.library;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import android.content.Context;
6+
import android.content.pm.PackageInfo;
7+
import android.content.pm.PackageManager;
8+
9+
import androidx.test.ext.junit.runners.AndroidJUnit4;
10+
import androidx.test.platform.app.InstrumentationRegistry;
11+
12+
import org.junit.Before;
13+
import org.junit.Test;
14+
import org.junit.runner.RunWith;
15+
16+
import backtraceio.library.common.ApplicationMetadataCache;
17+
18+
@RunWith(AndroidJUnit4.class)
19+
public class ApplicationMetadataTest {
20+
private Context context;
21+
22+
@Before
23+
public void setUp() {
24+
context = InstrumentationRegistry.getInstrumentation().getContext();
25+
// prepare instance
26+
ApplicationMetadataCache.getInstance(context);
27+
}
28+
29+
@Test
30+
public void shouldCorrectlyRetrieveApplicationName() {
31+
ApplicationMetadataCache cache = ApplicationMetadataCache.getInstance(context);
32+
assertEquals(cache.getApplicationName(), context.getOpPackageName());
33+
}
34+
35+
@Test
36+
public void shouldCorrectlyRetrieveApplicationPackageName() {
37+
ApplicationMetadataCache cache = ApplicationMetadataCache.getInstance(context);
38+
assertEquals(cache.getPackageName(), context.getOpPackageName());
39+
}
40+
41+
@Test
42+
public void shouldCorrectlyRetrieveApplicationVersion() throws PackageManager.NameNotFoundException {
43+
ApplicationMetadataCache cache = ApplicationMetadataCache.getInstance(context);
44+
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getOpPackageName(), 0);
45+
assertEquals(cache.getApplicationVersion(), String.valueOf(packageInfo.versionCode));
46+
}
47+
48+
}

backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientUniqueEventTest.java

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -400,48 +400,4 @@ public void uniqueEventUpdateAttributes() {
400400

401401
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
402402
}
403-
404-
@Test
405-
public void uniqueEventEmptyAttributeValueShouldNotOverridePreviousValueOnUpdate() {
406-
backtraceClient.metrics.enable(new BacktraceMetricsSettings(credentials, defaultBaseUrl, 0));
407-
408-
String expectedKey = "foo";
409-
String expectedValue = "bar";
410-
411-
backtraceClient.attributes.put(expectedKey, expectedValue);
412-
assertTrue(backtraceClient.metrics.addUniqueEvent(uniqueAttributeName[0]));
413-
414-
assertEquals(uniqueAttributeName[0], backtraceClient.metrics.getUniqueEvents().getLast().getName());
415-
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
416-
417-
backtraceClient.attributes.put(expectedKey, "");
418-
assertEquals("", backtraceClient.attributes.get(expectedKey));
419-
420-
// Force update
421-
backtraceClient.metrics.send();
422-
423-
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
424-
}
425-
426-
@Test
427-
public void uniqueEventNullAttributeValueShouldNotOverridePreviousValueOnUpdate() {
428-
backtraceClient.metrics.enable(new BacktraceMetricsSettings(credentials, defaultBaseUrl, 0));
429-
430-
String expectedKey = "foo";
431-
String expectedValue = "bar";
432-
433-
backtraceClient.attributes.put(expectedKey, expectedValue);
434-
assertTrue(backtraceClient.metrics.addUniqueEvent(uniqueAttributeName[0]));
435-
436-
assertEquals(uniqueAttributeName[0], backtraceClient.metrics.getUniqueEvents().getLast().getName());
437-
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
438-
439-
backtraceClient.attributes.put(expectedKey, null);
440-
assertNull(backtraceClient.attributes.get(expectedKey));
441-
442-
// Force update
443-
backtraceClient.metrics.send();
444-
445-
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
446-
}
447403
}

backtrace-library/src/androidTest/java/backtraceio/library/metrics/BacktraceMetricsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public void setUp() {
5757
@Test
5858
public void addAttributesSummedEvent() {
5959
SummedEvent summedEvent = new SummedEvent(summedEventName, null);
60-
Map<String, Object> attributes = new HashMap<String, Object>() {{
60+
Map<String, String> attributes = new HashMap<String, String>() {{
6161
put("foo", "bar");
6262
}};
6363
summedEvent.addAttributes(attributes);
@@ -67,7 +67,7 @@ public void addAttributesSummedEvent() {
6767
@Test
6868
public void addAttributesUniqueEvent() {
6969
UniqueEvent uniqueEvent = new UniqueEvent(uniqueAttributeName[0], null);
70-
Map<String, Object> attributes = new HashMap<String, Object>() {{
70+
Map<String, String> attributes = new HashMap<String, String>() {{
7171
put("foo", "bar");
7272
}};
7373
uniqueEvent.update(BacktraceTimeHelper.getTimestampSeconds(), attributes);
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package backtraceio.library.common;
2+
3+
import android.content.Context;
4+
import android.content.pm.PackageInfo;
5+
import android.content.pm.PackageManager;
6+
7+
import backtraceio.library.logger.BacktraceLogger;
8+
9+
public class ApplicationMetadataCache {
10+
11+
private static final transient String LOG_TAG = ApplicationMetadataCache.class.getSimpleName();
12+
13+
private static volatile ApplicationMetadataCache instance;
14+
15+
/**
16+
* Cached application name
17+
*/
18+
private String applicationName;
19+
20+
/**
21+
* Cached application version
22+
*/
23+
private String applicationVersion;
24+
25+
/**
26+
* Cached package name
27+
*/
28+
private String packageName;
29+
30+
private final Context context;
31+
32+
private ApplicationMetadataCache(Context context) {
33+
this.context = context;
34+
}
35+
36+
/**
37+
* Returns current application cache. This instance is a singleton since we can only operate
38+
* in a single application scope.
39+
*
40+
* @param context Application context
41+
* @return Application metadata cache
42+
*/
43+
public static ApplicationMetadataCache getInstance(Context context) {
44+
if (instance == null) {
45+
synchronized (ApplicationMetadataCache.class) {
46+
if (instance == null) {
47+
instance = new ApplicationMetadataCache(context);
48+
}
49+
}
50+
}
51+
return instance;
52+
}
53+
54+
/**
55+
* Retrieves application name from context. The name will be cached over checks
56+
*
57+
* @return application name
58+
*/
59+
public String getApplicationName() {
60+
if (!BacktraceStringHelper.isNullOrEmpty(applicationName)) {
61+
return applicationName;
62+
}
63+
64+
applicationName = context.getApplicationInfo().loadLabel(context.getPackageManager()).toString();
65+
return applicationName;
66+
}
67+
68+
/**
69+
* Retrieves application version from the context. If the version name is not defined, the version code will be used instead.
70+
*
71+
* @return current application version.
72+
*/
73+
public String getApplicationVersion() {
74+
if (!BacktraceStringHelper.isNullOrEmpty(applicationVersion)) {
75+
return applicationVersion;
76+
}
77+
try {
78+
PackageInfo info = context.getPackageManager()
79+
.getPackageInfo(context.getPackageName(), 0);
80+
applicationVersion = BacktraceStringHelper.isNullOrEmpty(info.versionName) ? String.valueOf(info.versionCode) : info.versionName;
81+
82+
return applicationVersion;
83+
} catch (PackageManager.NameNotFoundException e) {
84+
BacktraceLogger.e(LOG_TAG, "Could not resolve application version", e);
85+
return "";
86+
}
87+
}
88+
89+
/**
90+
* Retrieves package name from the context.
91+
*
92+
* @return current package name.
93+
*/
94+
public String getPackageName() {
95+
if (!BacktraceStringHelper.isNullOrEmpty(packageName)) {
96+
return packageName;
97+
}
98+
packageName = context.getApplicationContext().getPackageName();
99+
100+
return packageName;
101+
}
102+
}

backtrace-library/src/main/java/backtraceio/library/common/DeviceAttributesHelper.java

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import android.text.TextUtils;
2020

2121
import java.io.BufferedReader;
22-
import java.io.InputStreamReader;
22+
import java.io.FileReader;
2323
import java.util.HashMap;
2424
import java.util.UUID;
2525

@@ -36,6 +36,11 @@
3636
public class DeviceAttributesHelper {
3737
private final Context context;
3838

39+
/*
40+
* Current Device id
41+
*/
42+
private static String uuid;
43+
3944
public DeviceAttributesHelper(Context context) {
4045
this.context = context;
4146
}
@@ -61,15 +66,17 @@ public HashMap<String, String> getDeviceAttributes(Boolean includeDynamicAttribu
6166
result.put("device.cpu.temperature", String.valueOf(getCpuTemperature()));
6267
result.put("device.is_power_saving_mode", String.valueOf(isPowerSavingMode()));
6368
result.put("device.wifi.status", getWifiStatus().toString());
64-
result.put("system.memory.total", getMaxRamSize());
65-
result.put("system.memory.free", getDeviceFreeRam());
66-
result.put("system.memory.active", getDeviceActiveRam());
6769
result.put("app.storage_used", getAppUsedStorageSize());
6870
result.put("battery.level", String.valueOf(getBatteryLevel()));
6971
result.put("battery.state", getBatteryState().toString());
7072
result.put("cpu.boottime", String.valueOf(java.lang.System.currentTimeMillis() - android.os.SystemClock
7173
.elapsedRealtime()));
7274

75+
76+
ActivityManager.MemoryInfo memoryInfo = getMemoryInformation();
77+
result.put("system.memory.total", Long.toString(memoryInfo.totalMem));
78+
result.put("system.memory.free", Long.toString(memoryInfo.availMem));
79+
result.put("system.memory.active", Long.toString(memoryInfo.totalMem - memoryInfo.availMem));
7380
return result;
7481
}
7582

@@ -144,14 +151,14 @@ private BluetoothStatus isBluetoothEnabled() {
144151
private float getCpuTemperature() {
145152
Process p;
146153
try {
147-
p = Runtime.getRuntime().exec("cat sys/class/thermal/thermal_zone0/temp");
148-
p.waitFor();
149-
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
150154

155+
BufferedReader reader = new BufferedReader(new FileReader("/sys/class/thermal/thermal_zone0/temp"));
151156
String line = reader.readLine();
152157
if (line == null) {
153158
return 0.0f;
154159
}
160+
reader.close();
161+
155162
return Float.parseFloat(line) / 1000.0f;
156163
} catch (Exception e) {
157164
return 0.0f;
@@ -255,33 +262,20 @@ private BatteryState getBatteryState() {
255262
* @return unique device identifier
256263
*/
257264
private String generateDeviceId() {
258-
String androidId = Settings.Secure.getString(this.context.getContentResolver(),
259-
Settings.Secure.ANDROID_ID);
260-
261-
if (TextUtils.isEmpty(androidId)) {
262-
return null;
265+
if (!BacktraceStringHelper.isNullOrEmpty(uuid)) {
266+
return uuid;
263267
}
264268

265-
return UUID.nameUUIDFromBytes(androidId.getBytes()).toString();
266-
}
267-
268-
/**
269-
* Get RAM size of current device
270-
* available from API 16
271-
*
272-
* @return device RAM size
273-
*/
274-
private String getMaxRamSize() {
275-
return Long.toString(getMemoryInformation().totalMem);
276-
}
269+
String androidId = Settings.Secure.getString(this.context.getContentResolver(),
270+
Settings.Secure.ANDROID_ID);
277271

278-
private String getDeviceFreeRam() {
279-
return Long.toString(getMemoryInformation().availMem);
280-
}
272+
// if the android id is not defined we want to cache at least guid
273+
// for the current session
274+
uuid = TextUtils.isEmpty(androidId)
275+
? UUID.randomUUID().toString()
276+
: UUID.nameUUIDFromBytes(androidId.getBytes()).toString();
281277

282-
private String getDeviceActiveRam() {
283-
ActivityManager.MemoryInfo mi = getMemoryInformation();
284-
return Long.toString(mi.totalMem - mi.availMem);
278+
return uuid;
285279
}
286280

287281
private ActivityManager.MemoryInfo getMemoryInformation() {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package backtraceio.library.models.attributes;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
public class ReportDataAttributes {
7+
private final Map<String, String> reportAttributes = new HashMap<>();
8+
9+
private final Map<String, Object> reportAnnotations = new HashMap<>();
10+
11+
12+
public void addAnnotation(String key, Object value) {
13+
reportAnnotations.put(key, value);
14+
}
15+
16+
public void addAttribute(String key, String value) {
17+
reportAttributes.put(key, value);
18+
}
19+
20+
public Map<String, String> getAttributes() {
21+
return reportAttributes;
22+
}
23+
24+
public Map<String, Object> getAnnotations() {
25+
return reportAnnotations;
26+
}
27+
}

0 commit comments

Comments
 (0)