Skip to content

Commit 826e736

Browse files
Merge pull request #190 from statsig-io/more_logging
Log statsigoptions and configname
2 parents 588ea2e + 9127abc commit 826e736

File tree

6 files changed

+51
-25
lines changed

6 files changed

+51
-25
lines changed

src/main/kotlin/com/statsig/sdk/ErrorBoundary.kt

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.statsig.sdk
22

3+
import com.google.gson.Gson
34
import okhttp3.MediaType.Companion.toMediaType
45
import okhttp3.OkHttpClient
56
import okhttp3.Request
@@ -27,30 +28,30 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
2728
}
2829

2930
suspend fun swallow(tag: String, task: suspend () -> Unit) {
30-
capture(tag, task) {
31-
// no-op
32-
}
31+
capture(tag, task, {
32+
// no op
33+
})
3334
}
3435

35-
suspend fun <T> capture(tag: String, task: suspend () -> T, recover: suspend () -> T): T {
36+
suspend fun <T> capture(tag: String, task: suspend () -> T, recover: suspend () -> T, configName: String? = null): T {
3637
return try {
3738
task()
3839
} catch (ex: Throwable) {
39-
onException(tag, ex)
40+
onException(tag, ex, configName)
4041
recover()
4142
}
4243
}
4344

44-
fun <T> captureSync(tag: String, task: () -> T, recover: () -> T): T {
45+
fun <T> captureSync(tag: String, task: () -> T, recover: () -> T, configName: String? = null): T {
4546
return try {
4647
task()
4748
} catch (ex: Throwable) {
48-
onException(tag, ex)
49+
onException(tag, ex, configName)
4950
recover()
5051
}
5152
}
5253

53-
internal fun logException(tag: String, ex: Throwable) {
54+
internal fun logException(tag: String, ex: Throwable, configName: String? = null) {
5455
try {
5556
if (options.localMode || seen.contains(ex.javaClass.name)) {
5657
return
@@ -63,12 +64,14 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
6364
if (safeInfo.length > maxInfoLength) {
6465
safeInfo = safeInfo.substring(0, maxInfoLength)
6566
}
66-
67+
val optionsCopy = Gson().toJson(options.getLoggingCopy())
6768
val body = """{
6869
"tag": "$tag",
6970
"exception": "${ex.javaClass.name}",
7071
"info": "$safeInfo",
71-
"statsigMetadata": ${statsigMetadata.asJson()}
72+
"statsigMetadata": ${statsigMetadata.asJson()},
73+
"configName": "$configName",
74+
"setupOptions": $optionsCopy
7275
}
7376
""".trimIndent()
7477
val req =
@@ -84,7 +87,7 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
8487
}
8588
}
8689

87-
private fun onException(tag: String, ex: Throwable) {
90+
private fun onException(tag: String, ex: Throwable, configName: String? = null) {
8891
if (ex is StatsigIllegalStateException ||
8992
ex is StatsigUninitializedException
9093
) {
@@ -94,6 +97,6 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
9497
println("[Statsig]: An unexpected exception occurred.")
9598
println(ex)
9699

97-
logException(tag, ex)
100+
logException(tag, ex, configName)
98101
}
99102
}

src/main/kotlin/com/statsig/sdk/StatsigLogger.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ internal class StatsigLogger(
3434
private val coroutineScope: CoroutineScope,
3535
private val network: StatsigNetwork,
3636
private val statsigMetadata: StatsigMetadata,
37+
private val statsigOptions: StatsigOptions,
3738
) {
3839

3940
private val executor = Executors.newSingleThreadExecutor()
@@ -131,7 +132,11 @@ internal class StatsigLogger(
131132

132133
fun logDiagnostics(context: ContextType, markers: Collection<Marker>) {
133134
val event = StatsigEvent(DIAGNOSTICS_EVENT)
134-
event.eventMetadata = mapOf("context" to context.toString().lowercase(), "markers" to gson.toJson(markers))
135+
event.eventMetadata = mapOf(
136+
"context" to context.toString().lowercase(),
137+
"markers" to gson.toJson(markers),
138+
"statsigOptions" to gson.toJson(statsigOptions.getLoggingCopy()),
139+
)
135140
log(event)
136141
}
137142

src/main/kotlin/com/statsig/sdk/StatsigOptions.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,17 @@ class StatsigOptions(
5151
fun getEnvironment(): MutableMap<String, String>? {
5252
return environment
5353
}
54+
55+
fun getLoggingCopy(): Map<String, Any> {
56+
return mapOf(
57+
"api" to (api ?: "DEFAULT"),
58+
"initTimeoutMs" to initTimeoutMs,
59+
"localMode" to localMode,
60+
"disableDiagnostics" to disableDiagnostics,
61+
"rulesetsSyncIntervalMs" to rulesetsSyncIntervalMs,
62+
"idListsSyncIntervalMs" to idListsSyncIntervalMs,
63+
"setDataStore" to (dataStore != null),
64+
"setBootstrapValues" to (bootstrapValues != null),
65+
)
66+
}
5467
}

src/main/kotlin/com/statsig/sdk/StatsigServer.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ private class StatsigServerImpl() :
204204
statsigJob = SupervisorJob()
205205
statsigScope = CoroutineScope(statsigJob + coroutineExceptionHandler)
206206
network = StatsigNetwork(serverSecret, options, statsigMetadata, errorBoundary)
207-
logger = StatsigLogger(statsigScope, network, statsigMetadata)
207+
logger = StatsigLogger(statsigScope, network, statsigMetadata, options)
208208
this.options = options
209209
}
210210

@@ -244,14 +244,14 @@ private class StatsigServerImpl() :
244244
logGateExposureImpl(user, gateName, result)
245245
}
246246
return@capture result.booleanValue
247-
}, { return@capture false })
247+
}, { return@capture false }, configName = gateName)
248248
}
249249

250250
override suspend fun checkGateWithExposureLoggingDisabled(user: StatsigUser, gateName: String): Boolean {
251251
return errorBoundary.capture("checkGateWithExposureLoggingDisabled", {
252252
val result = checkGateImpl(user, gateName)
253253
return@capture result.booleanValue
254-
}, { return@capture false })
254+
}, { return@capture false }, configName = gateName)
255255
}
256256

257257
private suspend fun checkGateImpl(user: StatsigUser, gateName: String): ConfigEvaluation {
@@ -298,7 +298,7 @@ private class StatsigServerImpl() :
298298
return@capture getDynamicConfigFromEvalResult(result, user, dynamicConfigName)
299299
}, {
300300
return@capture DynamicConfig.empty(dynamicConfigName)
301-
})
301+
}, configName = dynamicConfigName)
302302
}
303303

304304
override suspend fun getConfigWithExposureLoggingDisabled(user: StatsigUser, dynamicConfigName: String): DynamicConfig {
@@ -311,7 +311,7 @@ private class StatsigServerImpl() :
311311
return@capture getDynamicConfigFromEvalResult(result, normalizedUser, dynamicConfigName)
312312
}, {
313313
return@capture DynamicConfig.empty(dynamicConfigName)
314-
})
314+
}, configName = dynamicConfigName)
315315
}
316316

317317
override suspend fun manuallyLogConfigExposure(user: StatsigUser, configName: String) {
@@ -330,7 +330,7 @@ private class StatsigServerImpl() :
330330
return@capture getConfig(user, experimentName)
331331
}, {
332332
return@capture DynamicConfig.empty(experimentName)
333-
})
333+
}, configName = experimentName)
334334
}
335335

336336
override suspend fun getExperimentWithExposureLoggingDisabled(
@@ -346,7 +346,7 @@ private class StatsigServerImpl() :
346346
return@capture getDynamicConfigFromEvalResult(result, user, experimentName)
347347
}, {
348348
return@capture DynamicConfig.empty(experimentName)
349-
})
349+
}, configName = experimentName)
350350
}
351351

352352
override suspend fun getExperimentInLayerForUser(
@@ -383,23 +383,23 @@ private class StatsigServerImpl() :
383383
return@capture DynamicConfig.empty()
384384
}, {
385385
return@capture DynamicConfig.empty()
386-
})
386+
}, configName = layerName)
387387
}
388388

389389
override suspend fun getLayer(user: StatsigUser, layerName: String): Layer {
390390
return this.errorBoundary.capture("getLayer", {
391391
return@capture getLayerImpl(user, layerName, false)
392392
}, {
393393
return@capture Layer.empty(layerName)
394-
})
394+
}, configName = layerName)
395395
}
396396

397397
override suspend fun getLayerWithExposureLoggingDisabled(user: StatsigUser, layerName: String): Layer {
398398
return this.errorBoundary.capture("getLayerWithExposureLoggingDisabled", {
399399
return@capture getLayerImpl(user, layerName, true)
400400
}, {
401401
return@capture Layer.empty(layerName)
402-
})
402+
}, configName = layerName)
403403
}
404404

405405
override fun getClientInitializeResponse(

src/test/java/com/statsig/sdk/DiagnosticsTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.google.gson.Gson
44
import com.google.gson.GsonBuilder
55
import com.google.gson.ToNumberPolicy
66
import com.google.gson.reflect.TypeToken
7+
import junit.framework.Assert.assertEquals
78
import kotlinx.coroutines.CompletableDeferred
89
import kotlinx.coroutines.runBlocking
910
import okhttp3.mockwebserver.Dispatcher
@@ -55,6 +56,7 @@ class DiagnosticsTest {
5556
verifyMarker(markers[5], Marker(key = KeyType.GET_ID_LIST_SOURCES, action = ActionType.START, step = StepType.NETWORK_REQUEST))
5657
verifyMarker(markers[6], Marker(key = KeyType.GET_ID_LIST_SOURCES, action = ActionType.END, step = StepType.NETWORK_REQUEST))
5758
verifyMarker(markers[7], Marker(key = KeyType.OVERALL, action = ActionType.END))
59+
assertEquals(Gson().toJson(options.getLoggingCopy()), diagnosticsEvent!!.eventMetadata!!["statsigOptions"])
5860
}
5961

6062
@Test

src/test/java/com/statsig/sdk/ErrorBoundaryTest.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class ErrorBoundaryTest {
2121
private lateinit var boundary: ErrorBoundary
2222
private lateinit var server: MockWebServer
2323
private lateinit var statsigMetadata: StatsigMetadata
24+
private lateinit var options: StatsigOptions
2425

2526
@Before
2627
internal fun setup() {
@@ -33,7 +34,8 @@ class ErrorBoundaryTest {
3334
}
3435
}
3536
statsigMetadata = StatsigMetadata()
36-
boundary = ErrorBoundary("secret-key", StatsigOptions(), statsigMetadata)
37+
options = StatsigOptions(idListsSyncIntervalMs = 4000)
38+
boundary = ErrorBoundary("secret-key", options, statsigMetadata)
3739
boundary.uri = server.url("/v1/sdk_exception").toUri()
3840
}
3941

@@ -72,11 +74,12 @@ class ErrorBoundaryTest {
7274
}
7375

7476
@Test
75-
fun testLogsStatsigMetadata() = runBlocking {
77+
fun testLogsStatsigMetadataAndOptions() = runBlocking {
7678
boundary.swallow("") { throw IOException() }
7779

7880
val body = Gson().fromJson(server.takeRequest().body.readUtf8(), Map::class.java)
7981
assertEquals(body["statsigMetadata"], Gson().fromJson(statsigMetadata.asJson(), Map::class.java))
82+
assertEquals(Gson().fromJson(Gson().toJson(options.getLoggingCopy()), Map::class.java), body["setupOptions"])
8083
}
8184

8285
@Test

0 commit comments

Comments
 (0)