From 929d581b65546dd4a203ab50ca13b4e2f326b566 Mon Sep 17 00:00:00 2001 From: kevin-statsig Date: Wed, 15 Apr 2026 15:27:20 -0700 Subject: [PATCH 1/7] update android-sdk workflow actions to hashes (#497) ### TL;DR Hashes instead of version numbers. --- .github/workflows/kong.yml | 6 +++--- .github/workflows/publish-to-maven.yml | 6 +++--- .github/workflows/scheduler.yml | 2 +- .github/workflows/tests.yml | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/kong.yml b/.github/workflows/kong.yml index fffdff9..a2cebeb 100644 --- a/.github/workflows/kong.yml +++ b/.github/workflows/kong.yml @@ -21,12 +21,12 @@ jobs: - name: Get KONG run: git clone https://oauth2:$repo_pat@github.com/statsig-io/kong.git . - - uses: actions/setup-java@v4 + - uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: java-version: "17" distribution: "temurin" - - uses: actions/cache@v3 + - uses: actions/cache@6f8efc29b200d32929f49075959781ed54ec270c # v3 with: path: | ~/.gradle/caches @@ -40,7 +40,7 @@ jobs: run: npm install - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4 - name: Setup Android SDK run: npm run kong -- setup android -v diff --git a/.github/workflows/publish-to-maven.yml b/.github/workflows/publish-to-maven.yml index 2f91cc1..181ed9a 100644 --- a/.github/workflows/publish-to-maven.yml +++ b/.github/workflows/publish-to-maven.yml @@ -15,16 +15,16 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@17f84c3641ba7b8f6deff6309fc4c864478f5d62 # v3 with: distribution: 'temurin' java-version: '17' - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v5 + uses: gradle/actions/wrapper-validation@0723195856401067f7a2779048b490ace7a47d7c # v5 - name: Grant Execute Permission for Gradlew run: chmod +x gradlew diff --git a/.github/workflows/scheduler.yml b/.github/workflows/scheduler.yml index 7e36350..83fff0b 100644 --- a/.github/workflows/scheduler.yml +++ b/.github/workflows/scheduler.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Trigger Scheduled Test Runs if: github.event.repository.private - uses: actions/github-script@v6 + uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6 with: script: | const args = { diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a79cbbd..646434a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,15 +12,15 @@ jobs: timeout-minutes: 12 runs-on: ubuntu-latest-16core steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - uses: actions/setup-java@v5 + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: 17 distribution: "adopt" - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5 - name: Lint run: ./gradlew ktLintCheck @@ -30,7 +30,7 @@ jobs: - name: Upload test report on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: test-report path: build/reports/tests/testDebugUnitTest/ From 1ab1d60e16891f03c6b695d64264df6712a8e6b3 Mon Sep 17 00:00:00 2001 From: kev-oai Date: Thu, 16 Apr 2026 13:14:48 -0700 Subject: [PATCH 2/7] update github workflows (#1) * update kong workflow with OAI secrets * fix kong workflow test working directory * update unit test workflow configuration for openai repo --- .github/workflows/kong.yml | 24 +++++++++++++++++++++--- .github/workflows/tests.yml | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/kong.yml b/.github/workflows/kong.yml index a2cebeb..f9d651a 100644 --- a/.github/workflows/kong.yml +++ b/.github/workflows/kong.yml @@ -9,8 +9,9 @@ on: env: test_api_key: ${{ secrets.KONG_SERVER_SDK_KEY }} - test_client_key: ${{ secrets. KONG_CLIENT_SDK_KEY }} - repo_pat: ${{ secrets.KONG_FINE_GRAINED_REPO_PAT }} + test_client_key: ${{ secrets.KONG_CLIENT_SDK_KEY }} + OAI_GITHUB_APP_ID: ${{ secrets.OAI_GITHUB_APP_ID }} + OAI_GITHUB_APP_PRIVATE_KEY: ${{ secrets.OAI_GITHUB_APP_PRIVATE_KEY }} FORCE_COLOR: true jobs: @@ -18,8 +19,21 @@ jobs: timeout-minutes: 10 runs-on: ubuntu-latest steps: + - uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3 + id: app-token + with: + client-id: ${{ secrets.OAI_GITHUB_APP_ID }} + private-key: ${{ secrets.OAI_GITHUB_APP_PRIVATE_KEY }} + owner: openai + repositories: statsig-priv-kong - name: Get KONG - run: git clone https://oauth2:$repo_pat@github.com/statsig-io/kong.git . + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + token: ${{ steps.app-token.outputs.token }} + repository: openai/statsig-priv-kong + ref: main + path: kong + persist-credentials: false - uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: @@ -37,16 +51,20 @@ jobs: ${{ runner.os }}-android-gradle- - name: Install Deps + working-directory: kong run: npm install - name: Setup Gradle uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4 - name: Setup Android SDK + working-directory: kong run: npm run kong -- setup android -v - name: Precompile Android Bridge + working-directory: kong run: (cd bridges/android-bridge ; ./gradlew assemble) - name: Run Tests + working-directory: kong run: npm run kong -- test android -v -r diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 646434a..b5db3f1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,7 +10,7 @@ on: jobs: gradle: timeout-minutes: 12 - runs-on: ubuntu-latest-16core + runs-on: ubuntu-latest steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 From c435b73b73dab544afee300c48d45a3ee2e33127 Mon Sep 17 00:00:00 2001 From: kev-oai Date: Mon, 20 Apr 2026 11:14:02 -0700 Subject: [PATCH 3/7] make eventLoggingApi a mutable runtime option (#3) ### TL;DR Allow updating eventLoggingApi at runtime. ### Why make this change? Feature request to support a cutover between two logging endpoints ### What changed? * Added `eventLoggingAPI` to `StatsigRuntimeMutableOptions` and updated `StatsigOptions` accordingly * Added `setApi()` to `StatsigLogger` and updated `api` field from val to var * Added logic for the logging api change to `StatsigClient` --- .../com/statsig/androidsdk/StatsigClient.kt | 20 +++++++++++--- .../com/statsig/androidsdk/StatsigLogger.kt | 6 ++++- .../com/statsig/androidsdk/StatsigOptions.kt | 7 +++-- .../StatsigRuntimeMutableOptions.kt | 9 ++++++- .../com/statsig/androidsdk/LogEventTest.kt | 27 +++++++++++++++++++ 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/statsig/androidsdk/StatsigClient.kt b/src/main/java/com/statsig/androidsdk/StatsigClient.kt index 660f6e4..783818c 100644 --- a/src/main/java/com/statsig/androidsdk/StatsigClient.kt +++ b/src/main/java/com/statsig/androidsdk/StatsigClient.kt @@ -117,6 +117,7 @@ class StatsigClient : LifecycleEventListener { @VisibleForTesting internal lateinit var options: StatsigOptions + private lateinit var runtimeMutableOptions: StatsigRuntimeMutableOptions private lateinit var connectivityListener: StatsigNetworkConnectivityListener @@ -675,7 +676,13 @@ class StatsigClient : LifecycleEventListener { enforceInitialized(functionName) errorBoundary.capture( { + this.runtimeMutableOptions = + StatsigRuntimeMutableOptions( + loggingEnabled = runtimeMutableOptions.loggingEnabled, + eventLoggingAPI = runtimeMutableOptions.eventLoggingAPI + ) this.logger.setLoggingEnabled(runtimeMutableOptions.loggingEnabled) + this.logger.setApi(runtimeMutableOptions.eventLoggingAPI) Log.v(TAG, "Runtime options successfully updated") }, tag = functionName @@ -1188,7 +1195,7 @@ class StatsigClient : LifecycleEventListener { retryScope.launch(dispatcherProvider.io) { try { this@StatsigClient.statsigNetwork.apiRetryFailedLogs( - this@StatsigClient.options.eventLoggingAPI, + this@StatsigClient.runtimeMutableOptions.eventLoggingAPI, this@StatsigClient.options.logEventFallbackUrls, statsigClientMetadata ) @@ -1267,6 +1274,11 @@ class StatsigClient : LifecycleEventListener { this.keyValueStorage = storage this.sdkKey = sdkKey this.options = options + this.runtimeMutableOptions = + StatsigRuntimeMutableOptions( + loggingEnabled = options.loggingEnabled, + eventLoggingAPI = options.eventLoggingAPI + ) val normalizedUser = normalizeUser(user) val initializeValues = options.initializeValues this.user = normalizedUser @@ -1313,14 +1325,14 @@ class StatsigClient : LifecycleEventListener { StatsigLogger( statsigScope, sdkKey, - options.eventLoggingAPI, + runtimeMutableOptions.eventLoggingAPI, statsigClientMetadata, statsigNetwork, normalizedUser, { store.getBootstrapMetadata() }, diagnostics, options.logEventFallbackUrls, - options.loggingEnabled, + runtimeMutableOptions.loggingEnabled, gson ) populateStatsigMetadata() @@ -1648,7 +1660,7 @@ class StatsigClient : LifecycleEventListener { } retryScope.launch(dispatcherProvider.io) { statsigNetwork.apiRetryFailedLogs( - this@StatsigClient.options.eventLoggingAPI, + this@StatsigClient.runtimeMutableOptions.eventLoggingAPI, this@StatsigClient.options.logEventFallbackUrls, statsigClientMetadata ) diff --git a/src/main/java/com/statsig/androidsdk/StatsigLogger.kt b/src/main/java/com/statsig/androidsdk/StatsigLogger.kt index 345d3fc..bc6226e 100644 --- a/src/main/java/com/statsig/androidsdk/StatsigLogger.kt +++ b/src/main/java/com/statsig/androidsdk/StatsigLogger.kt @@ -39,7 +39,7 @@ internal data class LogEventData( internal class StatsigLogger( private val coroutineScope: CoroutineScope, private val sdkKey: String, - private val api: String, + private var api: String, private val statsigMetadata: StatsigMetadata, private val statsigNetwork: StatsigNetwork, private val statsigUser: StatsigUser, @@ -259,6 +259,10 @@ internal class StatsigLogger( this.loggingEnabled = loggingEnabled } + fun setApi(api: String) { + this.api = api + } + private fun addManualFlag( metadata: MutableMap, isManual: Boolean diff --git a/src/main/java/com/statsig/androidsdk/StatsigOptions.kt b/src/main/java/com/statsig/androidsdk/StatsigOptions.kt index 35f0974..a706210 100644 --- a/src/main/java/com/statsig/androidsdk/StatsigOptions.kt +++ b/src/main/java/com/statsig/androidsdk/StatsigOptions.kt @@ -40,12 +40,11 @@ class StatsigOptions( @SerializedName("api") var api: String = DEFAULT_INIT_API, /** - * The endpoint to use for logging events. Default is "https://api.statsig.com/v1". - * The SDK will hit different endpoints for initialize + * The endpoint to use for logging events. The SDK will hit different endpoints for initialize * to evaluate gates and for logEvent to log event data. The api option controls the evaluation * endpoint, and eventLoggingApi controls the event logging endpoint. */ - @SerializedName("eventLoggingAPI") var eventLoggingAPI: String = DEFAULT_EVENT_API, + eventLoggingAPI: String = DEFAULT_EVENT_API, /** * The endpoint to use for logging sdk-internal exceptions for Statsig diagnostics. @@ -166,7 +165,7 @@ class StatsigOptions( var logNetworkMetadata: Boolean = false, loggingEnabled: Boolean = DEFAULT_LOGGING_ENABLED -) : StatsigRuntimeMutableOptions(loggingEnabled) { +) : StatsigRuntimeMutableOptions(loggingEnabled, eventLoggingAPI) { @SerializedName("autoValueUpdateIntervalMinutes") var autoValueUpdateIntervalMinutes = diff --git a/src/main/java/com/statsig/androidsdk/StatsigRuntimeMutableOptions.kt b/src/main/java/com/statsig/androidsdk/StatsigRuntimeMutableOptions.kt index 3a70a55..43f0e34 100644 --- a/src/main/java/com/statsig/androidsdk/StatsigRuntimeMutableOptions.kt +++ b/src/main/java/com/statsig/androidsdk/StatsigRuntimeMutableOptions.kt @@ -15,5 +15,12 @@ open class StatsigRuntimeMutableOptions( * [loggingEnabled] defaults to true if a value is not provided. */ @SerializedName("loggingEnabled") - var loggingEnabled: Boolean = DEFAULT_LOGGING_ENABLED + var loggingEnabled: Boolean = DEFAULT_LOGGING_ENABLED, + + /** + * The endpoint to use for logging events. This can be updated at runtime to support gradual + * cutovers between log ingestion endpoints. + */ + @SerializedName("eventLoggingAPI") + var eventLoggingAPI: String = DEFAULT_EVENT_API ) diff --git a/src/test/java/com/statsig/androidsdk/LogEventTest.kt b/src/test/java/com/statsig/androidsdk/LogEventTest.kt index 85c5eac..e6f6919 100644 --- a/src/test/java/com/statsig/androidsdk/LogEventTest.kt +++ b/src/test/java/com/statsig/androidsdk/LogEventTest.kt @@ -141,6 +141,33 @@ class LogEventTest { } } + @Test + fun testRuntimeMutableSettingsEventLoggingApi() = runBlocking { + val initialLogEventApi = "https://initial.fake.statsig.com/v1" + val updatedLogEventApi = "https://updated.fake.statsig.com/v1" + val options = StatsigOptions(eventLoggingAPI = initialLogEventApi) + + setup(options) + + Statsig.logEvent("event_before_api_update") + Statsig.flush() + + Statsig.updateRuntimeOptions( + StatsigRuntimeMutableOptions(eventLoggingAPI = updatedLogEventApi) + ) + + Statsig.logEvent("event_after_api_update") + Statsig.flush() + + coVerify(exactly = 1) { + network.apiPostLogs(initialLogEventApi, any(), any(), any(), any()) + } + coVerify(exactly = 1) { + network.apiPostLogs(updatedLogEventApi, any(), any(), any(), any()) + } + assertThat(options.eventLoggingAPI).isEqualTo(initialLogEventApi) + } + @Test fun testOverrideLoggingApi() = runBlocking { val apiPermutations = arrayOf( From d1a187169a0aa58667b58ea0601e66e0097fed2c Mon Sep 17 00:00:00 2001 From: kev-oai Date: Mon, 20 Apr 2026 13:42:50 -0700 Subject: [PATCH 4/7] Update workflow actions (#2) ## Summary - update GitHub Actions workflow dependencies that were still on deprecated Node runtimes - update release-bot workflow to the openai version instead of the statsig-io copy. ## Why GitHub is warning that some workflow actions are still running on deprecated Node.js versions. This branch moves those workflows to current action versions that support the newer runner runtime. --- .github/workflows/kong.yml | 6 +++--- .github/workflows/publish-to-maven.yml | 4 ++-- .github/workflows/release-bot.yml | 2 +- .github/workflows/scheduler.yml | 2 +- .github/workflows/tests.yml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/kong.yml b/.github/workflows/kong.yml index f9d651a..53e5a96 100644 --- a/.github/workflows/kong.yml +++ b/.github/workflows/kong.yml @@ -35,12 +35,12 @@ jobs: path: kong persist-credentials: false - - uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "17" distribution: "temurin" - - uses: actions/cache@6f8efc29b200d32929f49075959781ed54ec270c # v3 + - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: | ~/.gradle/caches @@ -55,7 +55,7 @@ jobs: run: npm install - name: Setup Gradle - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5 - name: Setup Android SDK working-directory: kong diff --git a/.github/workflows/publish-to-maven.yml b/.github/workflows/publish-to-maven.yml index 181ed9a..258a826 100644 --- a/.github/workflows/publish-to-maven.yml +++ b/.github/workflows/publish-to-maven.yml @@ -15,10 +15,10 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - name: Set up JDK 17 - uses: actions/setup-java@17f84c3641ba7b8f6deff6309fc4c864478f5d62 # v3 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: distribution: 'temurin' java-version: '17' diff --git a/.github/workflows/release-bot.yml b/.github/workflows/release-bot.yml index 71fa098..5f06473 100644 --- a/.github/workflows/release-bot.yml +++ b/.github/workflows/release-bot.yml @@ -13,6 +13,6 @@ jobs: if: startsWith(github.head_ref, 'releases/') || github.event_name == 'release' runs-on: ubuntu-latest steps: - - uses: statsig-io/statsig-publish-sdk-action@main + - uses: openai/statsig-publish-sdk-action@main with: kong-private-key: ${{ secrets.KONG_GH_APP_PRIVATE_KEY }} diff --git a/.github/workflows/scheduler.yml b/.github/workflows/scheduler.yml index 83fff0b..3870097 100644 --- a/.github/workflows/scheduler.yml +++ b/.github/workflows/scheduler.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Trigger Scheduled Test Runs if: github.event.repository.private - uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | const args = { diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b5db3f1..dee38dc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: timeout-minutes: 12 runs-on: ubuntu-latest steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: From b8d7c433bd146452780c6023c97659070be145e1 Mon Sep 17 00:00:00 2001 From: kev-oai Date: Mon, 20 Apr 2026 13:54:44 -0700 Subject: [PATCH 5/7] Updated gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 9ba0438..40bcdf3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ android.useAndroidX=true -libraryVersion=5.0.0 +libraryVersion=5.1.0 org.gradle.caching=true org.gradle.configuration-cache=true org.gradle.configuration-cache.problems=warn From 42dd79aa4a1c8f1467b78267c5cea5618816e438 Mon Sep 17 00:00:00 2001 From: kev-oai Date: Mon, 20 Apr 2026 14:59:10 -0700 Subject: [PATCH 6/7] Update releasebot with app token --- .github/workflows/release-bot.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/release-bot.yml b/.github/workflows/release-bot.yml index 5f06473..a3f6cb5 100644 --- a/.github/workflows/release-bot.yml +++ b/.github/workflows/release-bot.yml @@ -13,6 +13,13 @@ jobs: if: startsWith(github.head_ref, 'releases/') || github.event_name == 'release' runs-on: ubuntu-latest steps: + - uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3 + id: app-token + with: + client-id: ${{ secrets.OAI_GITHUB_APP_ID }} + private-key: ${{ secrets.OAI_GITHUB_APP_PRIVATE_KEY }} + owner: openai + repositories: statsig-publish-sdk-action - uses: openai/statsig-publish-sdk-action@main with: kong-private-key: ${{ secrets.KONG_GH_APP_PRIVATE_KEY }} From af8938fdc202cda6d39eadb8a936761ff35e696c Mon Sep 17 00:00:00 2001 From: kev-oai Date: Mon, 20 Apr 2026 15:02:38 -0700 Subject: [PATCH 7/7] actually use token --- .github/workflows/release-bot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-bot.yml b/.github/workflows/release-bot.yml index a3f6cb5..9f030a9 100644 --- a/.github/workflows/release-bot.yml +++ b/.github/workflows/release-bot.yml @@ -22,4 +22,5 @@ jobs: repositories: statsig-publish-sdk-action - uses: openai/statsig-publish-sdk-action@main with: + token: ${{ steps.app-token.outputs.token }} kong-private-key: ${{ secrets.KONG_GH_APP_PRIVATE_KEY }}