Skip to content

Commit

Permalink
Add Event to Track Number of Non Exposed Checks (#194)
Browse files Browse the repository at this point in the history
* Add Event to Track Number of Non Exposed Checks

* update

* include layers and flush

* update

* update

* update tests

* update
  • Loading branch information
sroyal-statsig authored Mar 5, 2024
1 parent 8e7780d commit 1f87006
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 3 deletions.
10 changes: 10 additions & 0 deletions src/main/java/com/statsig/androidsdk/Statsig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,16 @@ object Statsig {
}
}

/**
* Flushes all events to the Statsig servers
* @throws IllegalStateException if the SDK has not been initialized
*/
@JvmStatic
suspend fun flush() {
enforceInitialized("flush")
client.flush()
}

/**
* @return If SDK is initialized, initialized is set to true when SDK basic functionality is setup,
* and become usable. SDK use the same function to enforce initialize for other functions.
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/statsig/androidsdk/StatsigClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ class StatsigClient() : LifecycleEventListener {
enforceInitialized(functionName)
var result = false
errorBoundary.capture({
this.logger.addNonExposedCheck(gateName)
val gate = store.checkGate(gateName)
result = gate.value
}, tag = functionName, configName = gateName)
Expand Down Expand Up @@ -209,6 +210,7 @@ class StatsigClient() : LifecycleEventListener {
enforceInitialized(functionName)
var result: DynamicConfig? = null
errorBoundary.capture({
this.logger.addNonExposedCheck(configName)
result = store.getConfig(configName)
}, tag = functionName, configName = configName)
return result ?: DynamicConfig.getUninitialized(configName)
Expand Down Expand Up @@ -251,6 +253,7 @@ class StatsigClient() : LifecycleEventListener {
enforceInitialized(functionName)
var exp: DynamicConfig? = null
errorBoundary.capture({
this.logger.addNonExposedCheck(experimentName)
exp = store.getExperiment(experimentName, keepDeviceValue)
updateStickyValues()
}, configName = experimentName, tag = functionName)
Expand Down Expand Up @@ -293,6 +296,7 @@ class StatsigClient() : LifecycleEventListener {
enforceInitialized(functionName)
var layer: Layer? = null
errorBoundary.capture({
this.logger.addNonExposedCheck(layerName)
layer = store.getLayer(null, layerName, keepDeviceValue)
updateStickyValues()
}, tag = functionName, configName = layerName)
Expand Down Expand Up @@ -448,6 +452,13 @@ class StatsigClient() : LifecycleEventListener {
}
}

suspend fun flush() {
enforceInitialized("flush")
errorBoundary.captureAsync {
this.logger.flush()
}
}

/**
* @param gateName the name of the gate you want to override
* @param value the result to be returned when checkGate is called
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/statsig/androidsdk/StatsigLogger.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal const val CONFIG_EXPOSURE = "statsig::config_exposure"
internal const val LAYER_EXPOSURE = "statsig::layer_exposure"
internal const val GATE_EXPOSURE = "statsig::gate_exposure"
internal const val DIAGNOSTICS_EVENT = "statsig::diagnostics"
internal const val NON_EXPOSED_CHECKS_EVENT = "statsig::non_exposed_checks"

internal data class LogEventData(
@SerializedName("events") val events: ArrayList<LogEvent>,
Expand Down Expand Up @@ -46,6 +47,7 @@ internal class StatsigLogger(

private var events = ConcurrentLinkedQueue<LogEvent>()
private var loggedExposures = ConcurrentHashMap<String, Long>()
private var nonExposedChecks = ConcurrentHashMap<String, Long>()

suspend fun log(event: LogEvent) {
withContext(singleThreadDispatcher) {
Expand All @@ -65,6 +67,7 @@ internal class StatsigLogger(
suspend fun flush() {
withContext(singleThreadDispatcher) {
addErrorBoundaryDiagnostics()
addNonExposedChecksEvent()
if (events.size == 0) {
return@withContext
}
Expand Down Expand Up @@ -212,6 +215,11 @@ internal class StatsigLogger(
return true
}

fun addNonExposedCheck(configName: String) {
val count = nonExposedChecks[configName] ?: 0
nonExposedChecks[configName] = count + 1
}

private fun makeDiagnosticsEvent(context: ContextType, markers: Collection<Marker>): LogEvent {
// Need to verify if the JSON is in the right format for log event
val event = LogEvent(DIAGNOSTICS_EVENT)
Expand All @@ -220,6 +228,16 @@ internal class StatsigLogger(
return event
}

private fun addNonExposedChecksEvent() {
if (nonExposedChecks.isEmpty()) {
return
}
val event = LogEvent(NON_EXPOSED_CHECKS_EVENT)
event.metadata = mapOf("checks" to gson.toJson(nonExposedChecks))
this.events.add(event)
nonExposedChecks.clear()
}

private fun addErrorBoundaryDiagnostics() {
val markers = diagnostics.getMarkers(ContextType.API_CALL)
if (markers.isEmpty()) {
Expand Down
8 changes: 6 additions & 2 deletions src/test/java/com/statsig/androidsdk/LayerExposureTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,10 @@ class LayerExposureTest {
layer.getInt("an_int", 0)
Statsig.shutdown()

assertNull(logs)
val logs = logs!!

assertEquals(1, logs.events.count())
assertEquals("statsig::non_exposed_checks", logs.events[0].eventName)
}

@Test
Expand All @@ -299,14 +302,15 @@ class LayerExposureTest {
Statsig.shutdown()

val logs = logs!!
assertEquals(1, logs.events.count())
assertEquals(2, logs.events.count())

assertEquals(
Gson().toJson(mapOf("userID" to "dloomb", "email" to "[email protected]")),
Gson().toJson(logs.events[0].user),
)
assertEquals("statsig::layer_exposure", logs.events[0].eventName)
assertEquals("true", logs.events[0].metadata!!["isManualExposure"])
assertEquals("statsig::non_exposed_checks", logs.events[1].eventName)
}

private fun start(layers: Map<String, APIDynamicConfig>, user: StatsigUser = StatsigUser(userID = "jkw")) {
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/com/statsig/androidsdk/StatsigTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class StatsigTest {
client.shutdown()

var parsedLogs = Gson().fromJson(flushedLogs, LogEventData::class.java)
assertEquals(14, parsedLogs.events.count())
assertEquals(15, parsedLogs.events.count())
// first 2 are exposures pre initialize() completion
assertEquals("custom_stable_id", parsedLogs.statsigMetadata.stableID)
assertEquals("Android", parsedLogs.statsigMetadata.systemName)
Expand Down

0 comments on commit 1f87006

Please sign in to comment.