Skip to content

Commit 76cb94b

Browse files
Merge pull request #175 from statsig-io/statsigMetadata_refactor
Refactor statsigMetadata to be a data class
2 parents d5a5f17 + 9857d8a commit 76cb94b

File tree

10 files changed

+50
-48
lines changed

10 files changed

+50
-48
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import java.net.URI
88
import java.net.URLEncoder
99
import java.nio.charset.StandardCharsets
1010

11-
internal class ErrorBoundary(private val apiKey: String, private val options: StatsigOptions) {
11+
internal class ErrorBoundary(private val apiKey: String, private val options: StatsigOptions, private val statsigMetadata: StatsigMetadata) {
1212
internal var uri = URI("https://statsigapi.net/v1/sdk_exception")
1313
private val seen = HashSet<String>()
1414
private val maxInfoLength = 3000
@@ -68,7 +68,7 @@ internal class ErrorBoundary(private val apiKey: String, private val options: St
6868
"tag": "$tag",
6969
"exception": "${ex.javaClass.name}",
7070
"info": "$safeInfo",
71-
"statsigMetadata": ${StatsigMetadata.asJson()}
71+
"statsigMetadata": ${statsigMetadata.asJson()}
7272
}
7373
""".trimIndent()
7474
val req =

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ internal class Evaluator(
3636
private val statsigScope: CoroutineScope,
3737
private val errorBoundary: ErrorBoundary,
3838
private val diagnostics: Diagnostics,
39+
private val statsigMetadata: StatsigMetadata,
3940
) {
4041
private var specStore: SpecStore
4142
private val uaParser: Parser by lazy {
@@ -55,7 +56,7 @@ internal class Evaluator(
5556

5657
init {
5758
CountryLookup.initialize()
58-
specStore = SpecStore(this.network, this.options, StatsigMetadata(), statsigScope, errorBoundary, diagnostics)
59+
specStore = SpecStore(this.network, this.options, statsigMetadata, statsigScope, errorBoundary, diagnostics)
5960
network.setDiagnostics(diagnostics)
6061

6162
statsigScope.launch {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ internal data class StatsigEvent(
88
@SerializedName("value") val eventValue: Any? = null,
99
@SerializedName("metadata") var eventMetadata: Map<String, String>? = null,
1010
@SerializedName("user") var user: StatsigUser? = null,
11-
@SerializedName("statsigMetadata") val statsigMetadata: Map<String, String>? = null,
11+
@SerializedName("statsigMetadata") val statsigMetadata: StatsigMetadata? = null,
1212
@SerializedName("secondaryExposures") val secondaryExposures: ArrayList<Map<String, String>>? = arrayListOf(),
1313
@SerializedName("time") val time: Long? = Utils.getTimeInMillis(),
1414
) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ internal fun safeAddEvaluationToEvent(evaluationDetails: EvaluationDetails?, met
3333
internal class StatsigLogger(
3434
private val coroutineScope: CoroutineScope,
3535
private val network: StatsigNetwork,
36-
private val statsigMetadata: Map<String, String>,
36+
private val statsigMetadata: StatsigMetadata,
3737
) {
3838

3939
private val executor = Executors.newSingleThreadExecutor()
Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,26 @@
11
package com.statsig.sdk
22

3+
import com.google.gson.GsonBuilder
4+
import com.google.gson.ToNumberPolicy
5+
import com.google.gson.annotations.SerializedName
36
import java.util.Properties
7+
import java.util.UUID
48

59
private const val VERSION = "1.6.1"
610

7-
internal class StatsigMetadata {
8-
companion object {
9-
private val version =
10-
try {
11-
val properties = Properties()
12-
properties.load(
13-
StatsigMetadata::class.java.getResourceAsStream("/statsigsdk.properties"),
14-
)
15-
properties.getProperty("version")
16-
} catch (e: Exception) {
17-
VERSION
18-
}
19-
20-
fun asMap(): Map<String, String> {
21-
return mapOf("sdkType" to "java-server", "sdkVersion" to version)
22-
}
23-
24-
fun asJson(): String {
25-
val map = asMap()
26-
val values = map.map { "\"${it.key}\":\"${it.value}\"" }
27-
return "{${values.joinToString(",")}}"
28-
}
11+
internal data class StatsigMetadata(@SerializedName("sdkType") var sdkType: String = "java-server", @SerializedName("sessionID") var sessionID: String = UUID.randomUUID().toString(), @SerializedName("languageVersion") var languageVersion: String = System.getProperty("java.version"), @SerializedName("exposureLoggingDisabled") var exposureLoggingDisabled: Boolean? = null) {
12+
@SerializedName("sdkVersion")
13+
var sdkVersion: String = try {
14+
val properties = Properties()
15+
properties.load(
16+
StatsigMetadata::class.java.getResourceAsStream("/statsigsdk.properties"),
17+
)
18+
properties.getProperty("version")
19+
} catch (e: Exception) {
20+
VERSION
21+
}
22+
fun asJson(): String {
23+
val gson = GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create()
24+
return gson.toJson(this)
2925
}
3026
}

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ private const val MS_IN_S: Long = 1000
2727
internal class StatsigNetwork(
2828
private val sdkKey: String,
2929
private val options: StatsigOptions,
30-
private val statsigMetadata: Map<String, String>,
30+
private val statsigMetadata: StatsigMetadata,
3131
private val errorBoundary: ErrorBoundary,
3232
private val backoffMultiplier: Int = BACKOFF_MULTIPLIER,
3333
) {
@@ -60,8 +60,8 @@ internal class StatsigNetwork(
6060
.addHeader("STATSIG-API-KEY", sdkKey)
6161
.addHeader("STATSIG-CLIENT-TIME", System.currentTimeMillis().toString())
6262
.addHeader("STATSIG-SERVER-SESSION-ID", serverSessionID)
63-
.addHeader("STATSIG-SDK-TYPE", statsigMetadata["sdkType"] ?: "")
64-
.addHeader("STATSIG-SDK-VERSION", statsigMetadata["sdkVersion"] ?: "")
63+
.addHeader("STATSIG-SDK-TYPE", statsigMetadata.sdkType)
64+
.addHeader("STATSIG-SDK-VERSION", statsigMetadata.sdkVersion)
6565
.method(original.method, original.body)
6666
.build()
6767
it.proceed(request)
@@ -91,12 +91,12 @@ internal class StatsigNetwork(
9191
}
9292

9393
suspend fun checkGate(user: StatsigUser?, gateName: String, disableExposureLogging: Boolean): ConfigEvaluation {
94-
val exposureLoggingMap = mapOf("exposureLoggingDisabled" to disableExposureLogging)
94+
statsigMetadata.exposureLoggingDisabled = disableExposureLogging
9595
val bodyJson = gson.toJson(
9696
mapOf(
9797
"gateName" to gateName,
9898
"user" to user,
99-
"statsigMetadata" to statsigMetadata + exposureLoggingMap,
99+
"statsigMetadata" to statsigMetadata,
100100
),
101101
)
102102
val requestBody: RequestBody = bodyJson.toRequestBody(json)
@@ -117,14 +117,15 @@ internal class StatsigNetwork(
117117
}
118118

119119
suspend fun getConfig(user: StatsigUser?, configName: String, disableExposureLogging: Boolean): ConfigEvaluation {
120-
val exposureLoggingMap = mapOf("exposureLoggingDisabled" to disableExposureLogging)
120+
statsigMetadata.exposureLoggingDisabled = disableExposureLogging
121121
val bodyJson = gson.toJson(
122122
mapOf(
123123
"configName" to configName,
124124
"user" to user,
125-
"statsigMetadata" to statsigMetadata + exposureLoggingMap,
125+
"statsigMetadata" to statsigMetadata,
126126
),
127127
)
128+
statsigMetadata.exposureLoggingDisabled = null
128129
val requestBody: RequestBody = bodyJson.toRequestBody(json)
129130

130131
val request: Request = Request.Builder()
@@ -196,13 +197,13 @@ internal class StatsigNetwork(
196197
}
197198
}
198199

199-
suspend fun postLogs(events: List<StatsigEvent>, statsigMetadata: Map<String, String>) {
200+
suspend fun postLogs(events: List<StatsigEvent>, statsigMetadata: StatsigMetadata) {
200201
retryPostLogs(events, statsigMetadata, 5, 1)
201202
}
202203

203204
suspend fun retryPostLogs(
204205
events: List<StatsigEvent>,
205-
statsigMetadata: Map<String, String>,
206+
statsigMetadata: StatsigMetadata,
206207
retries: Int,
207208
backoff: Int,
208209
) {

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

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

3-
import com.google.gson.Gson
43
import com.google.gson.GsonBuilder
54
import com.google.gson.ToNumberPolicy
65
import kotlinx.coroutines.*
@@ -192,11 +191,11 @@ private class StatsigServerImpl() :
192191
private lateinit var diagnostics: Diagnostics
193192
private var options: StatsigOptions = StatsigOptions()
194193
private val mutex = Mutex()
195-
private val statsigMetadata = StatsigMetadata.asMap()
194+
private val statsigMetadata = StatsigMetadata()
196195
override var initialized = false
197196

198197
override fun setup(serverSecret: String, options: StatsigOptions) {
199-
errorBoundary = ErrorBoundary(serverSecret, options)
198+
errorBoundary = ErrorBoundary(serverSecret, options, statsigMetadata)
200199
coroutineExceptionHandler = CoroutineExceptionHandler { _, ex ->
201200
// no-op - supervisor job should not throw when a child fails
202201
errorBoundary.logException("coroutineExceptionHandler", ex)
@@ -221,7 +220,7 @@ private class StatsigServerImpl() :
221220
}
222221
setupAndStartDiagnostics()
223222
configEvaluator =
224-
Evaluator(network, options, statsigScope, errorBoundary, diagnostics)
223+
Evaluator(network, options, statsigScope, errorBoundary, diagnostics, statsigMetadata)
225224
configEvaluator.initialize()
226225
initialized = true
227226
endInitDiagnostics(isSDKInitialized())
@@ -686,7 +685,7 @@ private class StatsigServerImpl() :
686685
normalizedUser,
687686
layer,
688687
paramName,
689-
Gson().toJson(metadata),
688+
gson.toJson(metadata),
690689
),
691690
)
692691
} else {

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import java.nio.charset.StandardCharsets
2020
class ErrorBoundaryTest {
2121
private lateinit var boundary: ErrorBoundary
2222
private lateinit var server: MockWebServer
23+
private lateinit var statsigMetadata: StatsigMetadata
2324

2425
@Before
2526
internal fun setup() {
@@ -31,8 +32,8 @@ class ErrorBoundaryTest {
3132
}
3233
}
3334
}
34-
35-
boundary = ErrorBoundary("secret-key", StatsigOptions())
35+
statsigMetadata = StatsigMetadata()
36+
boundary = ErrorBoundary("secret-key", StatsigOptions(), statsigMetadata)
3637
boundary.uri = server.url("/v1/sdk_exception").toUri()
3738
}
3839

@@ -75,7 +76,7 @@ class ErrorBoundaryTest {
7576
boundary.swallow("") { throw IOException() }
7677

7778
val body = Gson().fromJson(server.takeRequest().body.readUtf8(), Map::class.java)
78-
assertEquals(body["statsigMetadata"], StatsigMetadata.asMap())
79+
assertEquals(body["statsigMetadata"], Gson().fromJson(statsigMetadata.asJson(), Map::class.java))
7980
}
8081

8182
@Test

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,11 @@ class NetworkTest {
3232
successResponse.setBody("{}")
3333
server.enqueue(successResponse)
3434

35-
val metadata: MutableMap<String, String> = HashMap()
36-
metadata["sdkType"] = "test"
35+
val metadata = StatsigMetadata()
3736
val options = StatsigOptions()
3837
options.api = server.url("/v1").toString()
3938

40-
val eb = ErrorBoundary("", options)
39+
val eb = ErrorBoundary("", options, metadata)
4140
val net = spyk(StatsigNetwork("secret-123", options, metadata, eb, 1))
4241

4342
net.postLogs(listOf(StatsigEvent("TestEvent")), metadata)

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ class StatsigE2ETest {
235235
val eventLogInput = withTimeout(TEST_TIMEOUT) {
236236
eventLogInputCompletable.await()
237237
}
238-
239238
assert(eventLogInput.events.size == 3)
240239
assert(eventLogInput.events[0].eventName == "statsig::gate_exposure")
241240
assert(eventLogInput.events[0].eventMetadata!!["gate"].equals("always_on_gate"))
@@ -292,6 +291,12 @@ class StatsigE2ETest {
292291
assert(eventLogInput.events[0].eventMetadata!!["config"].equals("test_config"))
293292
assert(eventLogInput.events[0].eventMetadata!!["ruleID"].equals("1kNmlB23wylPFZi1M0Divl"))
294293
assert(eventLogInput.events[0].time!! / 1000 == now / 1000)
294+
val statsigMetadata = eventLogInput.events[0].statsigMetadata!!
295+
assert(statsigMetadata != null)
296+
assert(statsigMetadata.languageVersion != null)
297+
assert(statsigMetadata.sdkType == "java-server")
298+
assert(statsigMetadata.sessionID != null)
299+
assert(statsigMetadata.exposureLoggingDisabled == null)
295300

296301
assert(eventLogInput.events[1].eventName == "statsig::config_exposure")
297302
assert(eventLogInput.events[1].eventMetadata!!["config"].equals("test_config"))

0 commit comments

Comments
 (0)