Skip to content

Commit 442490b

Browse files
Add custom logger (#203)
https://linear.app/statsig/issue/SDK-86/custom-logger-for-java-server Replace println() with a callback, default still prints out to console
1 parent 7b8b8cb commit 442490b

File tree

10 files changed

+73
-14
lines changed

10 files changed

+73
-14
lines changed

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
102102
throw ex
103103
}
104104

105-
println("[Statsig]: An unexpected exception occurred.")
106-
println(ex)
105+
options.customLogger.warning("[Statsig]: An unexpected exception occurred: $ex")
107106

108107
logException(tag, ex, configName)
109108
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ internal class Evaluator(
374374
conditionFromString(condition.type)
375375
} catch (e: java.lang.IllegalArgumentException) {
376376
errorBoundary.logException("evaluateCondition:condition", e)
377-
println("[Statsig]: An exception was caught: $e")
377+
options.customLogger.warning("[Statsig]: An exception was caught: $e")
378378
null
379379
}
380380

@@ -872,7 +872,7 @@ internal class Evaluator(
872872
false
873873
} catch (e: Exception) {
874874
errorBoundary.logException("versionCompareHelper", e)
875-
println("[Statsig]: An exception was caught: $e")
875+
options.customLogger.warning("[Statsig]: An exception was caught: $e")
876876
false
877877
}
878878
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ internal class SpecStore constructor(
109109
configString = gson.toJson(configSpecs)
110110
} catch (e: Exception) {
111111
errorBoundary.logException("fireRulesUpdatedCallback", e)
112-
println("[Statsig]: An exception was caught: $e")
112+
options.customLogger.warning("[Statsig]: An exception was caught: $e")
113113
}
114114

115115
if (configString.isEmpty()) {
@@ -241,7 +241,7 @@ internal class SpecStore constructor(
241241
diagnostics.markEnd(KeyType.GET_ID_LIST, true, StepType.PROCESS, additionalMarker = Marker(url = list.url))
242242
} catch (e: Exception) {
243243
errorBoundary.logException("downloadIDList", e)
244-
println("[Statsig]: An exception was caught: $e")
244+
options.customLogger.warning("[Statsig]: An exception was caught: $e")
245245
diagnostics.markEnd(KeyType.GET_ID_LIST, false, StepType.NETWORK_REQUEST, additionalMarker = Marker(url = list.url))
246246
} finally {
247247
response?.close()
@@ -431,7 +431,7 @@ internal class SpecStore constructor(
431431
return gson.fromJson(specs, APIDownloadedConfigs::class.java)
432432
} catch (e: Exception) {
433433
errorBoundary.logException("parseConfigSpecs", e)
434-
println("[Statsig]: An exception was caught: $e")
434+
options.customLogger.warning("[Statsig]: An exception was caught: $e")
435435
}
436436
return null
437437
}
@@ -450,7 +450,7 @@ internal class SpecStore constructor(
450450
return configs
451451
} catch (e: Exception) {
452452
errorBoundary.logException("downloadConfigSpecs", e)
453-
println("[Statsig]: An exception was caught: $e")
453+
options.customLogger.warning("[Statsig]: An exception was caught: $e")
454454
} finally {
455455
response?.close()
456456
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,11 @@ class Statsig {
639639
private fun checkInitialized(): Boolean {
640640
val initialized = isInitialized()
641641
if (!initialized) {
642-
println("Call and wait for initialize to complete before calling SDK methods.")
642+
if (::statsigServer.isInitialized) {
643+
statsigServer.getCustomLogger().warning("Call and wait for initialize to complete before calling SDK methods.")
644+
} else {
645+
println("Call and wait for initialize to complete before calling SDK methods.")
646+
}
643647
}
644648
return initialized
645649
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ internal class StatsigNetwork(
215215
diagnostics?.endNetworkRequestDiagnostics(diagnosticsKey, response.isSuccessful, response)
216216
return response
217217
} catch (e: Exception) {
218-
println("[Statsig]: An exception was caught: $e")
218+
options.customLogger.warning("[Statsig]: An exception was caught: $e")
219219
if (e is JsonParseException) {
220220
errorBoundary.logException("postImpl", e)
221221
}
@@ -257,7 +257,7 @@ internal class StatsigNetwork(
257257
}
258258
}
259259
} catch (e: Exception) {
260-
println("[Statsig]: An exception was caught: $e")
260+
options.customLogger.warning("[Statsig]: An exception was caught: $e")
261261
if (e is JsonParseException) {
262262
errorBoundary.logException("retryPostLogs", e)
263263
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ private const val TIER_KEY: String = "tier"
44
private const val DEFAULT_INIT_TIME_OUT_MS: Long = 3000L
55
private const val CONFIG_SYNC_INTERVAL_MS: Long = 10 * 1000
66
private const val ID_LISTS_SYNC_INTERVAL_MS: Long = 60 * 1000
7+
private val defaultLogger = object : LoggerInterface {
8+
9+
override fun warning(message: String) {
10+
println(message)
11+
}
12+
13+
override fun info(message: String) {
14+
println(message)
15+
}
16+
}
717

818
/**
919
* A SAM for Java compatibility
@@ -13,6 +23,11 @@ fun interface RulesUpdatedCallback {
1323
fun accept(rules: String)
1424
}
1525

26+
interface LoggerInterface {
27+
fun warning(message: String)
28+
fun info(message: String)
29+
}
30+
1631
/**
1732
* An object of properties for initializing the sdk with advanced options
1833
* @property api the api endpoint to use for initialization and logging
@@ -30,6 +45,7 @@ class StatsigOptions(
3045
var rulesetsSyncIntervalMs: Long = CONFIG_SYNC_INTERVAL_MS,
3146
var idListsSyncIntervalMs: Long = ID_LISTS_SYNC_INTERVAL_MS,
3247
var dataStore: IDataStore? = null,
48+
var customLogger: LoggerInterface = defaultLogger,
3349
) {
3450
constructor(api: String) : this(api, DEFAULT_INIT_TIME_OUT_MS)
3551
constructor(initTimeoutMs: Long) : this(null, initTimeoutMs)

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ sealed class StatsigServer {
167167
abstract fun shutdown()
168168

169169
internal abstract suspend fun flush()
170+
internal abstract fun getCustomLogger(): LoggerInterface
170171

171172
companion object {
172173

@@ -661,6 +662,10 @@ private class StatsigServerImpl() :
661662
logger.flush()
662663
}
663664

665+
override fun getCustomLogger(): LoggerInterface {
666+
return options.customLogger
667+
}
668+
664669
private suspend fun getLayerImpl(user: StatsigUser, layerName: String, disableExposure: Boolean, onExposure: OnLayerExposure? = null): Layer {
665670
if (!isSDKInitialized()) {
666671
return Layer.empty(layerName)
@@ -748,11 +753,11 @@ private class StatsigServerImpl() :
748753

749754
private fun isSDKInitialized(): Boolean {
750755
if (statsigJob.isCancelled || statsigJob.isCompleted) {
751-
println("StatsigServer was shutdown")
756+
options.customLogger.info("StatsigServer was shutdown")
752757
return false
753758
}
754759
if (!this::configEvaluator.isInitialized || !configEvaluator.isInitialized) { // If the server was never initialized
755-
println("Must initialize a server before calling other APIs")
760+
options.customLogger.warning("Must initialize a server before calling other APIs")
756761
return false
757762
}
758763
return true
@@ -803,7 +808,7 @@ private class StatsigServerImpl() :
803808
if (!t.name.equals(currentThread.name)) {
804809
throw e
805810
}
806-
println("[Statsig]: Shutting down Statsig because of unhandled exception from your server")
811+
server.getCustomLogger().info("[Statsig]: Shutting down Statsig because of unhandled exception from your server")
807812
server.shutdown()
808813
throw e
809814
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.statsig.sdk
2+
3+
import kotlinx.coroutines.runBlocking
4+
import org.junit.Test
5+
6+
class CustomLoggerTest {
7+
val warningMessage = mutableListOf<String>()
8+
val infoMessage = mutableListOf<String>()
9+
val server = StatsigServer.create()
10+
val fakeLogger = object : LoggerInterface {
11+
override fun warning(message: String) {
12+
println(message)
13+
warningMessage.add(message)
14+
}
15+
16+
override fun info(message: String) {
17+
println(message)
18+
infoMessage.add(message)
19+
}
20+
}
21+
22+
@Test
23+
fun testExceptionLogger() = runBlocking {
24+
server.initialize("server-secret", StatsigOptions(customLogger = fakeLogger))
25+
assert(warningMessage.size == 2) // One from network one from gson
26+
server.shutdown()
27+
server.checkGate(StatsigUser("user_id"), "test_gate")
28+
assert(infoMessage.size == 1)
29+
}
30+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import okhttp3.mockwebserver.RecordedRequest
1414
import org.junit.After
1515
import org.junit.Assert
1616
import org.junit.Before
17+
import org.junit.Rule
1718
import org.junit.Test
1819
import java.lang.StringBuilder
1920

@@ -27,6 +28,9 @@ class DiagnosticsTest {
2728
lateinit var downloadConfigSpecsResponse: String
2829

2930
private val user = StatsigUser("testUser")
31+
@JvmField
32+
@Rule
33+
val retry = RetryRule(3)
3034

3135
@Before
3236
fun setup() {

src/test/java/com/statsig/sdk/EvaluatorTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public void testIP3Country() throws NoSuchFieldException, IllegalAccessException
2929

3030
APIDownloadedConfigs configs = gson.fromJson(CONFIG_SPEC, APIDownloadedConfigs.class);
3131
specStore.setDownloadedConfigs(configs,false);
32+
TestUtilJava.setInitReasonFromSpecStore(specStore, EvaluationReason.NETWORK);
3233

3334
// IP Passes, but ID doesnt pass rollout percentage
3435
StatsigUser user = new StatsigUser("123");

0 commit comments

Comments
 (0)