Skip to content
22 changes: 22 additions & 0 deletions app/src/org/commcare/adapters/EntityStringFilterer.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package org.commcare.adapters;


import com.google.firebase.perf.metrics.Trace;

import androidx.appcompat.app.AppCompatActivity;

import org.commcare.CommCareApplication;
import org.commcare.cases.entity.Entity;
import org.commcare.cases.entity.NodeEntityFactory;
import org.commcare.google.services.analytics.CCPerfMonitoring;
import org.commcare.models.database.IDatabase;
import org.commcare.modern.util.Pair;
import org.commcare.util.EntitySortUtil;
import org.commcare.utils.SessionUnavailableException;
import org.commcare.utils.StringUtils;
import org.javarosa.core.model.instance.TreeReference;
import org.javarosa.core.services.Logger;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;


/**
Expand Down Expand Up @@ -46,6 +54,7 @@ public EntityStringFilterer(EntityListAdapter adapter,
@Override
protected void filter() {
long startTime = System.currentTimeMillis();
Trace trace = CCPerfMonitoring.INSTANCE.startTracing(CCPerfMonitoring.TRACE_CASE_SEARCH_TIME);

if (!isFilterEmpty) {
buildMatchList();
Expand All @@ -55,6 +64,19 @@ protected void filter() {
return;
}

// If cancelled, the tracing is not to be stopped and Firebase is supposed to discard it
if (!isFilterEmpty && (fullEntityList != null && !fullEntityList.isEmpty())) {
try {
Map<String, String> attrs = new HashMap<>();
attrs.put(CCPerfMonitoring.ATTR_RESULTS_COUNT,
String.valueOf((matchList == null ? 0 : matchList.size())));
attrs.put(CCPerfMonitoring.ATTR_SEARCH_QUERY_LENGTH,
String.valueOf(StringUtils.getSumOfLengths(searchTerms)));
attrs.put(CCPerfMonitoring.ATTR_NUM_CASES_LOADED, String.valueOf(fullEntityList.size()));
CCPerfMonitoring.INSTANCE.stopTracing(trace, attrs);
} catch (Exception ignored) {}
}

long time = System.currentTimeMillis() - startTime;
if (time > 1000) {
Logger.log("cache", "Presumably finished caching new entities, time taken: " + time + "ms");
Expand Down
16 changes: 10 additions & 6 deletions app/src/org/commcare/google/services/analytics/CCPerfMonitoring.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,34 @@ object CCPerfMonitoring {
// Traces
// Measures the duration of synchronous case list loading
const val TRACE_SYNC_ENTITY_LIST_LOADING = "sync_case_list_loading"
const val TRACE_CASE_SEARCH_TIME = "case_search_time"

// Attributes
const val ATTR_NUM_CASES_LOADED = "number_of_cases_loaded"
const val ATTR_RESULTS_COUNT: String = "case_search_results_count"
const val ATTR_SEARCH_QUERY_LENGTH: String = "case_search_query_length"

fun startTracing (traceName: String): Trace? {
fun startTracing(traceName: String): Trace? {
try {
val trace = FirebasePerformance.getInstance().newTrace(traceName)
trace.putAttribute(CCAnalyticsParam.CCHQ_DOMAIN, ReportingUtils.getDomain())
trace.putAttribute(CCAnalyticsParam.CC_APP_ID, ReportingUtils.getAppId())
trace.putAttribute(CCAnalyticsParam.CC_APP_NAME, ReportingUtils.getAppName())
trace.putAttribute(CCAnalyticsParam.USERNAME, ReportingUtils.getUser())
trace.start();
trace.start()
return trace
} catch (exception: Exception) {
Logger.exception("Error starting perf trace: $traceName", exception)
}
return null
}

fun stopTracing(trace: Trace?) {
fun stopTracing(trace: Trace, attrs: MutableMap<String, String>?) {
try {
trace?.stop();
attrs?.forEach { (key, value) -> trace.putAttribute(key, value) }
trace.stop()
} catch (exception: Exception) {
Logger.exception("Error starting perf trace: ${trace?.name}", exception)
Logger.exception("Error stopping perf trace: ${trace.name}", exception)
}
}
}
}
13 changes: 9 additions & 4 deletions app/src/org/commcare/tasks/EntityLoaderTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import org.javarosa.core.services.Logger;
import org.javarosa.xpath.XPathException;

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

import javax.annotation.Nullable;

Expand Down Expand Up @@ -61,10 +63,13 @@ protected Pair<List<Entity<TreeReference>>, List<TreeReference>> doInBackground(
Pair<List<Entity<TreeReference>>, List<TreeReference>> entities = entityLoaderHelper.loadEntities(
nodeset[0], this);

if (trace != null && !entityLoaderHelper.isAsyncNodeEntityFactory()) {
trace.putAttribute(CCPerfMonitoring.ATTR_NUM_CASES_LOADED,
String.valueOf((entities == null || entities.first == null ? 0 : entities.first.size())));
CCPerfMonitoring.INSTANCE.stopTracing(trace);
if (!entityLoaderHelper.isAsyncNodeEntityFactory()) {
try {
Map<String, String> attrs = new HashMap<>();
attrs.put(CCPerfMonitoring.ATTR_NUM_CASES_LOADED,
String.valueOf((entities == null || entities.first == null ? 0 : entities.first.size())));
CCPerfMonitoring.INSTANCE.stopTracing(trace, attrs);
} catch (Exception ignored) {}
}
return entities;
} catch (XPathException xe) {
Expand Down
13 changes: 13 additions & 0 deletions app/src/org/commcare/utils/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ public static Spannable getStringSpannableRobust(Context c, int resId, String ar
return MarkupUtil.styleSpannable(c, ret);
}

/**
* Returns the total length of all strings in the array.
*/
public static int getSumOfLengths(String[] array) {
int total = 0;
for (String s : array) {
if (s != null) {
total += s.length();
}
}
return total;
}

public static String getLocalizedLevel(String levelCode, Context context) {
return switch (levelCode) {
case "1MON_ACTIVE" -> context.getString(R.string.personalid_work_history_level_1_month_active);
Expand Down
Loading