Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metrics performance improvements #157

Merged
merged 16 commits into from
Nov 13, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,68 @@

import backtraceio.library.logger.BacktraceLogger;

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

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

private static ApplicationMetadataCache instance;

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

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

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

/**
* 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) {
BartoszLitwiniuk marked this conversation as resolved.
Show resolved Hide resolved
if (instance == null) {
instance = new ApplicationMetadataCache(context);
}
return instance;
perf2711 marked this conversation as resolved.
Show resolved Hide resolved
}
perf2711 marked this conversation as resolved.
Show resolved Hide resolved

private final Context context;

public ApplicationMetadataCache(Context context) {
konraddysput marked this conversation as resolved.
Show resolved Hide resolved
this.context = context;
}

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

applicationName = context.getApplicationInfo().loadLabel(context.getPackageManager()).toString();
BartoszLitwiniuk marked this conversation as resolved.
Show resolved Hide resolved
return applicationName;
return applicationName;
}

/**
* Retrieves application version from the context. If the version name is not defined, the version code will be used instead.
* @param context application context
*
* @return current application version.
*/
public static String getApplicationVersion(Context context) {
if(!BacktraceStringHelper.isNullOrEmpty(applicationVersion)) {
public String getApplicationVersion() {
if (!BacktraceStringHelper.isNullOrEmpty(applicationVersion)) {
return applicationVersion;
}
try {
Expand All @@ -60,11 +84,11 @@ public static String getApplicationVersion(Context context) {

/**
* Retrieves package name from the context.
* @param context application context
*
* @return current package name.
*/
public static String getPackageName(Context context) {
if(!BacktraceStringHelper.isNullOrEmpty(packageName)) {
public String getPackageName() {
if (!BacktraceStringHelper.isNullOrEmpty(packageName)) {
return packageName;
}
packageName = context.getApplicationContext().getPackageName();
BartoszLitwiniuk marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class DeviceAttributesHelper {
/*
* Current Device id
*/
private static String guid;
private static String uuid;

public DeviceAttributesHelper(Context context) {
this.context = context;
Expand Down Expand Up @@ -262,20 +262,20 @@ private BatteryState getBatteryState() {
* @return unique device identifier
*/
private String generateDeviceId() {
if (!BacktraceStringHelper.isNullOrEmpty(guid)) {
return guid;
if (!BacktraceStringHelper.isNullOrEmpty(uuid)) {
return uuid;
}

String androidId = Settings.Secure.getString(this.context.getContentResolver(),
Settings.Secure.ANDROID_ID);

// if the android id is not defined we want to cache at least guid
BartoszLitwiniuk marked this conversation as resolved.
Show resolved Hide resolved
// for the current session
guid = TextUtils.isEmpty(androidId)
uuid = TextUtils.isEmpty(androidId)
? UUID.randomUUID().toString()
: UUID.nameUUIDFromBytes(androidId.getBytes()).toString();

return guid;
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;

public class ReportDataAttributes {
private final HashMap<String, String> reportAttributes = new HashMap<>();
konraddysput marked this conversation as resolved.
Show resolved Hide resolved

private final HashMap<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 HashMap<String, String> getAttributes() {
return reportAttributes;
}

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

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package backtraceio.library.models.attributes;

import java.util.Map;

import backtraceio.library.common.TypeHelper;

public class ReportDataBuilder {

/**
* Divide custom user attributes into primitive and complex attributes and add to this object. By default nullable values will be included.
*
* @param attributes client's attributes
* @return Report data attributes divided into attributes and annotations
*/
public static ReportDataAttributes getReportAttributes(Map<String, Object> attributes) {
return getReportAttributes(attributes, false);
}

/**
* Divide custom user attributes into primitive and complex attributes and add to this object
*
* @param attributes client's attributes
* @param skipNullable define attributes behavior on nullable value. By default all nullable attributes
* will be included in the report. For some features like metrics, we don't want to send
* nullable values, because they can generate invalid behavior/incorrect information.
* @return Report data attributes divided into attributes and annotations
*/
public static ReportDataAttributes getReportAttributes(Map<String, Object> attributes, boolean skipNullable) {
perf2711 marked this conversation as resolved.
Show resolved Hide resolved
ReportDataAttributes reportDataAttributes = new ReportDataAttributes();

if (attributes == null) {
return reportDataAttributes;
}

for (Map.Entry<String, Object> entry : attributes.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value == null) {
if (!skipNullable) {
reportDataAttributes.addAttribute(key, null);
}
continue;
}
if (TypeHelper.isPrimitiveOrPrimitiveWrapperOrString(value.getClass())) {
reportDataAttributes.addAttribute(key, value.toString());
} else {
reportDataAttributes.addAnnotation(key, value);
}
}

return reportDataAttributes;

konraddysput marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package backtraceio.library.models.json;

import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Build;
import android.provider.Settings;
Expand All @@ -15,11 +14,12 @@
import java.util.UUID;

import backtraceio.library.BacktraceClient;
import backtraceio.library.common.ApplicationHelper;
import backtraceio.library.common.ApplicationMetadataCache;
import backtraceio.library.common.BacktraceStringHelper;
import backtraceio.library.common.DeviceAttributesHelper;
import backtraceio.library.enums.ScreenOrientation;
import backtraceio.library.models.Tuple;
import backtraceio.library.models.attributes.ReportDataAttributes;
import backtraceio.library.models.attributes.ReportDataBuilder;

/**
* Class instance to get a built-in attributes from current application
Expand Down Expand Up @@ -103,9 +103,10 @@ private void setDeviceInformation(Boolean includeDynamicAttributes) {
}

private void setAppInformation() {
this.attributes.put("application.package", ApplicationHelper.getPackageName(this.context));
this.attributes.put("application", ApplicationHelper.getApplicationName(this.context));
String version = ApplicationHelper.getApplicationVersion(this.context);
ApplicationMetadataCache applicationMetadata = ApplicationMetadataCache.getInstance(this.context);
this.attributes.put("application.package", applicationMetadata.getPackageName());
this.attributes.put("application", applicationMetadata.getApplicationName());
String version = applicationMetadata.getApplicationVersion();
if (!BacktraceStringHelper.isNullOrEmpty(version)) {
// We want to standardize application.version attribute name
this.attributes.put("application.version", version);
Expand Down Expand Up @@ -204,9 +205,9 @@ private void convertReportAttributes(BacktraceReport report) {
}

private void convertAttributes(Map<String, Object> clientAttributes) {
Tuple<Map<String, String>, Map<String, Object>> reportData = ReportDataBuilder.getReportAttribues(clientAttributes);
this.attributes.putAll(reportData.first);
this.complexAttributes.putAll(reportData.second);
ReportDataAttributes data = ReportDataBuilder.getReportAttributes(clientAttributes);
this.attributes.putAll(data.getAttributes());
this.complexAttributes.putAll(data.getAnnotations());
}


Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@

import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedDeque;

import backtraceio.library.BacktraceCredentials;
import backtraceio.library.common.ApplicationHelper;
import backtraceio.library.common.ApplicationMetadataCache;
import backtraceio.library.common.BacktraceStringHelper;
import backtraceio.library.common.BacktraceTimeHelper;
import backtraceio.library.common.serialization.DebugHelper;
import backtraceio.library.events.EventsOnServerResponseEventListener;
import backtraceio.library.events.EventsRequestHandler;
import backtraceio.library.interfaces.Api;
import backtraceio.library.interfaces.Metrics;
import backtraceio.library.logger.BacktraceLogger;
import backtraceio.library.models.BacktraceMetricsSettings;
import backtraceio.library.models.json.BacktraceAttributes;
import backtraceio.library.models.json.ReportDataBuilder;
import backtraceio.library.models.attributes.ReportDataBuilder;
import backtraceio.library.models.metrics.SummedEvent;
import backtraceio.library.models.metrics.UniqueEvent;

Expand Down Expand Up @@ -182,17 +182,24 @@ public void enable(BacktraceMetricsSettings settings, String uniqueEventName) {
throw new IllegalArgumentException("Unique event name must be defined!");
}

this.applicationName = ApplicationHelper.getApplicationName(this.getContext());
this.applicationVersion = ApplicationHelper.getApplicationVersion(this.getContext());
ApplicationMetadataCache applicationMetadata = ApplicationMetadataCache.getInstance(this.getContext());
this.applicationName = applicationMetadata.getApplicationName();
this.applicationVersion = applicationMetadata.getApplicationVersion();
setStartupUniqueEventName(uniqueEventName);
perf2711 marked this conversation as resolved.
Show resolved Hide resolved
final long startMetricsSetup = DebugHelper.getCurrentTimeMillis();

setStartupUniqueEventName(uniqueEventName);
this.settings = settings;
this.enabled = true;
try {
startMetricsEventHandlers(backtraceApi);
sendStartupEvent();
BacktraceLogger.d(LOG_TAG, "Metrics enabled");
} catch (Exception e) {
BacktraceLogger.e(LOG_TAG, "Could not enable metrics, exception " + e.getMessage());
}
final long endMetricsSetup = DebugHelper.getCurrentTimeMillis();
BacktraceLogger.d(LOG_TAG, "Setup metrics integration took " + (endMetricsSetup - startMetricsSetup) + " milliseconds");
}

/**
Expand All @@ -202,7 +209,7 @@ public void enable(BacktraceMetricsSettings settings, String uniqueEventName) {
* Due to that, we need to have a getter that will always transform attributes to a simple format.
*/
private Map<String, String> getClientMetricsAttributes() {
return ReportDataBuilder.getReportAttribues(customReportAttributes).first;
return ReportDataBuilder.getReportAttributes(customReportAttributes, true).getAttributes();
}


Expand Down Expand Up @@ -272,7 +279,7 @@ public boolean addUniqueEvent(String attributeName, Map<String, Object> attribut
return false;
}

Map<String, String> metricsAttributes = ReportDataBuilder.getReportAttribues(attributes).first;
Map<String, String> metricsAttributes = ReportDataBuilder.getReportAttributes(attributes, true).getAttributes();
perf2711 marked this conversation as resolved.
Show resolved Hide resolved

Map<String, String> localAttributes = createLocalAttributes(metricsAttributes);

Expand Down Expand Up @@ -349,7 +356,7 @@ public boolean addSummedEvent(String metricGroupName, Map<String, Object> attrib
return false;
}

Map<String, String> metricsAttributes = ReportDataBuilder.getReportAttribues(attributes).first;
Map<String, String> metricsAttributes = ReportDataBuilder.getReportAttributes(attributes, true).getAttributes();

SummedEvent summedEvent = new SummedEvent(metricGroupName);
summedEvent.addAttributes(metricsAttributes);
Expand Down
Loading
Loading