Git Product home page Git Product logo

android-client-sdk's People

Contributors

bucketeer-bot avatar cre8ivejp avatar duyhungtnn avatar kentakozuka avatar masaaania avatar renovate[bot] avatar yshrsmz avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

android-client-sdk's Issues

Add new metrics events

Summary

We want to add and remove deprecated metric events from the SDK to improve our monitoring system.
Basically, we will make changes in the current implementation to support the new metrics. Nothing in particular.

We use Okhttp and Moshi for the API requests.

APIs

For get_evaluations, we will report all metrics events, Including the latency and size metrics events.
For register_events, we will only report error metrics, such as timeout, network, server errors, etc.

InternalErrorMetricsEvent

We will remove the InternalErrorMetricsEvent, and use InternalServerErrorMetricsEvent for 500 internal server errors and InternalSdkErrorMetricsEvent for SDK internal errors.

Labels

All the metrics events have a key/value map called labels.
In the labels, we will set the same tag that is used to initialize the SDK.

E.g

{
  "tag": "android"
}

Metric event list

Metric list
https://github.com/bucketeer-io/bucketeer/blob/main/proto/event/client/event.proto#L119-L184

enum ApiId {
  UNKNOWN_API = 0;
  GET_EVALUATION = 1;
  GET_EVALUATIONS = 2;
  REGISTER_EVENTS = 3;
}

message LatencyMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
  google.protobuf.Duration duration = 3;
}

message SizeMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
  int32 size_byte = 3;
}

// HTTP Mapping: 400 Bad Request
message BadRequestErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

// HTTP Mapping: 401 Unauthorized
message UnauthorizedErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

// HTTP Mapping: 403 Forbidden
message ForbiddenErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

// HTTP Mapping: 404 Not Found
message NotFoundErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

// HTTP Mapping: 499 Client Closed Request
message ClientClosedRequestErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

// HTTP Mapping: 500 Internal Server Error
message InternalServerErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

// HTTP Mapping: 503 Service Unavailable
message ServiceUnavailableErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

message TimeoutErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

message NetworkErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

message InternalSdkErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

message UnknownErrorMetricsEvent {
  ApiId api_id = 1;
  map<string, string> labels = 2;
}

chore: update errors metrics report

TODO

  • Track the 3xx status code as "RedirectRequestException".
    • add response_code via labels
  • Track the 413 status code as "PayloadTooLargeException"
  • 408 errors, and we should handle it as a timeout error.
  • Make iOS error handling consistent with Android SDK. Android handles more error code than iOS SDK. That is ( 405, 502, 504)
  • Implement adding more information via labels for Unknown errors, so we don't spend too much time debugging.
    • Add error_message and response_code to the ErrorMetricsEvent labels

Note

the current metrics on the server are the following.
https://github.com/bucketeer-io/bucketeer/blob/main/proto/event/client/event.proto#L99-L187

Add additional metadata to improve data analysis and monitoring

Overview

We should add more data to the SDK requests for future data analysis and monitoring.

  • App version
  • SDK Client version
  • OS version
  • Network (Cell/Wifi)
  • Device model
  • Mobile, Desktop, TV, or Tablet

Note: Some data will be required, such as the app version, and it will be added in the BKTConfig.

Model

Besides the sdk_version, all other additional data will be delivered using a map.

Note: For metrics events, we don't need the metadata.

  @JsonClass(generateAdapter = true)
  data class GoalEvent(
    val timestamp: Long,
    val goal_id: String,
    val user_id: String,
    val value: Double,
    val user: User,
    val tag: String,
    val source_id: SourceID,
    val sdk_version: String, // NEW
    val metadata: Map<String, String> // NEW
  ) : EventData()

  @JsonClass(generateAdapter = true)
  data class EvaluationEvent(
    val timestamp: Long,
    val feature_id: String,
    val feature_version: Int = 0,
    val user_id: String,
    val variation_id: String = "",
    val user: User,
    val reason: Reason,
    val tag: String,
    val source_id: SourceID,
    val sdk_version: String, // NEW
    val metadata: Map<String, String> // NEW
  ) : EventData()

  // we can't use codegen here
  // see MetricsEventAdapterFactory
  data class MetricsEvent(
    val timestamp: Long,
    val event: MetricsEventData,
    val type: MetricsEventType,
    val sdk_version: String, // NEW
  ) : EventData()

chore: add the current timeout setting in the TimeoutErrorMetricsEvent

Because the developer can manually configure the timeout in the initialize interface, the server doesn't know if the request got the timeout error using the default 30 seconds or user setting. To detect it on the server, we need to pass the current setting used in the failed request.

Things to do

  • Pass the current timeout setting in seconds via labels.

E.g.

labels = mapOf("tag" to "android", "timeout" to "5"),

https://github.com/bucketeer-io/android-client-sdk/blob/main/bucketeer/src/main/kotlin/io/bucketeer/sdk/android/internal/model/MetricsEventData.kt#L32

test fail: getEvaluations - network error on API 32

Problem

  • We have 2 test cases fail when run test against Android Emulator ARM API 32.
    • getEvaluations - network error
    • registerEvents - network error
  • But its not fail on API 29 (like in the CI/CD). It means on API 32 , the error "network error" is being reported as "timeout error"
Screenshot 2023-09-21 at 15 46 20
expected instance of: io.bucketeer.sdk.android.BKTException$NetworkException
but was instance of : io.bucketeer.sdk.android.BKTException$TimeoutException
with value          : io.bucketeer.sdk.android.BKTException$TimeoutException: Request timeout error: Connect timed out
expected instance of: io.bucketeer.sdk.android.BKTException$NetworkException
but was instance of : io.bucketeer.sdk.android.BKTException$TimeoutException
with value          : io.bucketeer.sdk.android.BKTException$TimeoutException: Request timeout error: Connect timed out
	at app//io.bucketeer.sdk.android.internal.remote.ApiClientImplTest.registerEvents - network error(ApiClientImplTest.kt:344)
Caused by: io.bucketeer.sdk.android.BKTException$TimeoutException: Request timeout error: Connect timed out
	at app//io.bucketeer.sdk.android.internal.remote.ApiClientExtKt.toBKTException(ApiClientExt.kt:93)
	at app//io.bucketeer.sdk.android.internal.remote.ApiClientImpl.registerEvents(ApiClientImpl.kt:152)
	at app//io.bucketeer.sdk.android.internal.remote.ApiClientImplTest.registerEvents - network error(ApiClientImplTest.kt:339)
Caused by: java.net.SocketTimeoutException: Connect timed out
	at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(Unknown Source)
	at java.base/sun.nio.ch.NioSocketImpl.connect(Unknown Source)
	at java.base/java.net.SocksSocketImpl.connect(Unknown Source)
	at java.base/java.net.Socket.connect(Unknown Source)
	at okhttp3.internal.platform.Platform.connectSocket(Platform.kt:128)
	at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.kt:295)
	at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:207)
	at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
	at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
	at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
	at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
	at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
	at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
	at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
	at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
	at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
	at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
	at io.bucketeer.sdk.android.internal.remote.ApiClientImpl.registerEvents(ApiClientImpl.kt:131)
	... 1 more

perf: cancel on going request like iOS SDK when the client SDK destroying

When the client SDK is being destroyed and there are ongoing requests to the server, it will continue running and may try to write to the closed database.
Currently, the DAO will simply ignore this.
We aim to implement request cancellation, similar to the iOS SDK, to enhance overall safety.

Change the Rest API endpoint

Things to do

  • Change all the fields in the request and the model data objects from snake_case to camelCase.
  • Change the reason type from int to string (reference)
  • Add protobuf @type (reference)
  • Change the APIs

JSON object structure

In the new endpoint's response, there is no data object.

Before:

{
  data: {
    ...
  },
}

After:

{
  ...
}

New APIs

  • get_evaluations
  • register_events

E.g.
https:/api.example.com/get_evaluations
https:/api.example.com/register_events

PR Reference:
ca-dp/bucketeer-ios-sdk#91

perf: improve the API response time

Summary

We are improving the evaluation process on the server to evaluate only the flags that have been changed.
This will improve the load on the server and the response time since it will only return the flags that have been changed.

Currently, when a flag changes on the server, it evaluates all flags again and sends the latest evaluations to the client SDK.
The SDK checks the response, and it does nothing if the response is empty. Otherwise, it deletes all the data in the DB and saves the latest evaluations.

Implementation

When the SDK is initialized

1- Change the featureTag setting to be optional in the BKTConfig
2- Save the featureTag in the SharedPreferences if it is configured in the BKTConfig
3- Clear the userEvaluationsID in the SharedPreferences if the featureTag changes

Sending requests

The following new fields will be added to get_evaluations request.

  • evaluatedAt: the last time the user was evaluated. The server will return in the get_evaluations response (UserEvaluations.CreatedAt), and it must be saved in the client
  • userAttributesUpdated: when the user attributes change via the customAttributes interface, the userAttributesUpdated field must be set to true in the next request.

Update conditions when getting the response

The server will return the new following fields in the response.

  • forceUpdate: a boolean that tells the SDK to delete all the current data and save the latest evaluations from the response
  • archivedFeatureIds: a list of feature flag ids that were archived on the console. All those feature flags must be deleted from the DB.

forceUpdate is True

1- Delete all the evaluations from DB, and save the latest evaluations from the response into the DB
2- Save the UserEvaluations.CreatedAt in the response as evaluatedAt in the SharedPreferences

forceUpdate is false

1- Check the evaluation list in the response and upsert them in the DB if the list is not empty
2- Check the list of the feature flags that were archived on the console and delete them from the DB
3- Save the UserEvaluations.CreatedAt in the response as evaluatedAt in the SharedPreferences

chore: add the sdkVersion in the requests

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

  • build(deps): update all non-major dependencies (benc-uk/workflow-dispatch, com.google.devtools.ksp, com.google.android.material:material, org.jetbrains.kotlinx:kotlinx-coroutines-android, androidx.lifecycle:lifecycle-process, androidx.lifecycle:lifecycle-runtime, org.jetbrains.kotlin.kapt, org.jetbrains.kotlin.android, com.android.application, com.android.library)
  • test(deps): update all non-major test dependencies (com.google.testparameterinjector:test-parameter-injector, org.robolectric:robolectric)
  • build(deps): update all major dependencies (major) (actions/setup-java, actions/upload-artifact, google-github-actions/release-please-action, gradle/gradle-build-action, macos)
  • Click on this checkbox to rebase all open PRs at once

Detected dependencies

github-actions
.github/workflows/build.yml
  • actions/checkout v4
  • actions/setup-java v3.13.0
  • gradle/gradle-build-action v2
  • actions/upload-artifact v3
.github/workflows/e2e.yml
  • actions/checkout v4
  • actions/setup-java v4.2.1@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
  • actions/cache v4
  • reactivecircus/android-emulator-runner v2.30.1@6b0df4b0efb23bb0ec63d881db79aefbc976e4b2
  • reactivecircus/android-emulator-runner v2.30.1@6b0df4b0efb23bb0ec63d881db79aefbc976e4b2
  • actions/upload-artifact v4
  • macos 13-large
.github/workflows/pr-title-validation.yml
  • amannn/action-semantic-pull-request v5
.github/workflows/publish-maven.yml
  • actions/checkout v4
  • actions/setup-java v3.13.0
.github/workflows/pullrequest.yml
  • actions/checkout v4
  • actions/setup-java v3.13.0
  • gradle/gradle-build-action v2
  • actions/upload-artifact v3
.github/workflows/release.yml
  • google-github-actions/release-please-action v3.7.13
.github/workflows/update-changelog-docs-page.yml
  • actions/checkout v4
  • actions/checkout v4
  • benc-uk/workflow-dispatch v1.2.2@798e70c97009500150087d30d9f11c5444830385
gradle
gradle.properties
settings.gradle
build.gradle
bucketeer/gradle.properties
bucketeer/build.gradle
gradle/libs.versions.toml
  • com.squareup.okhttp3:okhttp 4.12.0
  • com.squareup.okhttp3:mockwebserver 4.12.0
  • androidx.sqlite:sqlite-framework 2.4.0
  • com.google.android.gms:play-services-basement 18.3.0
  • com.squareup.moshi:moshi-kotlin 1.15.1
  • com.squareup.moshi:moshi-kotlin-codegen 1.15.1
  • com.squareup.moshi:moshi-adapters 1.15.1
  • junit:junit 4.13.2
  • org.robolectric:robolectric 4.11.1
  • com.google.truth:truth 1.4.2
  • com.google.testparameterinjector:test-parameter-injector 1.15
  • androidx.test:core 1.5.0
  • androidx.test:rules 1.5.0
  • androidx.test.ext:junit 1.1.5
  • androidx.test:orchestrator 1.4.2
  • androidx.appcompat:appcompat 1.6.1
  • androidx.lifecycle:lifecycle-runtime 2.7.0
  • androidx.lifecycle:lifecycle-process 2.7.0
  • com.google.android.material:material 1.11.0
  • com.facebook.stetho:stetho 1.6.0
  • org.jetbrains.kotlinx:kotlinx-coroutines-android 1.8.0
  • com.android.library 8.3.2
  • com.android.application 8.3.2
  • org.jetbrains.kotlin.android 1.9.23
  • org.jetbrains.kotlin.kapt 1.9.23
  • org.jetbrains.dokka 1.9.20
  • com.vanniktech.maven.publish 0.28.0
  • com.google.devtools.ksp 1.9.23-1.0.20
  • org.jmailen.kotlinter 4.3.0
mocks/build.gradle
sample/build.gradle
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.7

  • Check this box to trigger a request for Renovate to run again on this repository

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.