Skip to content

Commit 7524155

Browse files
add ErrorBoundary everywhere (#135)
* add ErrorBoundary everywhere * lint
1 parent a10d7f5 commit 7524155

File tree

9 files changed

+122
-67
lines changed

9 files changed

+122
-67
lines changed

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

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,39 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
1515
val MEDIA_TYPE = "application/json; charset=utf-8".toMediaType()
1616
}
1717

18-
fun <T> swallowSync(task: () -> T) {
18+
fun <T> swallowSync(tag: String, task: () -> T) {
1919
try {
2020
task()
2121
} catch (ex: Throwable) {
22-
onException(ex)
22+
onException(tag, ex)
2323
}
2424
}
2525

26-
suspend fun swallow(task: suspend () -> Unit) {
27-
capture(task) {
26+
suspend fun swallow(tag: String, task: suspend () -> Unit) {
27+
capture(tag, task) {
2828
// no-op
2929
}
3030
}
3131

32-
suspend fun <T> capture(task: suspend () -> T, recover: suspend () -> T): T {
32+
suspend fun <T> capture(tag: String, task: suspend () -> T, recover: suspend () -> T): T {
3333
return try {
3434
task()
3535
} catch (ex: Throwable) {
36-
onException(ex)
36+
onException(tag, ex)
3737
recover()
3838
}
3939
}
4040

41-
fun <T> captureSync(task: () -> T, recover: () -> T): T {
41+
fun <T> captureSync(tag: String, task: () -> T, recover: () -> T): T {
4242
return try {
4343
task()
4444
} catch (ex: Throwable) {
45-
onException(ex)
45+
onException(tag, ex)
4646
recover()
4747
}
4848
}
4949

50-
internal fun logException(ex: Throwable) {
50+
internal fun logException(tag: String, ex: Throwable) {
5151
try {
5252
if (options.localMode || seen.contains(ex.javaClass.name)) {
5353
return
@@ -56,6 +56,7 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
5656
seen.add(ex.javaClass.name)
5757

5858
val body = """{
59+
"tag": "$tag",
5960
"exception": "${ex.javaClass.name}",
6061
"info": "${ex.stackTraceToString()}",
6162
"statsigMetadata": ${StatsigMetadata.asJson()}
@@ -74,7 +75,7 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
7475
}
7576
}
7677

77-
private fun onException(ex: Throwable) {
78+
private fun onException(tag: String, ex: Throwable) {
7879
if (ex is StatsigIllegalStateException ||
7980
ex is StatsigUninitializedException
8081
) {
@@ -84,6 +85,6 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
8485
println("[Statsig]: An unexpected exception occurred.")
8586
println(ex)
8687

87-
logException(ex)
88+
logException(tag, ex)
8889
}
8990
}

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ internal class Evaluator(
3232
private var network: StatsigNetwork,
3333
private var options: StatsigOptions,
3434
private val statsigScope: CoroutineScope,
35+
private val errorBoundary: ErrorBoundary
3536
) {
3637
private var specStore: SpecStore
3738
private var uaParser: Parser = Parser()
@@ -42,7 +43,7 @@ internal class Evaluator(
4243
var isInitialized: Boolean = false
4344
init {
4445
CountryLookup.initialize()
45-
specStore = SpecStore(this.network, this.options, StatsigMetadata(), statsigScope)
46+
specStore = SpecStore(this.network, this.options, StatsigMetadata(), statsigScope, errorBoundary)
4647
}
4748

4849
suspend fun initialize() {
@@ -319,7 +320,9 @@ internal class Evaluator(
319320
if (!condition.type.isNullOrEmpty()) {
320321
conditionEnum = ConfigCondition.valueOf(condition.type.uppercase())
321322
}
322-
} catch (_E: java.lang.IllegalArgumentException) {
323+
} catch (e: java.lang.IllegalArgumentException) {
324+
errorBoundary.logException("evaluateCondition:condition", e)
325+
println("[Statsig]: An exception was caught: $e")
323326
conditionEnum = null
324327
}
325328
when (conditionEnum) {
@@ -621,7 +624,9 @@ internal class Evaluator(
621624
return ConfigEvaluation(fetchFromServer = true)
622625
}
623626
}
624-
} catch (_e: IllegalArgumentException) {
627+
} catch (e: IllegalArgumentException) {
628+
errorBoundary.logException("evaluateCondition:all", e)
629+
println("[Statsig]: An exception was caught: $e")
625630
return ConfigEvaluation(true)
626631
}
627632
}
@@ -693,6 +698,8 @@ internal class Evaluator(
693698
val i = Instant.from(ta)
694699
Date.from(i)
695700
} catch (e: Exception) {
701+
errorBoundary.logException("getDate", e)
702+
println("[Statsig]: An exception was caught: $e")
696703
null
697704
}
698705
}
@@ -747,6 +754,8 @@ internal class Evaluator(
747754
return try {
748755
compare(version1Str, version2Str)
749756
} catch (e: Exception) {
757+
errorBoundary.logException("versionCompareHelper", e)
758+
println("[Statsig]: An exception was caught: $e")
750759
false
751760
}
752761
}

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ internal class SpecStore constructor(
2020
private var options: StatsigOptions,
2121
private var statsigMetadata: StatsigMetadata,
2222
private var statsigScope: CoroutineScope,
23+
private val errorBoundary: ErrorBoundary
2324
) {
2425
private var initTime: Long = 0
2526
private var initReason: EvaluationReason = EvaluationReason.UNINITIALIZED
@@ -97,11 +98,20 @@ internal class SpecStore constructor(
9798
if (options.rulesUpdatedCallback == null) {
9899
return
99100
}
101+
102+
var configString = ""
100103
try {
101-
val configString = gson.toJson(configSpecs)
102-
options.rulesUpdatedCallback?.accept(configString)
104+
configString = gson.toJson(configSpecs)
103105
} catch (e: Exception) {
106+
errorBoundary.logException("fireRulesUpdatedCallback", e)
107+
println("[Statsig]: An exception was caught: $e")
108+
}
109+
110+
if (configString.isEmpty()) {
111+
return
104112
}
113+
114+
options.rulesUpdatedCallback?.accept(configString)
105115
}
106116

107117
private fun pollForChanges(): Flow<APIDownloadedConfigs?> {
@@ -207,7 +217,9 @@ internal class SpecStore constructor(
207217
}
208218
}
209219
list.size = list.size + contentLength
210-
} catch (_: Exception) {
220+
} catch (e: Exception) {
221+
errorBoundary.logException("downloadIDList", e)
222+
println("[Statsig]: An exception was caught: $e")
211223
}
212224
}
213225

@@ -365,7 +377,9 @@ internal class SpecStore constructor(
365377
}
366378
try {
367379
return gson.fromJson(specs, APIDownloadedConfigs::class.java)
368-
} catch (_: Exception) {
380+
} catch (e: Exception) {
381+
errorBoundary.logException("parseConfigSpecs", e)
382+
println("[Statsig]: An exception was caught: $e")
369383
}
370384
return null
371385
}
@@ -383,6 +397,8 @@ internal class SpecStore constructor(
383397
}
384398
return configs
385399
} catch (e: Exception) {
400+
errorBoundary.logException("downloadConfigSpecs", e)
401+
println("[Statsig]: An exception was caught: $e")
386402
}
387403
return null
388404
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.statsig.sdk
22

33
import com.google.gson.Gson
44
import com.google.gson.GsonBuilder
5+
import com.google.gson.JsonParseException
56
import com.google.gson.ToNumberPolicy
67
import com.google.gson.reflect.TypeToken
78
import kotlinx.coroutines.coroutineScope
@@ -26,6 +27,7 @@ internal class StatsigNetwork(
2627
private val sdkKey: String,
2728
private val options: StatsigOptions,
2829
private val statsigMetadata: Map<String, String>,
30+
private val errorBoundary: ErrorBoundary,
2931
private val backoffMultiplier: Int = BACKOFF_MULTIPLIER
3032
) {
3133
private val retryCodes: Set<Int> = setOf(
@@ -157,7 +159,7 @@ internal class StatsigNetwork(
157159
headers: Map<String, String> = emptyMap(),
158160
): Response? {
159161
try {
160-
var request = Request.Builder()
162+
val request = Request.Builder()
161163
.url(url)
162164
if (body != null) {
163165
val bodyJson = gson.toJson(body)
@@ -166,6 +168,10 @@ internal class StatsigNetwork(
166168
headers.forEach { (key, value) -> request.addHeader(key, value) }
167169
return client.newCall(request.build()).await()
168170
} catch (e: Exception) {
171+
println("[Statsig]: An exception was caught: $e")
172+
if (e is JsonParseException) {
173+
errorBoundary.logException("postImpl", e)
174+
}
169175
return null
170176
}
171177
}
@@ -202,7 +208,11 @@ internal class StatsigNetwork(
202208
return@coroutineScope
203209
}
204210
}
205-
} catch (_: Exception) {
211+
} catch (e: Exception) {
212+
println("[Statsig]: An exception was caught: $e")
213+
if (e is JsonParseException) {
214+
errorBoundary.logException("retryPostLogs", e)
215+
}
206216
}
207217

208218
val count = retries - --currRetry

0 commit comments

Comments
 (0)