From a0d455a18a836d52f947cfeb16c85bfed2023cf7 Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Mon, 28 Oct 2024 16:22:30 +0100 Subject: [PATCH 01/15] Metrics speedup --- .../services/BacktraceEventsHandler.java | 26 +++++-------------- .../library/services/BacktraceMetrics.java | 24 ++++++++++++++--- .../library/services/SummedEventsHandler.java | 12 +++------ .../library/services/UniqueEventsHandler.java | 2 ++ .../backtraceio/backtraceio/MainActivity.java | 6 ++++- 5 files changed, 37 insertions(+), 33 deletions(-) diff --git a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceEventsHandler.java b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceEventsHandler.java index 50e6ff60..6d0ad44d 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceEventsHandler.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceEventsHandler.java @@ -10,7 +10,6 @@ import backtraceio.library.common.BacktraceSerializeHelper; import backtraceio.library.interfaces.Api; import backtraceio.library.logger.BacktraceLogger; -import backtraceio.library.models.json.BacktraceAttributes; import backtraceio.library.models.metrics.Event; import backtraceio.library.models.metrics.EventsPayload; import backtraceio.library.models.metrics.EventsResult; @@ -52,22 +51,13 @@ abstract class BacktraceEventsHandler extends Handler { */ private int maximumNumberOfEvents = 350; - /** - * The application name - */ - protected String application; - - /** - * The application version - */ - protected String appVersion; - /** * Create BacktraceEventsHandler instance - * @param backtraceMetrics Backtrace metrics object - * @param api Backtrace API object - * @param backtraceHandlerThread Backtrace handler thread object - * @param urlPrefix Url routing prefix for metrics + * + * @param backtraceMetrics Backtrace metrics object + * @param api Backtrace API object + * @param backtraceHandlerThread Backtrace handler thread object + * @param urlPrefix Url routing prefix for metrics */ public BacktraceEventsHandler(BacktraceMetrics backtraceMetrics, Api api, @@ -89,11 +79,7 @@ public BacktraceEventsHandler(BacktraceMetrics backtraceMetrics, this.timeBetweenRetriesMillis = backtraceMetrics.settings.getTimeBetweenRetriesMillis(); long timeIntervalMillis = backtraceMetrics.settings.getTimeIntervalMillis(); - - BacktraceAttributes backtraceAttributes = new BacktraceAttributes(backtraceMetrics.getContext(), null, null); - this.application = backtraceAttributes.getApplicationName(); - this.appVersion = backtraceAttributes.getApplicationVersionOrEmpty(); - + if (timeIntervalMillis != 0) { final BacktraceEventsHandler handler = this; handler.postDelayed(new Runnable() { diff --git a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java index 82dbf461..2bbbad20 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java @@ -170,20 +170,26 @@ public void enable(BacktraceMetricsSettings settings, String uniqueEventName) { if (uniqueEventName == null || uniqueEventName.length() == 0) { throw new IllegalArgumentException("Unique event name must be defined!"); } - final long startMetricsSetup = DebugHelper.getCurrentTimeMillis(); + long startExeuction = DebugHelper.getCurrentTimeMillis(); setStartupUniqueEventName(uniqueEventName); this.settings = settings; this.enabled = true; + long startMetricsSetup = DebugHelper.getCurrentTimeMillis(); try { startMetricsEventHandlers(backtraceApi); + + BacktraceLogger.w(LOG_TAG, "ENABLE: startMetricsEventHandlers took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); + startMetricsSetup = DebugHelper.getCurrentTimeMillis(); + sendStartupEvent(); + + BacktraceLogger.w(LOG_TAG, "ENABLE: sendStartupEvent took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); 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"); + BacktraceLogger.w(LOG_TAG, "TOTAL: Setup metrics integration took " + (DebugHelper.getCurrentTimeMillis() - startExeuction) + " milliseconds"); } private void verifyIfMetricsAvailable() { @@ -194,8 +200,13 @@ private void verifyIfMetricsAvailable() { private void startMetricsEventHandlers(Api backtraceApi) { verifyIfMetricsAvailable(); + long startMetricsSetup = DebugHelper.getCurrentTimeMillis(); uniqueEventsHandler = backtraceApi.enableUniqueEvents(this); + + BacktraceLogger.w(LOG_TAG, "startMetricsEventHandlers: uniqueEventsHandler took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); + startMetricsSetup = DebugHelper.getCurrentTimeMillis(); summedEventsHandler = backtraceApi.enableSummedEvents(this); + BacktraceLogger.w(LOG_TAG, "startMetricsEventHandlers: enableSummedEvents took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); } public void setStartupUniqueEventName(String startupUniqueEventName) { @@ -211,10 +222,17 @@ public String getBaseUrl() { */ public void sendStartupEvent() { verifyIfMetricsAvailable(); + long startMetricsSetup = DebugHelper.getCurrentTimeMillis(); addUniqueEvent(startupUniqueEventName); addSummedEvent(startupSummedEventName); + BacktraceLogger.w(LOG_TAG, "sendStartupEvent: adding elements took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); + startMetricsSetup = DebugHelper.getCurrentTimeMillis(); uniqueEventsHandler.send(); + BacktraceLogger.w(LOG_TAG, "sendStartupEvent: sending uniqueEventsHandler took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); + startMetricsSetup = DebugHelper.getCurrentTimeMillis(); summedEventsHandler.send(); + + BacktraceLogger.w(LOG_TAG, "sendStartupEvent: sending summedEventsHandler took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); } /** diff --git a/backtrace-library/src/main/java/backtraceio/library/services/SummedEventsHandler.java b/backtrace-library/src/main/java/backtraceio/library/services/SummedEventsHandler.java index 14206828..fa936d5a 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/SummedEventsHandler.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/SummedEventsHandler.java @@ -22,17 +22,11 @@ public SummedEventsHandler(BacktraceMetrics backtraceMetrics, @Override protected SummedEventsPayload getEventsPayload() { Map attributes = backtraceMetrics.createLocalAttributes(null); + String application = attributes.get("application").toString(); + String appVersion = attributes.get("application.version").toString(); - ConcurrentLinkedDeque eventsCopy = new ConcurrentLinkedDeque<>(); - - for (SummedEvent event : events) { - event.addAttributes(attributes); - eventsCopy.addLast(new SummedEvent((SummedEvent) event)); - } + SummedEventsPayload payload = new SummedEventsPayload(events, application, appVersion); events.clear(); - - SummedEventsPayload payload = new SummedEventsPayload(eventsCopy, application, appVersion); - return payload; } diff --git a/backtrace-library/src/main/java/backtraceio/library/services/UniqueEventsHandler.java b/backtrace-library/src/main/java/backtraceio/library/services/UniqueEventsHandler.java index 96d12846..b6b6e5d3 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/UniqueEventsHandler.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/UniqueEventsHandler.java @@ -23,6 +23,8 @@ public UniqueEventsHandler(BacktraceMetrics backtraceMetrics, @Override protected UniqueEventsPayload getEventsPayload() { Map attributes = backtraceMetrics.createLocalAttributes(null); + String application = attributes.get("application").toString(); + String appVersion = attributes.get("application.version").toString(); for (UniqueEvent event : events) { event.update(BacktraceTimeHelper.getTimestampSeconds(), attributes); diff --git a/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java b/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java index f0c3f1cb..9d2618ae 100644 --- a/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java +++ b/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java @@ -29,6 +29,8 @@ import backtraceio.library.enums.database.RetryBehavior; import backtraceio.library.enums.database.RetryOrder; import backtraceio.library.events.OnServerResponseEventListener; +import backtraceio.library.logger.BacktraceLogger; +import backtraceio.library.logger.LogLevel; import backtraceio.library.models.BacktraceExceptionHandler; import backtraceio.library.models.database.BacktraceDatabaseSettings; import backtraceio.library.models.json.BacktraceReport; @@ -51,7 +53,7 @@ public void setOnServerResponseEventListener(OnServerResponseEventListener e) { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - + backtraceClient = initializeBacktrace(BuildConfig.BACKTRACE_SUBMISSION_URL); symlinkAndWriteFile(); @@ -76,6 +78,8 @@ private void symlinkAndWriteFile() { private BacktraceClient initializeBacktrace(final String submissionUrl) { BacktraceCredentials credentials = new BacktraceCredentials(submissionUrl); + + BacktraceLogger.setLevel(LogLevel.DEBUG); Context context = getApplicationContext(); String dbPath = context.getFilesDir().getAbsolutePath(); From 2dca999a7d9d00d096fef7d7401e46f6d9758969 Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Mon, 4 Nov 2024 13:11:32 +0100 Subject: [PATCH 02/15] Optimize attributes conversions --- .../library/metrics/BacktraceMetricsTest.java | 4 +- .../library/common/ApplicationHelper.java | 51 ++++++++++++++++ .../backtraceio/library/models/Tuple.java | 11 ++++ .../models/json/BacktraceAttributes.java | 52 +++------------- .../models/json/ReportDataBuilder.java | 40 ++++++++++++ .../library/models/metrics/Event.java | 27 +++----- .../library/models/metrics/EventsPayload.java | 8 +++ .../library/models/metrics/SummedEvent.java | 8 +-- .../library/models/metrics/UniqueEvent.java | 8 +-- .../library/services/BacktraceMetrics.java | 61 +++++++++++++------ .../library/services/SummedEventsHandler.java | 15 +++-- .../library/services/UniqueEventsHandler.java | 7 +-- 12 files changed, 192 insertions(+), 100 deletions(-) create mode 100644 backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java create mode 100644 backtrace-library/src/main/java/backtraceio/library/models/Tuple.java create mode 100644 backtrace-library/src/main/java/backtraceio/library/models/json/ReportDataBuilder.java diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/metrics/BacktraceMetricsTest.java b/backtrace-library/src/androidTest/java/backtraceio/library/metrics/BacktraceMetricsTest.java index f7e46145..d4b3b7ba 100644 --- a/backtrace-library/src/androidTest/java/backtraceio/library/metrics/BacktraceMetricsTest.java +++ b/backtrace-library/src/androidTest/java/backtraceio/library/metrics/BacktraceMetricsTest.java @@ -57,7 +57,7 @@ public void setUp() { @Test public void addAttributesSummedEvent() { SummedEvent summedEvent = new SummedEvent(summedEventName, null); - Map attributes = new HashMap() {{ + Map attributes = new HashMap() {{ put("foo", "bar"); }}; summedEvent.addAttributes(attributes); @@ -67,7 +67,7 @@ public void addAttributesSummedEvent() { @Test public void addAttributesUniqueEvent() { UniqueEvent uniqueEvent = new UniqueEvent(uniqueAttributeName[0], null); - Map attributes = new HashMap() {{ + Map attributes = new HashMap() {{ put("foo", "bar"); }}; uniqueEvent.update(BacktraceTimeHelper.getTimestampSeconds(), attributes); diff --git a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java new file mode 100644 index 00000000..6462dc02 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java @@ -0,0 +1,51 @@ +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 ApplicationHelper { + private static final transient String LOG_TAG = ApplicationHelper.class.getSimpleName(); + /** + * Cached application name + */ + private static String applicationName; + + /** + * Cached application version + */ + private static String applicationVersion; + + /** + * 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)) { + return applicationName; + } + + applicationName = context.getApplicationInfo().loadLabel(context.getPackageManager()).toString(); + return applicationName; + } + + public static String getApplicationVersion(Context context) { + 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.printStackTrace(); + return ""; + } + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java b/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java new file mode 100644 index 00000000..e6ec785f --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java @@ -0,0 +1,11 @@ +package backtraceio.library.models; + +public class Tuple { + public final T1 first; + public final T2 second; + + public Tuple(T1 first, T2 second) { + this.first = first; + this.second = second; + } +} \ No newline at end of file diff --git a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java index de9d247c..4948f185 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java @@ -15,18 +15,18 @@ import java.util.UUID; import backtraceio.library.BacktraceClient; +import backtraceio.library.common.ApplicationHelper; import backtraceio.library.common.BacktraceStringHelper; import backtraceio.library.common.DeviceAttributesHelper; import backtraceio.library.common.TypeHelper; import backtraceio.library.enums.ScreenOrientation; import backtraceio.library.logger.BacktraceLogger; +import backtraceio.library.models.Tuple; /** * Class instance to get a built-in attributes from current application */ public class BacktraceAttributes { - private static final transient String LOG_TAG = BacktraceAttributes.class.getSimpleName(); - /** * Get built-in primitive attributes */ @@ -42,15 +42,10 @@ public class BacktraceAttributes { */ private final Context context; - /** - * Are metrics enabled? - */ - private static boolean isMetricsEnabled = false; - /** * Metrics session ID */ - private static String sessionId = UUID.randomUUID().toString(); + private final static String sessionId = UUID.randomUUID().toString(); /** * Create instance of Backtrace Attribute @@ -112,8 +107,8 @@ private void setDeviceInformation(Boolean includeDynamicAttributes) { private void setAppInformation() { this.attributes.put("application.package", this.context.getApplicationContext() .getPackageName()); - this.attributes.put("application", getApplicationName()); - String version = getApplicationVersionOrEmpty(); + this.attributes.put("application", ApplicationHelper.getApplicationName(this.context)); + String version = ApplicationHelper.getApplicationVersion(this.context); if (!BacktraceStringHelper.isNullOrEmpty(version)) { // We want to standardize application.version attribute name this.attributes.put("application.version", version); @@ -211,41 +206,12 @@ private void convertReportAttributes(BacktraceReport report) { } } - /** - * Divide custom user attributes into primitive and complex attributes and add to this object - * - * @param attributes client's attributes - */ - private void convertAttributes(Map attributes) { - for (Map.Entry entry : attributes.entrySet()) { - Object value = entry.getValue(); - if (value == null) { - continue; - } - Class type = value.getClass(); - if (TypeHelper.isPrimitiveOrPrimitiveWrapperOrString(type)) { - this.attributes.put(entry.getKey(), value.toString()); - } else { - this.complexAttributes.put(entry.getKey(), value); - } - } - } - - public String getApplicationName() { - return this.context.getApplicationInfo().loadLabel(this.context - .getPackageManager()).toString(); + private void convertAttributes(Map clientAttributes) { + Tuple, Map> reportData = ReportDataBuilder.getReportAttribues(clientAttributes); + this.attributes.putAll(reportData.first); + this.complexAttributes.putAll(reportData.second); } - public String getApplicationVersionOrEmpty() { - try { - return this.context.getPackageManager() - .getPackageInfo(this.context.getPackageName(), 0).versionName; - } catch (PackageManager.NameNotFoundException e) { - BacktraceLogger.e(LOG_TAG, "Could not resolve application version"); - e.printStackTrace(); - } - return ""; - } public Map getAllAttributes() { Map attributes = new HashMap(); diff --git a/backtrace-library/src/main/java/backtraceio/library/models/json/ReportDataBuilder.java b/backtrace-library/src/main/java/backtraceio/library/models/json/ReportDataBuilder.java new file mode 100644 index 00000000..02b63f79 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/models/json/ReportDataBuilder.java @@ -0,0 +1,40 @@ +package backtraceio.library.models.json; +import java.util.HashMap; +import java.util.Map; + +import backtraceio.library.common.TypeHelper; +import backtraceio.library.models.Tuple; + +public class ReportDataBuilder { + + /** + * Divide custom user attributes into primitive and complex attributes and add to this object + * + * @param attributes client's attributes + */ + public static Tuple, Map> getReportAttribues(Map attributes) { + HashMap reportAttributes = new HashMap<>(); + HashMap reportAnnotations = new HashMap<>(); + + if(attributes == null) { + return new Tuple<>(reportAttributes, reportAnnotations); + } + + for (Map.Entry entry : attributes.entrySet()) { + Object value = entry.getValue(); + if (value == null) { + reportAttributes.put(entry.getKey(), "null"); + continue; + } + Class type = value.getClass(); + if (TypeHelper.isPrimitiveOrPrimitiveWrapperOrString(type)) { + reportAttributes.put(entry.getKey(), value.toString()); + } else { + reportAnnotations.put(entry.getKey(), value); + } + } + + return new Tuple<>(reportAttributes, reportAnnotations); + + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/models/metrics/Event.java b/backtrace-library/src/main/java/backtraceio/library/models/metrics/Event.java index fce15e6e..6c475a5f 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/metrics/Event.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/metrics/Event.java @@ -12,8 +12,11 @@ public abstract class Event { @SerializedName("timestamp") protected long timestamp; + /** + * The event should always have attributes. Event without attributes won't be processed + */ @SerializedName("attributes") - protected Map attributes; + protected Map attributes = new HashMap<>(); public Event(long timestamp) { this.timestamp = timestamp; @@ -23,30 +26,16 @@ public long getTimestamp() { return this.timestamp; } - public Map getAttributes() { + public Map getAttributes() { return this.attributes; } public abstract String getName(); - protected void addAttributesImpl(Map attributes) { - if (attributes == null || attributes.size() == 0) { + protected void addAttributesImpl(Map attributes) { + if (attributes == null || attributes.isEmpty()) { return; } - - Map attributesNoEmpty = new HashMap(); - - for (String key : attributes.keySet()) { - Object value = attributes.get(key); - if (BacktraceStringHelper.isObjectNotNullOrNotEmptyString(value)) { - attributesNoEmpty.put(key, value); - } - } - - if (this.attributes == null) { - this.attributes = attributesNoEmpty; - } else { - this.attributes.putAll(attributesNoEmpty); - } + this.attributes.putAll(attributes); } } diff --git a/backtrace-library/src/main/java/backtraceio/library/models/metrics/EventsPayload.java b/backtrace-library/src/main/java/backtraceio/library/models/metrics/EventsPayload.java index 05198c75..f07d9241 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/metrics/EventsPayload.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/metrics/EventsPayload.java @@ -33,5 +33,13 @@ public void setDroppedEvents(int droppedEvents) { this.eventsMetadata.setDroppedEvents(droppedEvents); } + public String getApplicationVersion() { + return appVersion; + } + + public String getApplicationName() { + return application; + } + public abstract ConcurrentLinkedDeque getEvents(); } diff --git a/backtrace-library/src/main/java/backtraceio/library/models/metrics/SummedEvent.java b/backtrace-library/src/main/java/backtraceio/library/models/metrics/SummedEvent.java index b9665f01..bcd8efb8 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/metrics/SummedEvent.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/metrics/SummedEvent.java @@ -13,14 +13,14 @@ public final class SummedEvent extends Event { private final String name; public SummedEvent(String name) { - this(name, new HashMap()); + this(name, null); } - public SummedEvent(String name, Map attributes) { + public SummedEvent(String name, Map attributes) { this(name, BacktraceTimeHelper.getTimestampSeconds(), attributes); } - public SummedEvent(String name, long timestamp, Map attributes) { + public SummedEvent(String name, long timestamp, Map attributes) { super(timestamp); this.name = name; addAttributesImpl(attributes); @@ -35,7 +35,7 @@ public String getName() { return this.name; } - public void addAttributes(Map attributes) { + public void addAttributes(Map attributes) { addAttributesImpl(attributes); } } diff --git a/backtrace-library/src/main/java/backtraceio/library/models/metrics/UniqueEvent.java b/backtrace-library/src/main/java/backtraceio/library/models/metrics/UniqueEvent.java index 789b9825..151bbe93 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/metrics/UniqueEvent.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/metrics/UniqueEvent.java @@ -22,14 +22,14 @@ public class UniqueEvent extends Event { private final List name; public UniqueEvent(String name) { - this(name, new HashMap()); + this(name, null); } - public UniqueEvent(String name, Map attributes) { + public UniqueEvent(String name, Map attributes) { this(name, BacktraceTimeHelper.getTimestampSeconds(), attributes); } - public UniqueEvent(String name, long timestamp, Map attributes) { + public UniqueEvent(String name, long timestamp, Map attributes) { super(timestamp); this.name = new ArrayList() {{ add(name); @@ -49,7 +49,7 @@ public String getName() { return ""; } - public void update(long timestamp, Map attributes) { + public void update(long timestamp, Map attributes) { this.timestamp = timestamp; addAttributesImpl(attributes); } diff --git a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java index 2bbbad20..88b2c355 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java @@ -9,6 +9,7 @@ import java.util.concurrent.ConcurrentLinkedDeque; import backtraceio.library.BacktraceCredentials; +import backtraceio.library.common.ApplicationHelper; import backtraceio.library.common.BacktraceStringHelper; import backtraceio.library.common.BacktraceTimeHelper; import backtraceio.library.common.serialization.DebugHelper; @@ -19,6 +20,7 @@ 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.metrics.SummedEvent; import backtraceio.library.models.metrics.UniqueEvent; @@ -84,7 +86,7 @@ public final class BacktraceMetrics implements Metrics { /** * Custom attributes provided by the user to BacktraceBase */ - Map customReportAttributes; + Map customReportAttributes; /** * The application context @@ -117,6 +119,16 @@ public final class BacktraceMetrics implements Metrics { */ private final BacktraceCredentials credentials; + /** + * Application name + */ + private String applicationName; + + /** + * Application version + */ + private String applicationVersion; + /** * Create new Backtrace metrics instance * @@ -126,7 +138,8 @@ public final class BacktraceMetrics implements Metrics { */ public BacktraceMetrics(Context context, @NotNull Map customReportAttributes, Api backtraceApi, BacktraceCredentials credentials) { this.context = context; - this.customReportAttributes = customReportAttributes; + // use only attributes, ignore annotations + this.customReportAttributes = ReportDataBuilder.getReportAttribues(customReportAttributes).first; this.backtraceApi = backtraceApi; this.credentials = credentials; } @@ -172,6 +185,8 @@ public void enable(BacktraceMetricsSettings settings, String uniqueEventName) { } long startExeuction = DebugHelper.getCurrentTimeMillis(); + this.applicationName = ApplicationHelper.getApplicationName(this.getContext()); + this.applicationVersion = ApplicationHelper.getApplicationVersion(this.getContext()); setStartupUniqueEventName(uniqueEventName); this.settings = settings; this.enabled = true; @@ -269,7 +284,9 @@ public boolean addUniqueEvent(String attributeName, Map attribut return false; } - Map localAttributes = createLocalAttributes(attributes); + Map metricsAttributes = ReportDataBuilder.getReportAttribues(attributes).first; + + Map localAttributes = createLocalAttributes(metricsAttributes); // validate if unique event attribute is available and // prevent undefined attributes @@ -322,7 +339,7 @@ public int count() { /** * Add a summed event to the next Backtrace Metrics request * - * @param metricGroupName + * @param metricGroupName name of the metrics group * @return true if success */ public boolean addSummedEvent(String metricGroupName) { @@ -332,8 +349,8 @@ public boolean addSummedEvent(String metricGroupName) { /** * Add a summed event to the next Backtrace Metrics request * - * @param metricGroupName - * @param attributes + * @param metricGroupName name of the metrics group + * @param attributes metrics attributes * @return true if success */ public boolean addSummedEvent(String metricGroupName, Map attributes) { @@ -344,12 +361,10 @@ public boolean addSummedEvent(String metricGroupName, Map attrib return false; } - Map localAttributes = new HashMap<>(); - if (attributes != null) { - localAttributes.putAll(attributes); - } + Map metricsAttributes = ReportDataBuilder.getReportAttribues(attributes).first; - SummedEvent summedEvent = new SummedEvent(metricGroupName, BacktraceTimeHelper.getTimestampSeconds(), localAttributes); + SummedEvent summedEvent = new SummedEvent(metricGroupName); + summedEvent.addAttributes(metricsAttributes); summedEventsHandler.events.addLast(summedEvent); if (count() == maximumNumberOfEvents) { uniqueEventsHandler.send(); @@ -404,17 +419,27 @@ private boolean shouldProcessEvent(String name) { return true; } - protected Map createLocalAttributes(Map attributes) { - Map localAttributes = new HashMap<>(); + protected Map createLocalAttributes(Map attributes) { + final long start = DebugHelper.getCurrentTimeMillis(); + BacktraceAttributes backtraceAttributes = new BacktraceAttributes(context, null); + + Map result = backtraceAttributes.attributes; + result.putAll(customReportAttributes); - if (attributes != null) { - localAttributes.putAll(attributes); + if (attributes != null && !attributes.isEmpty()) { + result.putAll(attributes); } - BacktraceAttributes backtraceAttributes = new BacktraceAttributes(context, null, customReportAttributes); - localAttributes.putAll(backtraceAttributes.getAllAttributes()); + BacktraceLogger.w(LOG_TAG, "createLocalAttributes: took:" + (DebugHelper.getCurrentTimeMillis() - start) + " milliseconds"); + return result; + } + + protected String getApplicationName() { + return applicationName; + } - return localAttributes; + protected String getApplicationVersion() { + return applicationVersion; } /** diff --git a/backtrace-library/src/main/java/backtraceio/library/services/SummedEventsHandler.java b/backtrace-library/src/main/java/backtraceio/library/services/SummedEventsHandler.java index fa936d5a..85b27ade 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/SummedEventsHandler.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/SummedEventsHandler.java @@ -1,5 +1,7 @@ package backtraceio.library.services; +import java.util.ArrayList; +import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentLinkedDeque; @@ -21,11 +23,14 @@ public SummedEventsHandler(BacktraceMetrics backtraceMetrics, @Override protected SummedEventsPayload getEventsPayload() { - Map attributes = backtraceMetrics.createLocalAttributes(null); - String application = attributes.get("application").toString(); - String appVersion = attributes.get("application.version").toString(); - - SummedEventsPayload payload = new SummedEventsPayload(events, application, appVersion); + Map attributes = backtraceMetrics.createLocalAttributes(null); + for (SummedEvent event: events) { + event.addAttributes(attributes); + } + SummedEventsPayload payload = new SummedEventsPayload( + new ConcurrentLinkedDeque<>(events), + backtraceMetrics.getApplicationName(), + backtraceMetrics.getApplicationVersion()); events.clear(); return payload; } diff --git a/backtrace-library/src/main/java/backtraceio/library/services/UniqueEventsHandler.java b/backtrace-library/src/main/java/backtraceio/library/services/UniqueEventsHandler.java index b6b6e5d3..6b7199f7 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/UniqueEventsHandler.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/UniqueEventsHandler.java @@ -22,16 +22,13 @@ public UniqueEventsHandler(BacktraceMetrics backtraceMetrics, @Override protected UniqueEventsPayload getEventsPayload() { - Map attributes = backtraceMetrics.createLocalAttributes(null); - String application = attributes.get("application").toString(); - String appVersion = attributes.get("application.version").toString(); + Map attributes = backtraceMetrics.createLocalAttributes(null); for (UniqueEvent event : events) { event.update(BacktraceTimeHelper.getTimestampSeconds(), attributes); } - UniqueEventsPayload payload = new UniqueEventsPayload(events, application, appVersion); - return payload; + return new UniqueEventsPayload(events, backtraceMetrics.getApplicationName(), backtraceMetrics.getApplicationVersion()); } @Override From 33c5cccef44a6e19a0cd3e55e13dda9cb0f0e78c Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Mon, 4 Nov 2024 13:17:09 +0100 Subject: [PATCH 03/15] Add end of line to Tuple --- .../src/main/java/backtraceio/library/models/Tuple.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java b/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java index e6ec785f..c25386d4 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java @@ -8,4 +8,4 @@ public Tuple(T1 first, T2 second) { this.first = first; this.second = second; } -} \ No newline at end of file +} From 095ee2a6862e89d6b7678fc043cca37ad1323821 Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Mon, 4 Nov 2024 13:39:33 +0100 Subject: [PATCH 04/15] Attributes getter and remove old not valid tests --- .../BacktraceClientUniqueEventTest.java | 44 ------------------- .../library/services/BacktraceMetrics.java | 21 ++++++--- 2 files changed, 16 insertions(+), 49 deletions(-) diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientUniqueEventTest.java b/backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientUniqueEventTest.java index af44bff8..ad6a15d0 100644 --- a/backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientUniqueEventTest.java +++ b/backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientUniqueEventTest.java @@ -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)); - } } diff --git a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java index 88b2c355..28332aae 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java @@ -86,7 +86,7 @@ public final class BacktraceMetrics implements Metrics { /** * Custom attributes provided by the user to BacktraceBase */ - Map customReportAttributes; + Map customReportAttributes; /** * The application context @@ -138,8 +138,7 @@ public final class BacktraceMetrics implements Metrics { */ public BacktraceMetrics(Context context, @NotNull Map customReportAttributes, Api backtraceApi, BacktraceCredentials credentials) { this.context = context; - // use only attributes, ignore annotations - this.customReportAttributes = ReportDataBuilder.getReportAttribues(customReportAttributes).first; + this.customReportAttributes = customReportAttributes; this.backtraceApi = backtraceApi; this.credentials = credentials; } @@ -207,6 +206,18 @@ public void enable(BacktraceMetricsSettings settings, String uniqueEventName) { BacktraceLogger.w(LOG_TAG, "TOTAL: Setup metrics integration took " + (DebugHelper.getCurrentTimeMillis() - startExeuction) + " milliseconds"); } + /** + * Attributes are passed by the reference from the Backtrace client instance. + * If we modify them in the constructor, we won't be able to get "up to date" + * version from the client anymore. + * + * Due to that, we need to have a getter that will always transform attributes to a simple format. + */ + private Map getClientMetricsAttributes() { + return ReportDataBuilder.getReportAttribues(customReportAttributes).first; + } + + private void verifyIfMetricsAvailable() { if (!enabled) { throw new IllegalArgumentException("Metrics are not available!"); @@ -421,10 +432,10 @@ private boolean shouldProcessEvent(String name) { protected Map createLocalAttributes(Map attributes) { final long start = DebugHelper.getCurrentTimeMillis(); - BacktraceAttributes backtraceAttributes = new BacktraceAttributes(context, null); + BacktraceAttributes backtraceAttributes = new BacktraceAttributes(context, null, null, true); Map result = backtraceAttributes.attributes; - result.putAll(customReportAttributes); + result.putAll(this.getClientMetricsAttributes()); if (attributes != null && !attributes.isEmpty()) { result.putAll(attributes); From 2ac667f3abdb7fa9b91325a7aa0f6690d3435c7e Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Tue, 5 Nov 2024 17:35:00 +0100 Subject: [PATCH 05/15] Optimize attributes --- .../library/common/ApplicationHelper.java | 27 +++++++++- .../common/DeviceAttributesHelper.java | 54 +++++++++---------- .../models/json/BacktraceAttributes.java | 5 +- 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java index 6462dc02..2d8a7665 100644 --- a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java +++ b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java @@ -18,6 +18,11 @@ public class ApplicationHelper { */ private static String applicationVersion; + /** + * Cached package name + */ + private static String packageName; + /** * Retrieves application name from context. The name will be cached over checks * @param context application context @@ -32,6 +37,11 @@ public static String getApplicationName(Context context) { 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)) { return applicationVersion; @@ -43,9 +53,22 @@ public static String getApplicationVersion(Context context) { return applicationVersion; } catch (PackageManager.NameNotFoundException e) { - BacktraceLogger.e(LOG_TAG, "Could not resolve application version"); - e.printStackTrace(); + BacktraceLogger.e(LOG_TAG, "Could not resolve application version", e); return ""; } } + + /** + * Retrieves package name from the context. + * @param context application context + * @return current package name. + */ + public static String getPackageName(Context context) { + if(!BacktraceStringHelper.isNullOrEmpty(packageName)) { + return packageName; + } + packageName = context.getApplicationContext().getPackageName(); + + return packageName; + } } diff --git a/backtrace-library/src/main/java/backtraceio/library/common/DeviceAttributesHelper.java b/backtrace-library/src/main/java/backtraceio/library/common/DeviceAttributesHelper.java index 046c6651..6fd3811d 100644 --- a/backtrace-library/src/main/java/backtraceio/library/common/DeviceAttributesHelper.java +++ b/backtrace-library/src/main/java/backtraceio/library/common/DeviceAttributesHelper.java @@ -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; @@ -36,6 +36,11 @@ public class DeviceAttributesHelper { private final Context context; + /* + * Current Device id + */ + private static String guid; + public DeviceAttributesHelper(Context context) { this.context = context; } @@ -61,15 +66,17 @@ public HashMap 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; } @@ -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; @@ -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(guid)) { + return guid; } - 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 + guid = 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 guid; } private ActivityManager.MemoryInfo getMemoryInformation() { diff --git a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java index 4948f185..410790c1 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java @@ -18,9 +18,7 @@ import backtraceio.library.common.ApplicationHelper; import backtraceio.library.common.BacktraceStringHelper; import backtraceio.library.common.DeviceAttributesHelper; -import backtraceio.library.common.TypeHelper; import backtraceio.library.enums.ScreenOrientation; -import backtraceio.library.logger.BacktraceLogger; import backtraceio.library.models.Tuple; /** @@ -105,8 +103,7 @@ private void setDeviceInformation(Boolean includeDynamicAttributes) { } private void setAppInformation() { - this.attributes.put("application.package", this.context.getApplicationContext() - .getPackageName()); + this.attributes.put("application.package", ApplicationHelper.getPackageName(this.context)); this.attributes.put("application", ApplicationHelper.getApplicationName(this.context)); String version = ApplicationHelper.getApplicationVersion(this.context); if (!BacktraceStringHelper.isNullOrEmpty(version)) { From ccca7dc83c75ee9614d41862d16cbb45ed44720a Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Tue, 5 Nov 2024 18:02:47 +0100 Subject: [PATCH 06/15] Remove debugging information and format file --- .../library/services/BacktraceMetrics.java | 31 ++----------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java index 28332aae..7e14fac1 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java @@ -12,7 +12,6 @@ import backtraceio.library.common.ApplicationHelper; 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; @@ -183,34 +182,23 @@ public void enable(BacktraceMetricsSettings settings, String uniqueEventName) { throw new IllegalArgumentException("Unique event name must be defined!"); } - long startExeuction = DebugHelper.getCurrentTimeMillis(); this.applicationName = ApplicationHelper.getApplicationName(this.getContext()); this.applicationVersion = ApplicationHelper.getApplicationVersion(this.getContext()); setStartupUniqueEventName(uniqueEventName); this.settings = settings; this.enabled = true; - long startMetricsSetup = DebugHelper.getCurrentTimeMillis(); try { startMetricsEventHandlers(backtraceApi); - - BacktraceLogger.w(LOG_TAG, "ENABLE: startMetricsEventHandlers took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); - startMetricsSetup = DebugHelper.getCurrentTimeMillis(); - sendStartupEvent(); - - BacktraceLogger.w(LOG_TAG, "ENABLE: sendStartupEvent took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); - BacktraceLogger.d(LOG_TAG, "Metrics enabled"); } catch (Exception e) { BacktraceLogger.e(LOG_TAG, "Could not enable metrics, exception " + e.getMessage()); } - BacktraceLogger.w(LOG_TAG, "TOTAL: Setup metrics integration took " + (DebugHelper.getCurrentTimeMillis() - startExeuction) + " milliseconds"); } /** * Attributes are passed by the reference from the Backtrace client instance. * If we modify them in the constructor, we won't be able to get "up to date" - * version from the client anymore. - * + * version from the client anymore. * Due to that, we need to have a getter that will always transform attributes to a simple format. */ private Map getClientMetricsAttributes() { @@ -226,13 +214,8 @@ private void verifyIfMetricsAvailable() { private void startMetricsEventHandlers(Api backtraceApi) { verifyIfMetricsAvailable(); - long startMetricsSetup = DebugHelper.getCurrentTimeMillis(); uniqueEventsHandler = backtraceApi.enableUniqueEvents(this); - - BacktraceLogger.w(LOG_TAG, "startMetricsEventHandlers: uniqueEventsHandler took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); - startMetricsSetup = DebugHelper.getCurrentTimeMillis(); summedEventsHandler = backtraceApi.enableSummedEvents(this); - BacktraceLogger.w(LOG_TAG, "startMetricsEventHandlers: enableSummedEvents took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); } public void setStartupUniqueEventName(String startupUniqueEventName) { @@ -248,17 +231,11 @@ public String getBaseUrl() { */ public void sendStartupEvent() { verifyIfMetricsAvailable(); - long startMetricsSetup = DebugHelper.getCurrentTimeMillis(); addUniqueEvent(startupUniqueEventName); addSummedEvent(startupSummedEventName); - BacktraceLogger.w(LOG_TAG, "sendStartupEvent: adding elements took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); - startMetricsSetup = DebugHelper.getCurrentTimeMillis(); + uniqueEventsHandler.send(); - BacktraceLogger.w(LOG_TAG, "sendStartupEvent: sending uniqueEventsHandler took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); - startMetricsSetup = DebugHelper.getCurrentTimeMillis(); summedEventsHandler.send(); - - BacktraceLogger.w(LOG_TAG, "sendStartupEvent: sending summedEventsHandler took:" + (DebugHelper.getCurrentTimeMillis() - startMetricsSetup) + " milliseconds"); } /** @@ -361,7 +338,7 @@ public boolean addSummedEvent(String metricGroupName) { * Add a summed event to the next Backtrace Metrics request * * @param metricGroupName name of the metrics group - * @param attributes metrics attributes + * @param attributes metrics attributes * @return true if success */ public boolean addSummedEvent(String metricGroupName, Map attributes) { @@ -431,7 +408,6 @@ private boolean shouldProcessEvent(String name) { } protected Map createLocalAttributes(Map attributes) { - final long start = DebugHelper.getCurrentTimeMillis(); BacktraceAttributes backtraceAttributes = new BacktraceAttributes(context, null, null, true); Map result = backtraceAttributes.attributes; @@ -441,7 +417,6 @@ protected Map createLocalAttributes(Map attribut result.putAll(attributes); } - BacktraceLogger.w(LOG_TAG, "createLocalAttributes: took:" + (DebugHelper.getCurrentTimeMillis() - start) + " milliseconds"); return result; } From 5a4a7c9e0287a7173d3750d9a574cfb59c474c74 Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Tue, 5 Nov 2024 18:06:25 +0100 Subject: [PATCH 07/15] Rollback MainActivity --- .../src/main/java/backtraceio/backtraceio/MainActivity.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java b/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java index 9d2618ae..e0f5be57 100644 --- a/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java +++ b/example-app/src/main/java/backtraceio/backtraceio/MainActivity.java @@ -29,8 +29,6 @@ import backtraceio.library.enums.database.RetryBehavior; import backtraceio.library.enums.database.RetryOrder; import backtraceio.library.events.OnServerResponseEventListener; -import backtraceio.library.logger.BacktraceLogger; -import backtraceio.library.logger.LogLevel; import backtraceio.library.models.BacktraceExceptionHandler; import backtraceio.library.models.database.BacktraceDatabaseSettings; import backtraceio.library.models.json.BacktraceReport; @@ -78,8 +76,6 @@ private void symlinkAndWriteFile() { private BacktraceClient initializeBacktrace(final String submissionUrl) { BacktraceCredentials credentials = new BacktraceCredentials(submissionUrl); - - BacktraceLogger.setLevel(LogLevel.DEBUG); Context context = getApplicationContext(); String dbPath = context.getFilesDir().getAbsolutePath(); From 75a94f08a9e15d428d5bc0c1eb46ff4a42f13b1c Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Wed, 6 Nov 2024 17:20:40 +0100 Subject: [PATCH 08/15] Reformat file. Bring previous metrics logic --- .../backtraceio/library/common/ApplicationHelper.java | 11 +++++++---- .../library/services/BacktraceMetrics.java | 8 +++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java index 2d8a7665..ae70b9c3 100644 --- a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java +++ b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java @@ -25,25 +25,27 @@ public class ApplicationHelper { /** * 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)) { + if (!BacktraceStringHelper.isNullOrEmpty(applicationName)) { return applicationName; } applicationName = context.getApplicationInfo().loadLabel(context.getPackageManager()).toString(); - 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)) { + if (!BacktraceStringHelper.isNullOrEmpty(applicationVersion)) { return applicationVersion; } try { @@ -60,11 +62,12 @@ 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)) { + if (!BacktraceStringHelper.isNullOrEmpty(packageName)) { return packageName; } packageName = context.getApplicationContext().getPackageName(); diff --git a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java index 7e14fac1..6bf7f9fb 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java @@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentLinkedDeque; @@ -12,6 +11,7 @@ import backtraceio.library.common.ApplicationHelper; 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; @@ -184,15 +184,21 @@ public void enable(BacktraceMetricsSettings settings, String uniqueEventName) { this.applicationName = ApplicationHelper.getApplicationName(this.getContext()); this.applicationVersion = ApplicationHelper.getApplicationVersion(this.getContext()); + setStartupUniqueEventName(uniqueEventName); + 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"); } /** From 5eab77b198d1435ed5d2b151acfad16731b27c09 Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Thu, 7 Nov 2024 11:23:49 +0100 Subject: [PATCH 09/15] Report data builder tests --- .../common/DeviceAttributesHelper.java | 10 +-- .../attributes/ReportDataAttributes.java | 27 ++++++++ .../models/attributes/ReportDataBuilder.java | 54 +++++++++++++++ .../models/json/BacktraceAttributes.java | 10 +-- .../models/json/ReportDataBuilder.java | 40 ----------- .../library/services/BacktraceMetrics.java | 8 +-- .../ReportDataAnnotationBuilderTest.java | 49 ++++++++++++++ .../ReportDataAttributeBuilderTest.java | 67 +++++++++++++++++++ 8 files changed, 211 insertions(+), 54 deletions(-) create mode 100644 backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataAttributes.java create mode 100644 backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java delete mode 100644 backtrace-library/src/main/java/backtraceio/library/models/json/ReportDataBuilder.java create mode 100644 backtrace-library/src/test/java/backtraceio/library/ReportDataAnnotationBuilderTest.java create mode 100644 backtrace-library/src/test/java/backtraceio/library/ReportDataAttributeBuilderTest.java diff --git a/backtrace-library/src/main/java/backtraceio/library/common/DeviceAttributesHelper.java b/backtrace-library/src/main/java/backtraceio/library/common/DeviceAttributesHelper.java index 6fd3811d..63b6100d 100644 --- a/backtrace-library/src/main/java/backtraceio/library/common/DeviceAttributesHelper.java +++ b/backtrace-library/src/main/java/backtraceio/library/common/DeviceAttributesHelper.java @@ -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; @@ -262,8 +262,8 @@ 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(), @@ -271,11 +271,11 @@ private String generateDeviceId() { // if the android id is not defined we want to cache at least guid // 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() { diff --git a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataAttributes.java b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataAttributes.java new file mode 100644 index 00000000..01189b50 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataAttributes.java @@ -0,0 +1,27 @@ +package backtraceio.library.models.attributes; + +import java.util.HashMap; + +public class ReportDataAttributes { + private final HashMap reportAttributes = new HashMap<>(); + + private final HashMap 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 getAttributes() { + return reportAttributes; + } + + public HashMap getAnnotations() { + return reportAnnotations; + } + +} diff --git a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java new file mode 100644 index 00000000..6922cda3 --- /dev/null +++ b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java @@ -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 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 attributes, boolean skipNullable) { + ReportDataAttributes reportDataAttributes = new ReportDataAttributes(); + + if (attributes == null) { + return reportDataAttributes; + } + + for (Map.Entry 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; + + } +} diff --git a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java index 410790c1..083e1a14 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java @@ -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; @@ -19,7 +18,8 @@ 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 @@ -204,9 +204,9 @@ private void convertReportAttributes(BacktraceReport report) { } private void convertAttributes(Map clientAttributes) { - Tuple, Map> 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()); } diff --git a/backtrace-library/src/main/java/backtraceio/library/models/json/ReportDataBuilder.java b/backtrace-library/src/main/java/backtraceio/library/models/json/ReportDataBuilder.java deleted file mode 100644 index 02b63f79..00000000 --- a/backtrace-library/src/main/java/backtraceio/library/models/json/ReportDataBuilder.java +++ /dev/null @@ -1,40 +0,0 @@ -package backtraceio.library.models.json; -import java.util.HashMap; -import java.util.Map; - -import backtraceio.library.common.TypeHelper; -import backtraceio.library.models.Tuple; - -public class ReportDataBuilder { - - /** - * Divide custom user attributes into primitive and complex attributes and add to this object - * - * @param attributes client's attributes - */ - public static Tuple, Map> getReportAttribues(Map attributes) { - HashMap reportAttributes = new HashMap<>(); - HashMap reportAnnotations = new HashMap<>(); - - if(attributes == null) { - return new Tuple<>(reportAttributes, reportAnnotations); - } - - for (Map.Entry entry : attributes.entrySet()) { - Object value = entry.getValue(); - if (value == null) { - reportAttributes.put(entry.getKey(), "null"); - continue; - } - Class type = value.getClass(); - if (TypeHelper.isPrimitiveOrPrimitiveWrapperOrString(type)) { - reportAttributes.put(entry.getKey(), value.toString()); - } else { - reportAnnotations.put(entry.getKey(), value); - } - } - - return new Tuple<>(reportAttributes, reportAnnotations); - - } -} diff --git a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java index 6bf7f9fb..afbe7fd7 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java @@ -19,7 +19,7 @@ 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; @@ -208,7 +208,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 getClientMetricsAttributes() { - return ReportDataBuilder.getReportAttribues(customReportAttributes).first; + return ReportDataBuilder.getReportAttributes(customReportAttributes, true).getAttributes(); } @@ -278,7 +278,7 @@ public boolean addUniqueEvent(String attributeName, Map attribut return false; } - Map metricsAttributes = ReportDataBuilder.getReportAttribues(attributes).first; + Map metricsAttributes = ReportDataBuilder.getReportAttributes(attributes, true).getAttributes(); Map localAttributes = createLocalAttributes(metricsAttributes); @@ -355,7 +355,7 @@ public boolean addSummedEvent(String metricGroupName, Map attrib return false; } - Map metricsAttributes = ReportDataBuilder.getReportAttribues(attributes).first; + Map metricsAttributes = ReportDataBuilder.getReportAttributes(attributes, true).getAttributes(); SummedEvent summedEvent = new SummedEvent(metricGroupName); summedEvent.addAttributes(metricsAttributes); diff --git a/backtrace-library/src/test/java/backtraceio/library/ReportDataAnnotationBuilderTest.java b/backtrace-library/src/test/java/backtraceio/library/ReportDataAnnotationBuilderTest.java new file mode 100644 index 00000000..a0259ee9 --- /dev/null +++ b/backtrace-library/src/test/java/backtraceio/library/ReportDataAnnotationBuilderTest.java @@ -0,0 +1,49 @@ +package backtraceio.library; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; + +import static org.junit.Assert.assertEquals; + +import backtraceio.library.models.attributes.ReportDataAttributes; +import backtraceio.library.models.attributes.ReportDataBuilder; + +@RunWith(Parameterized.class) +public class ReportDataAnnotationBuilderTest { + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(new Object[][]{ + {new HashMap() {{ + put("add", "value"); + }}}, + {new HashSet() {{ + add("value"); + }}}, + {new Object()}, + }); + } + + private final Object annotation; + + public ReportDataAnnotationBuilderTest(Object annotation) { + this.annotation = annotation; + } + + @Test + public void correctlySetComplexObjectAsAnnotation() { + String key = "annotation-key"; + ReportDataAttributes data = ReportDataBuilder.getReportAttributes(new HashMap() { + { + put(key, annotation); + } + }); + assertEquals(data.getAnnotations().get(key), annotation); + } +} diff --git a/backtrace-library/src/test/java/backtraceio/library/ReportDataAttributeBuilderTest.java b/backtrace-library/src/test/java/backtraceio/library/ReportDataAttributeBuilderTest.java new file mode 100644 index 00000000..dd0cd75d --- /dev/null +++ b/backtrace-library/src/test/java/backtraceio/library/ReportDataAttributeBuilderTest.java @@ -0,0 +1,67 @@ +package backtraceio.library; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import backtraceio.library.models.attributes.ReportDataAttributes; +import backtraceio.library.models.attributes.ReportDataBuilder; + +@RunWith(Parameterized.class) +public class ReportDataAttributeBuilderTest { + + private final String key = "attribute-key"; + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(new Object[][]{ + {"String value"}, + {123}, + {45.67}, + {true}, + }); + } + + private final Object primitiveValue; + + public ReportDataAttributeBuilderTest(Object primitiveValue) { + this.primitiveValue = primitiveValue; + } + + @Test + public void correctlySetPrimitiveValueIntoAttribute() { + ReportDataAttributes data = ReportDataBuilder.getReportAttributes(new HashMap() { + { + put(key, primitiveValue); + } + }); + assertEquals(data.getAttributes().get(key), primitiveValue.toString()); + } + + @Test + public void shouldSetNullableValueAsAttribute() { + ReportDataAttributes data = ReportDataBuilder.getReportAttributes(new HashMap() { + { + put(key, null); + } + }); + assertNull(data.getAttributes().get(key)); + } + + @Test + public void shouldSkipNullableValue() { + ReportDataAttributes data = ReportDataBuilder.getReportAttributes(new HashMap() { + { + put(key, null); + } + }, true); + assertNull(data.getAttributes().get(key)); + } +} From 330769b8d9e8b6bb47d43581bffd56176b7a73dc Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Thu, 7 Nov 2024 11:57:00 +0100 Subject: [PATCH 10/15] Move application cache to singleton --- ...per.java => ApplicationMetadataCache.java} | 43 ++++++++++++++----- .../models/json/BacktraceAttributes.java | 9 ++-- .../library/services/BacktraceMetrics.java | 7 +-- 3 files changed, 41 insertions(+), 18 deletions(-) rename backtrace-library/src/main/java/backtraceio/library/common/{ApplicationHelper.java => ApplicationMetadataCache.java} (65%) diff --git a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java similarity index 65% rename from backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java rename to backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java index ae70b9c3..3858cb3f 100644 --- a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationHelper.java +++ b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java @@ -6,30 +6,53 @@ 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) { + if (instance == null) { + instance = new ApplicationMetadataCache(context); + } + return instance; + } + + private final Context context; + + public ApplicationMetadataCache(Context context) { + 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) { + public String getApplicationName() { if (!BacktraceStringHelper.isNullOrEmpty(applicationName)) { return applicationName; } @@ -41,10 +64,9 @@ public static String getApplicationName(Context context) { /** * 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) { + public String getApplicationVersion() { if (!BacktraceStringHelper.isNullOrEmpty(applicationVersion)) { return applicationVersion; } @@ -63,10 +85,9 @@ 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) { + public String getPackageName() { if (!BacktraceStringHelper.isNullOrEmpty(packageName)) { return packageName; } diff --git a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java index 083e1a14..a9e9d34d 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java @@ -14,7 +14,7 @@ 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; @@ -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); diff --git a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java index afbe7fd7..605d0bca 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java @@ -8,7 +8,7 @@ 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; @@ -182,8 +182,9 @@ 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); final long startMetricsSetup = DebugHelper.getCurrentTimeMillis(); From ef6cd0229507e2b73481ecd60c02a1ef6e422fd0 Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Thu, 7 Nov 2024 14:44:50 +0100 Subject: [PATCH 11/15] SkipNul, remove additional unique event and make application cache thread safe --- .../library/ApplicationCacheTest.java | 31 +++++++++++++++++++ .../common/ApplicationMetadataCache.java | 8 +++-- .../models/attributes/ReportDataBuilder.java | 6 ++-- .../library/services/BacktraceMetrics.java | 2 +- 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 backtrace-library/src/androidTest/java/backtraceio/library/ApplicationCacheTest.java diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/ApplicationCacheTest.java b/backtrace-library/src/androidTest/java/backtraceio/library/ApplicationCacheTest.java new file mode 100644 index 00000000..c6a8dc2e --- /dev/null +++ b/backtrace-library/src/androidTest/java/backtraceio/library/ApplicationCacheTest.java @@ -0,0 +1,31 @@ +package backtraceio.library; + +import android.content.Context; + +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 ApplicationCacheTest { + 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); + + } + +} diff --git a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java index 3858cb3f..6b581d95 100644 --- a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java +++ b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java @@ -10,7 +10,7 @@ public class ApplicationMetadataCache { private static final transient String LOG_TAG = ApplicationMetadataCache.class.getSimpleName(); - private static ApplicationMetadataCache instance; + private static volatile ApplicationMetadataCache instance; /** * Cached application name @@ -36,7 +36,11 @@ public class ApplicationMetadataCache { */ public static ApplicationMetadataCache getInstance(Context context) { if (instance == null) { - instance = new ApplicationMetadataCache(context); + synchronized (ApplicationMetadataCache.class) { + if (instance == null) { + instance = new ApplicationMetadataCache(context); + } + } } return instance; } diff --git a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java index 6922cda3..3aa84043 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java @@ -20,12 +20,12 @@ public static ReportDataAttributes getReportAttributes(Map attri * 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 + * @param skipNull 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 attributes, boolean skipNullable) { + public static ReportDataAttributes getReportAttributes(Map attributes, boolean skipNull) { ReportDataAttributes reportDataAttributes = new ReportDataAttributes(); if (attributes == null) { @@ -36,7 +36,7 @@ public static ReportDataAttributes getReportAttributes(Map attri String key = entry.getKey(); Object value = entry.getValue(); if (value == null) { - if (!skipNullable) { + if (!skipNull) { reportDataAttributes.addAttribute(key, null); } continue; diff --git a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java index 605d0bca..980c6f84 100644 --- a/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java +++ b/backtrace-library/src/main/java/backtraceio/library/services/BacktraceMetrics.java @@ -185,7 +185,7 @@ public void enable(BacktraceMetricsSettings settings, String uniqueEventName) { ApplicationMetadataCache applicationMetadata = ApplicationMetadataCache.getInstance(this.getContext()); this.applicationName = applicationMetadata.getApplicationName(); this.applicationVersion = applicationMetadata.getApplicationVersion(); - setStartupUniqueEventName(uniqueEventName); + final long startMetricsSetup = DebugHelper.getCurrentTimeMillis(); setStartupUniqueEventName(uniqueEventName); From b5565d9aa72042c16e15b63a14dd8ceba0748cd6 Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Thu, 7 Nov 2024 17:35:47 +0100 Subject: [PATCH 12/15] Application metadata cache test --- .../library/ApplicationCacheTest.java | 31 ------------ .../library/ApplicationMetadataTest.java | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+), 31 deletions(-) delete mode 100644 backtrace-library/src/androidTest/java/backtraceio/library/ApplicationCacheTest.java create mode 100644 backtrace-library/src/androidTest/java/backtraceio/library/ApplicationMetadataTest.java diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/ApplicationCacheTest.java b/backtrace-library/src/androidTest/java/backtraceio/library/ApplicationCacheTest.java deleted file mode 100644 index c6a8dc2e..00000000 --- a/backtrace-library/src/androidTest/java/backtraceio/library/ApplicationCacheTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package backtraceio.library; - -import android.content.Context; - -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 ApplicationCacheTest { - 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); - - } - -} diff --git a/backtrace-library/src/androidTest/java/backtraceio/library/ApplicationMetadataTest.java b/backtrace-library/src/androidTest/java/backtraceio/library/ApplicationMetadataTest.java new file mode 100644 index 00000000..ca4e0727 --- /dev/null +++ b/backtrace-library/src/androidTest/java/backtraceio/library/ApplicationMetadataTest.java @@ -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)); + } + +} From 8f58ea5c6352dbf7c3f3457a8fde321c21d9e364 Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Thu, 7 Nov 2024 19:59:15 +0100 Subject: [PATCH 13/15] Update ReportDataBuilder.java --- .../library/models/attributes/ReportDataBuilder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java index 3aa84043..a20cceb0 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java @@ -7,7 +7,7 @@ public class ReportDataBuilder { /** - * Divide custom user attributes into primitive and complex attributes and add to this object. By default nullable values will be included. + * Divide custom user attributes into primitive and complex attributes and add to this object. By default null values will be included. * * @param attributes client's attributes * @return Report data attributes divided into attributes and annotations @@ -20,9 +20,9 @@ public static ReportDataAttributes getReportAttributes(Map attri * Divide custom user attributes into primitive and complex attributes and add to this object * * @param attributes client's attributes - * @param skipNull define attributes behavior on nullable value. By default all nullable attributes + * @param skipNull define attributes behavior on null value. By default all null values * 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. + * null values, because they can generate invalid behavior/incorrect information. * @return Report data attributes divided into attributes and annotations */ public static ReportDataAttributes getReportAttributes(Map attributes, boolean skipNull) { From 1e1660b25fbadb25e396171d664f95bada71cc9c Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Tue, 12 Nov 2024 11:13:59 +0100 Subject: [PATCH 14/15] Pull request updates: private constructor, move singleton method, format files, remove tuple --- .../library/common/ApplicationMetadataCache.java | 12 ++++++------ .../main/java/backtraceio/library/models/Tuple.java | 11 ----------- .../models/attributes/ReportDataAttributes.java | 10 +++++----- .../library/models/attributes/ReportDataBuilder.java | 9 ++++----- 4 files changed, 15 insertions(+), 27 deletions(-) delete mode 100644 backtrace-library/src/main/java/backtraceio/library/models/Tuple.java diff --git a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java index 6b581d95..34637180 100644 --- a/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java +++ b/backtrace-library/src/main/java/backtraceio/library/common/ApplicationMetadataCache.java @@ -27,6 +27,12 @@ public class ApplicationMetadataCache { */ 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. @@ -45,12 +51,6 @@ public static ApplicationMetadataCache getInstance(Context context) { return instance; } - private final Context context; - - public ApplicationMetadataCache(Context context) { - this.context = context; - } - /** * Retrieves application name from context. The name will be cached over checks * diff --git a/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java b/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java deleted file mode 100644 index c25386d4..00000000 --- a/backtrace-library/src/main/java/backtraceio/library/models/Tuple.java +++ /dev/null @@ -1,11 +0,0 @@ -package backtraceio.library.models; - -public class Tuple { - public final T1 first; - public final T2 second; - - public Tuple(T1 first, T2 second) { - this.first = first; - this.second = second; - } -} diff --git a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataAttributes.java b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataAttributes.java index 01189b50..889c82d1 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataAttributes.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataAttributes.java @@ -1,11 +1,12 @@ package backtraceio.library.models.attributes; import java.util.HashMap; +import java.util.Map; public class ReportDataAttributes { - private final HashMap reportAttributes = new HashMap<>(); + private final Map reportAttributes = new HashMap<>(); - private final HashMap reportAnnotations = new HashMap<>(); + private final Map reportAnnotations = new HashMap<>(); public void addAnnotation(String key, Object value) { @@ -16,12 +17,11 @@ public void addAttribute(String key, String value) { reportAttributes.put(key, value); } - public HashMap getAttributes() { + public Map getAttributes() { return reportAttributes; } - public HashMap getAnnotations() { + public Map getAnnotations() { return reportAnnotations; } - } diff --git a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java index a20cceb0..b6922ce2 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/attributes/ReportDataBuilder.java @@ -19,10 +19,10 @@ public static ReportDataAttributes getReportAttributes(Map attri /** * Divide custom user attributes into primitive and complex attributes and add to this object * - * @param attributes client's attributes - * @param skipNull define attributes behavior on null value. By default all null values - * will be included in the report. For some features like metrics, we don't want to send - * null values, because they can generate invalid behavior/incorrect information. + * @param attributes client's attributes + * @param skipNull define attributes behavior on null value. By default all null values + * will be included in the report. For some features like metrics, we don't want to send + * null values, because they can generate invalid behavior/incorrect information. * @return Report data attributes divided into attributes and annotations */ public static ReportDataAttributes getReportAttributes(Map attributes, boolean skipNull) { @@ -49,6 +49,5 @@ public static ReportDataAttributes getReportAttributes(Map attri } return reportDataAttributes; - } } From 7871a13bbe88e45dbea1a8f2617fd440ad9911fc Mon Sep 17 00:00:00 2001 From: Konrad Dysput Date: Tue, 12 Nov 2024 11:25:18 +0100 Subject: [PATCH 15/15] Simplify BacktraceAttributes business logic --- .../library/models/json/BacktraceAttributes.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java index a9e9d34d..ad03bd9b 100644 --- a/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java +++ b/backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java @@ -69,7 +69,7 @@ public BacktraceAttributes(Context context, BacktraceReport report, Map clientAttributes) { - convertAttributes(clientAttributes); - } - /** * Divide report attributes into primitive and complex attributes and add to this object * @@ -205,6 +196,9 @@ private void convertReportAttributes(BacktraceReport report) { } private void convertAttributes(Map clientAttributes) { + if (clientAttributes == null || clientAttributes.isEmpty()) { + return; + } ReportDataAttributes data = ReportDataBuilder.getReportAttributes(clientAttributes); this.attributes.putAll(data.getAttributes()); this.complexAttributes.putAll(data.getAnnotations());