Skip to content

Commit

Permalink
feat(android): implement custom events with user defined attrs
Browse files Browse the repository at this point in the history
* implement custom events
* add sessions with custom events
  • Loading branch information
abhaysood committed Dec 19, 2024
1 parent 9cffcbc commit db3ca25
Show file tree
Hide file tree
Showing 59 changed files with 891,508 additions and 739 deletions.
112 changes: 112 additions & 0 deletions android/measure/api/measure.api
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,125 @@ public final class sh/measure/android/Measure {
public final fun startSpan (Ljava/lang/String;)Lsh/measure/android/tracing/Span;
public final fun startSpan (Ljava/lang/String;J)Lsh/measure/android/tracing/Span;
public final fun stop ()V
public final fun trackEvent (Ljava/lang/String;Ljava/util/Map;Ljava/lang/Long;)V
public static synthetic fun trackEvent$default (Lsh/measure/android/Measure;Ljava/lang/String;Ljava/util/Map;Ljava/lang/Long;ILjava/lang/Object;)V
public static final fun trackHandledException (Ljava/lang/Throwable;)V
public static final fun trackNavigation (Ljava/lang/String;)V
public static final fun trackNavigation (Ljava/lang/String;Ljava/lang/String;)V
public static synthetic fun trackNavigation$default (Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)V
public static final fun trackScreenView (Ljava/lang/String;)V
}

public abstract interface class sh/measure/android/attributes/AttributeValue {
public static final field Companion Lsh/measure/android/attributes/AttributeValue$Companion;
public abstract fun getValue ()Ljava/lang/Object;
}

public final class sh/measure/android/attributes/AttributeValue$Companion {
}

public final class sh/measure/android/attributes/AttributesBuilder {
public static final field $stable I
public fun <init> ()V
public final fun build ()Ljava/util/Map;
public final fun put (Ljava/lang/String;D)Lsh/measure/android/attributes/AttributesBuilder;
public final fun put (Ljava/lang/String;F)Lsh/measure/android/attributes/AttributesBuilder;
public final fun put (Ljava/lang/String;I)Lsh/measure/android/attributes/AttributesBuilder;
public final fun put (Ljava/lang/String;J)Lsh/measure/android/attributes/AttributesBuilder;
public final fun put (Ljava/lang/String;Ljava/lang/String;)Lsh/measure/android/attributes/AttributesBuilder;
public final fun put (Ljava/lang/String;Z)Lsh/measure/android/attributes/AttributesBuilder;
}

public final class sh/measure/android/attributes/BooleanAttr : sh/measure/android/attributes/AttributeValue {
public static final synthetic fun box-impl (Z)Lsh/measure/android/attributes/BooleanAttr;
public static fun constructor-impl (Z)Z
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (ZLjava/lang/Object;)Z
public static final fun equals-impl0 (ZZ)Z
public fun getValue ()Ljava/lang/Boolean;
public synthetic fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public static fun hashCode-impl (Z)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (Z)Ljava/lang/String;
public final synthetic fun unbox-impl ()Z
}

public final class sh/measure/android/attributes/DoubleAttr : sh/measure/android/attributes/AttributeValue {
public static final synthetic fun box-impl (D)Lsh/measure/android/attributes/DoubleAttr;
public static fun constructor-impl (D)D
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (DLjava/lang/Object;)Z
public static final fun equals-impl0 (DD)Z
public fun getValue ()Ljava/lang/Double;
public synthetic fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public static fun hashCode-impl (D)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (D)Ljava/lang/String;
public final synthetic fun unbox-impl ()D
}

public final class sh/measure/android/attributes/FloatAttr : sh/measure/android/attributes/AttributeValue {
public static final synthetic fun box-impl (F)Lsh/measure/android/attributes/FloatAttr;
public static fun constructor-impl (F)F
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (FLjava/lang/Object;)Z
public static final fun equals-impl0 (FF)Z
public fun getValue ()Ljava/lang/Float;
public synthetic fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public static fun hashCode-impl (F)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (F)Ljava/lang/String;
public final synthetic fun unbox-impl ()F
}

public final class sh/measure/android/attributes/IntAttr : sh/measure/android/attributes/AttributeValue {
public static final synthetic fun box-impl (I)Lsh/measure/android/attributes/IntAttr;
public static fun constructor-impl (I)I
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (ILjava/lang/Object;)Z
public static final fun equals-impl0 (II)Z
public fun getValue ()Ljava/lang/Integer;
public synthetic fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public static fun hashCode-impl (I)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (I)Ljava/lang/String;
public final synthetic fun unbox-impl ()I
}

public final class sh/measure/android/attributes/LongAttr : sh/measure/android/attributes/AttributeValue {
public static final synthetic fun box-impl (J)Lsh/measure/android/attributes/LongAttr;
public static fun constructor-impl (J)J
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (JLjava/lang/Object;)Z
public static final fun equals-impl0 (JJ)Z
public fun getValue ()Ljava/lang/Long;
public synthetic fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public static fun hashCode-impl (J)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (J)Ljava/lang/String;
public final synthetic fun unbox-impl ()J
}

public final class sh/measure/android/attributes/StringAttr : sh/measure/android/attributes/AttributeValue {
public static final synthetic fun box-impl (Ljava/lang/String;)Lsh/measure/android/attributes/StringAttr;
public static fun constructor-impl (Ljava/lang/String;)Ljava/lang/String;
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (Ljava/lang/String;Ljava/lang/Object;)Z
public static final fun equals-impl0 (Ljava/lang/String;Ljava/lang/String;)Z
public synthetic fun getValue ()Ljava/lang/Object;
public fun getValue ()Ljava/lang/String;
public fun hashCode ()I
public static fun hashCode-impl (Ljava/lang/String;)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (Ljava/lang/String;)Ljava/lang/String;
public final synthetic fun unbox-impl ()Ljava/lang/String;
}

public final class sh/measure/android/config/MeasureConfig : sh/measure/android/config/IMeasureConfig {
public static final field $stable I
public fun <init> ()V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -620,10 +620,42 @@ class EventsTest {
// Implementation would go here if we could reliably trigger trim memory in tests
}

@Test
fun tracksCustomEvent() {
// Given
robot.initializeMeasure(MeasureConfig(enableLogging = true))
ActivityScenario.launch(TestActivity::class.java).use {
// When
robot.trackCustomEvent()
triggerExport()

// Then
assertEventTracked(EventType.CUSTOM)
}
}

@Test
fun tracksAttributesWithEvents() {
// Given
robot.initializeMeasure(MeasureConfig(enableLogging = true))
ActivityScenario.launch(TestActivity::class.java).use {
// When
robot.addAttribute("user_defined_attr_key", "user_defined_attr_value")
triggerExport()

// Then
assetAttribute("user_defined_attr_key", "user_defined_attr_value")
}
}

private fun String.containsEvent(eventType: String): Boolean {
return contains("\"type\":\"$eventType\"")
}

private fun String.containsAttribute(key: String, value: String): Boolean {
return contains("\"$key\":\"$value\"")
}

private fun triggerExport() {
Measure.simulateAppCrash(
type = EventType.EXCEPTION,
Expand Down Expand Up @@ -675,6 +707,11 @@ class EventsTest {
Assert.assertFalse(body.containsEvent(eventType))
}

private fun assetAttribute(key: String, value: String) {
val body = getLastRequestBody()
Assert.assertTrue(body.containsAttribute(key, value))
}

private fun getLastRequestBody(): String {
val request = mockWebServer.takeRequest(timeout = 1000, unit = TimeUnit.MILLISECONDS)
Assert.assertNotNull(request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.test.uiautomator.By
import androidx.test.uiautomator.Direction
import androidx.test.uiautomator.UiDevice
import okhttp3.Headers
import sh.measure.android.attributes.AttributesBuilder
import sh.measure.android.config.MeasureConfig

/**
Expand Down Expand Up @@ -88,9 +89,9 @@ class EventsTestRobot {
if (network != null) {
val capabilities = connectivityManager.getNetworkCapabilities(network)
return capabilities != null && (
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || capabilities.hasTransport(
NetworkCapabilities.TRANSPORT_CELLULAR,
) || capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
)
}
return false
Expand All @@ -117,4 +118,17 @@ class EventsTestRobot {
RuntimeException("Test exception"),
)
}

fun trackCustomEvent() {
Measure.trackEvent(
"custom_event",
AttributesBuilder().apply {
"custom_event_key" to "custom_event_value"
}.build(),
)
}

fun addAttribute(key: String, value: String) {
Measure.addAttribute("user_defined_attr_key", "user_defined_attr_value")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ class FakeConfigProvider : ConfigProvider {
override var defaultHttpHeadersBlocklist: List<String> = emptyList()
override var sessionEndLastEventThresholdMs: Long = 1_000_000
override var maxSessionDurationMs: Long = 6_000_000
override var maxUserDefinedAttributeKeyLength: Int = 1_000_000
override var maxUserDefinedAttributeValueLength: Int = 1_000_000
override var userDefinedAttributeKeyWithSpaces: Boolean = true
override var maxEventNameLength: Int = 64
override val customEventNameRegex: String = "^[a-zA-Z0-9_-]+\$"
override val maxUserDefinedAttributesPerEvent: Int = 100
override var maxUserDefinedAttributeKeyLength: Int = 64
override var maxUserDefinedAttributeValueLength: Int = 256
override var screenshotMaskHexColor: String = "#222222"
override var screenshotCompressionQuality: Int = 100
override var eventTypeExportAllowList: List<String> = emptyList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,6 @@ internal class TestMeasureInitializer(
override val userDefinedAttribute: UserDefinedAttribute = UserDefinedAttributeImpl(
logger,
configProvider,
database,
executorServiceRegistry.ioExecutor(),
),
override val userAttributeProcessor: UserAttributeProcessor = UserAttributeProcessor(
logger,
Expand Down
Loading

0 comments on commit db3ca25

Please sign in to comment.