Skip to content

Commit

Permalink
feat(android): persist and sync uncaught exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
abhaysood committed Sep 26, 2023
1 parent 9afbbcd commit c20e9e4
Show file tree
Hide file tree
Showing 57 changed files with 1,728 additions and 850 deletions.
8 changes: 8 additions & 0 deletions measure-android/measure/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ android {
kotlinOptions {
jvmTarget = "1.8"
}
testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
}

dependencies {
Expand All @@ -65,4 +70,7 @@ dependencies {

testImplementation("org.mockito.kotlin:mockito-kotlin:5.1.0")
testImplementation("junit:junit:4.13.2")
testImplementation("androidx.test.ext:junit-ktx:1.1.5")
testImplementation("org.robolectric:robolectric:4.9.2")

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,54 @@
package sh.measure.android

import android.content.Context
import sh.measure.android.executors.BackgroundTaskRunner
import sh.measure.android.executors.CustomThreadFactory
import sh.measure.android.id.UUIDProvider
import sh.measure.android.logger.AndroidLogger
import sh.measure.android.logger.LogLevel
import sh.measure.android.network.HttpClient
import sh.measure.android.network.HttpClientOkHttp
import sh.measure.android.network.Transport
import sh.measure.android.network.TransportImpl
import sh.measure.android.session.ResourceFactoryImpl
import sh.measure.android.session.SessionController
import sh.measure.android.session.SessionControllerImpl
import sh.measure.android.session.SessionProvider
import sh.measure.android.storage.SqliteDbHelper
import sh.measure.android.storage.Storage
import sh.measure.android.storage.StorageImpl
import sh.measure.android.time.AndroidTimeProvider
import sh.measure.android.tracker.MeasureSignalTracker

class Measure {
companion object {
fun init(context: Context) {
// TODO(abhay): Refactor this. This is a temporary entry point for initializing the
// Measure SDK.
val logger = AndroidLogger().apply { log(LogLevel.Debug, "Initializing Measure") }
MeasureClient(logger, context).apply { init() }
val threadFactory = CustomThreadFactory()
val backgroundTaskRunner = BackgroundTaskRunner(threadFactory)
val storage: Storage = StorageImpl(logger, SqliteDbHelper(logger, context))
val httpClient: HttpClient =
HttpClientOkHttp(logger, Config.MEASURE_BASE_URL, Config.MEASURE_SECRET_TOKEN)
val transport: Transport =
TransportImpl(logger, httpClient)
val timeProvider = AndroidTimeProvider()
val idProvider = UUIDProvider()
val config = Config
val resourceFactory = ResourceFactoryImpl(logger, context, config)
val sessionProvider = SessionProvider(
logger, timeProvider, idProvider, resourceFactory
)
val sessionController: SessionController = SessionControllerImpl(
logger, sessionProvider, storage, transport, backgroundTaskRunner
)
MeasureClient(
logger,
timeProvider = timeProvider,
signalTracker = MeasureSignalTracker(logger, sessionController),
sessionController = sessionController,
).init()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,73 +1,25 @@
package sh.measure.android

import android.content.Context
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.json.Json
import sh.measure.android.database.DbClient
import sh.measure.android.database.SqliteDbClient
import sh.measure.android.debug.DebugHeartbeatCollector
import sh.measure.android.events.DefaultTracker
import sh.measure.android.events.EventType
import sh.measure.android.events.MeasureEventFactory
import sh.measure.android.events.sinks.DbSink
import sh.measure.android.events.sinks.HttpSink
import sh.measure.android.events.sinks.LoggingSink
import sh.measure.android.exceptions.ExceptionData
import sh.measure.android.exceptions.UnhandledExceptionCollector
import sh.measure.android.id.IdProvider
import sh.measure.android.id.UUIDProvider
import sh.measure.android.logger.Logger
import sh.measure.android.network.HttpClient
import sh.measure.android.network.HttpClientOkHttp
import sh.measure.android.resource.ResourceFactory
import sh.measure.android.resource.SessionProvider
import sh.measure.android.time.AndroidDateProvider
import sh.measure.android.time.DateProvider
import sh.measure.android.session.SessionController
import sh.measure.android.time.TimeProvider
import sh.measure.android.tracker.SignalTracker

/**
* Maintains global state and provides a way for different components to communicate with each
* other.
*/
internal class MeasureClient(private val logger: Logger, private val context: Context) {
private val idProvider: IdProvider = UUIDProvider()
private val dateProvider: DateProvider = AndroidDateProvider
private val sessionProvider: SessionProvider = SessionProvider(idProvider)
private val resource = ResourceFactory.create(logger, context, sessionProvider, Config)
private val httpClient: HttpClient = HttpClientOkHttp(
logger, baseUrl = Config.MEASURE_BASE_URL, secretToken = Config.MEASURE_SECRET_TOKEN
)
private val dbClient: DbClient = SqliteDbClient(logger, context)
private val defaultTracker = DefaultTracker()

internal class MeasureClient(
private val logger: Logger,
private val timeProvider: TimeProvider,
private val signalTracker: SignalTracker,
private val sessionController: SessionController
) {
fun init() {
defaultTracker.apply {
addEventSink(DbSink(logger, dbClient))
addEventSink(HttpSink(logger, httpClient, dbClient))
addEventSink(LoggingSink(logger))
}
UnhandledExceptionCollector(logger, this).register()
DebugHeartbeatCollector(context, this).register()
}

fun captureException(exceptionData: ExceptionData) {
val event = MeasureEventFactory.createMeasureEvent(
type = EventType.EXCEPTION,
value = Json.encodeToJsonElement(ExceptionData.serializer(), exceptionData),
resource = resource,
idProvider = idProvider,
dateProvider = dateProvider
)
defaultTracker.track(event)
}

fun captureHeartbeat(string: String) {
val event = MeasureEventFactory.createMeasureEvent(
type = EventType.STRING,
value = Json.encodeToJsonElement(String.serializer(), string),
resource = resource,
idProvider = idProvider,
dateProvider = dateProvider
)
defaultTracker.track(event)
sessionController.createSession()
UnhandledExceptionCollector(logger, signalTracker, timeProvider).register()
sessionController.syncSessions()
sessionController.deleteSessionsWithoutCrash()
}
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit c20e9e4

Please sign in to comment.