Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/benchmark_suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ jobs:
script: |
adb root
./gradlew --no-configuration-cache -PmanifestEndpoint=https://api-sandbox.simple.org/api/ installQaDebug installQaDebugAndroidTest lockClocks
adb shell am instrument -w -e filter org.simple.clinic.benchmark.SelectBenchmarkTests -e benchmark_app_performance true -e dd_client_token ${{ secrets.DD_PERF_CLIENT_TOKEN }} -e dd_application_id ${{ secrets.DD_PERF_APPLICATION_ID }} org.simple.clinic.qa.debug.test/org.simple.clinic.AndroidTestJUnitRunner
adb shell am instrument -w -e filter org.simple.clinic.benchmark.SelectBenchmarkTests -e benchmark_app_performance true -e sentry_dsn ${{ secrets.SENTRY_DSN }} org.simple.clinic.qa.debug.test/org.simple.clinic.AndroidTestJUnitRunner
adb uninstall org.simple.clinic.qa.debug
adb uninstall org.simple.clinic.qa.debug.test
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
- Bump AGP to v8.8.2
- Calculate lab-based CVD risk score
- Update copy of statin nudge to support lab-based nudge
- Report SQL performance metrics to Sentry

### Fixes

Expand Down
24 changes: 7 additions & 17 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
@file:Suppress("UnstableApiUsage")

import com.android.build.gradle.internal.tasks.databinding.DataBindingGenBaseClassesTask
import io.sentry.android.gradle.extensions.InstrumentationFeature
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
import org.simple.rmg.RoomMetadataGenerator
import java.util.EnumSet

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.sentry)
alias(libs.plugins.datadog)
alias(libs.plugins.ksp)
alias(libs.plugins.kotlin.compose.compiler)
alias(libs.plugins.google.services)
Expand All @@ -33,7 +34,8 @@ sentry {
// We are using our own instrumentation tooling for Room queries
// Look at [ADR 013: SQL Performance Profiling (v2)]
tracingInstrumentation {
enabled.set(false)
enabled = true
features.set(EnumSet.allOf(InstrumentationFeature::class.java) - InstrumentationFeature.DATABASE)
}
}

Expand Down Expand Up @@ -87,22 +89,12 @@ android {
val manifestEndpoint: String by project
val disableScreenshot: String by project
val allowRootedDevice: String by project
val datadogServiceName: String by project
val datadogApplicationId: String by project
val datadogClientToken: String by project
val datadogEnvironment: String by project

addManifestPlaceholders(mapOf(
"sentryDsn" to sentryDsn,
"sentryEnvironment" to sentryEnvironment
))

buildConfigField("String", "SENTRY_DSN", "\"$sentryDsn\"")
buildConfigField("String", "SENTRY_ENVIRONMENT", "\"$sentryEnvironment\"")
buildConfigField("String", "MANIFEST_ENDPOINT", "\"$manifestEndpoint\"")
buildConfigField("boolean", "DISABLE_SCREENSHOT", disableScreenshot)
buildConfigField("boolean", "ALLOW_ROOTED_DEVICE", allowRootedDevice)
buildConfigField("String", "DATADOG_SERVICE_NAME", "\"$datadogServiceName\"")
buildConfigField("String", "DATADOG_APPLICATION_ID", "\"$datadogApplicationId\"")
buildConfigField("String", "DATADOG_CLIENT_TOKEN", "\"$datadogClientToken\"")
buildConfigField("String", "DATADOG_ENVIRONMENT", "\"$datadogEnvironment\"")

ksp {
arg("room.schemaLocation", "$projectDir/schemas")
Expand Down Expand Up @@ -482,8 +474,6 @@ dependencies {

runtimeOnly(libs.jackson.core)

implementation(libs.datadog.sdk)

androidTestImplementation(libs.apache.commons.math)
}

Expand Down
2 changes: 1 addition & 1 deletion app/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<meta-data
android:name="listener"
android:value="org.simple.clinic.benchmark.WaitForDatadogToUpload" />
android:value="org.simple.clinic.benchmark.WaitForSentryToUpload" />

</instrumentation>
</manifest>
66 changes: 19 additions & 47 deletions app/src/androidTest/java/org/simple/clinic/TestClinicApp.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
package org.simple.clinic

import android.app.Application
import android.content.Context
import androidx.test.platform.app.InstrumentationRegistry
import com.datadog.android.Datadog
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.core.configuration.Credentials
import com.datadog.android.core.configuration.UploadFrequency
import com.datadog.android.privacy.TrackingConsent
import com.datadog.android.rum.GlobalRum
import com.datadog.android.rum.RumMonitor
import com.datadog.android.rum.tracking.ViewTrackingStrategy
import com.datadog.android.tracing.AndroidTracer
import com.tspoon.traceur.Traceur
import io.opentracing.util.GlobalTracer
import io.sentry.SentryLevel
import io.sentry.SentryOptions
import io.sentry.android.core.SentryAndroid
import org.simple.clinic.TestClinicApp.Companion.appComponent
import org.simple.clinic.benchmark.BackupBenchmarkDatabase
import org.simple.clinic.di.DaggerTestAppComponent
Expand Down Expand Up @@ -100,9 +92,8 @@ class TestClinicApp : Application() {
dataSync.syncTheWorld()
backupBenchmarkDatabase.backup()

setupDatadog(
clientToken = instrumentationArgs.getString("dd_client_token")!!,
applicationId = instrumentationArgs.getString("dd_application_id")!!
setupSentry(
dsn = instrumentationArgs.getString("sentry_dsn")!!,
)
}
}
Expand Down Expand Up @@ -155,39 +146,20 @@ class TestClinicApp : Application() {
.build()
}

private fun setupDatadog(
clientToken: String,
applicationId: String
) {
val datadogConfig = Configuration
.Builder(
logsEnabled = true,
tracesEnabled = true,
crashReportsEnabled = false,
rumEnabled = false
)
.useViewTrackingStrategy(NoopViewTrackingStrategy())
.setUploadFrequency(UploadFrequency.FREQUENT)
.build()
val credentials = Credentials(
clientToken = clientToken,
envName = "test",
variant = BuildConfig.FLAVOR,
rumApplicationId = applicationId,
serviceName = "simple-android-perf-regression"
)
Datadog.initialize(this, credentials, datadogConfig, TrackingConsent.GRANTED)
GlobalRum.registerIfAbsent(RumMonitor.Builder().build())
GlobalTracer.registerIfAbsent(AndroidTracer.Builder().setPartialFlushThreshold(5).build())
}

private class NoopViewTrackingStrategy : ViewTrackingStrategy {
override fun register(context: Context) {
// No need to track views in tests
}

override fun unregister(context: Context?) {
// No need to track views in tests
private fun setupSentry(dsn: String) {
SentryAndroid.init(this) { options ->
options.dsn = dsn
options.environment = "test"
options.sampleRate = 0.0
options.tracesSampleRate = 1.0

options.beforeSend = SentryOptions.BeforeSendCallback { event, _ ->
if (event.level != SentryLevel.DEBUG) {
event
} else {
null
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package org.simple.clinic.benchmark

import android.util.Log
import io.opentracing.util.GlobalTracer
import io.sentry.Sentry
import io.sentry.SentryLongDate
import io.sentry.SpanStatus
import io.sentry.TransactionOptions
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
import org.simple.clinic.TestClinicApp
import java.util.concurrent.TimeUnit.MICROSECONDS
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit.MILLISECONDS
import javax.inject.Inject

Expand Down Expand Up @@ -65,19 +68,22 @@ class BenchmarkTestRule(

Log.i("PerfRegression", "Median benchmark for $testClass#$testMethod: ${medianTimeTaken}ms")

val tracer = GlobalTracer.get()
val adjustedStartTime = millisToMicros(System.currentTimeMillis() - medianTimeTaken)
val span = tracer
.buildSpan("test.method")
.withTag("class", testClass)
.withTag("method", testMethod)
.withStartTimestamp(adjustedStartTime)
.start()
val adjustedStartTime = millisToNanos(System.currentTimeMillis() - medianTimeTaken)

span.finish(adjustedStartTime + millisToMicros(medianTimeTaken))
val span = Sentry.startTransaction(
/* name = */ "test.method",
/* operation = */ "$testClass/$testMethod",
/* transactionOptions = */ TransactionOptions().apply {
startTimestamp = SentryLongDate(adjustedStartTime)
}
)

span.finish(
SpanStatus.OK,
SentryLongDate(adjustedStartTime + millisToNanos(medianTimeTaken)))
}

private fun millisToMicros(millis: Long) = MICROSECONDS.convert(millis, MILLISECONDS)
private fun millisToNanos(millis: Long) = TimeUnit.NANOSECONDS.convert(millis, MILLISECONDS)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@ package org.simple.clinic.benchmark
import android.os.Bundle
import android.util.Log
import androidx.test.internal.runner.listener.InstrumentationRunListener
import io.opentracing.util.GlobalTracer
import org.junit.runner.Result
import org.simple.clinic.TestClinicApp
import java.io.PrintStream
import java.time.Duration

class WaitForDatadogToUpload : InstrumentationRunListener() {
class WaitForSentryToUpload : InstrumentationRunListener() {

override fun instrumentationRunFinished(streamResult: PrintStream?, resultBundle: Bundle?, junitResults: Result?) {
// We don't have a way to force Datadog to upload all its traces, so we'll wait for a few seconds
// for DD to upload, and then we'll finish it.
// We don't have a way to force Sentry to upload all its traces, so we'll wait for a few seconds
// for Sentry to upload, and then we'll finish it.
if (TestClinicApp.isInBenchmarkMode) {
Log.i("PerfRegression", "Wait for Datadog upload")
Log.i("PerfRegression", "Wait for Sentry upload")
Thread.sleep(Duration.ofMinutes(1).toMillis())
GlobalTracer.get().close()
}
}
}
4 changes: 0 additions & 4 deletions app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
tools:ignore="GoogleAppIndexingWarning"
tools:replace="android:name,android:icon">

<meta-data
android:name="io.sentry.auto-init"
android:value="false" />

<receiver android:name=".DebugNotificationActionReceiver" />

<receiver
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.simple.clinic.di.network

import com.datadog.android.DatadogInterceptor
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin
import dagger.Module
import dagger.Provides
import io.sentry.okhttp.SentryOkHttpInterceptor
import okhttp3.Interceptor
import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.logging.HttpLoggingInterceptor.Level.BODY
Expand All @@ -25,7 +25,7 @@ class HttpInterceptorsModule {
}

return listOf(
DatadogInterceptor(),
SentryOkHttpInterceptor(),
loggedInInterceptor,
appInfoHttpInterceptor,
loggingInterceptor,
Expand Down
12 changes: 2 additions & 10 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,8 @@
android:value="barcode" />

<meta-data
android:name="io.sentry.dsn"
android:value="${sentryDsn}" />

<meta-data
android:name="io.sentry.environment"
android:value="${sentryEnvironment}" />

<meta-data
android:name="io.sentry.sample-rate"
android:value="0.75" />
android:name="io.sentry.auto-init"
android:value="false" />

<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
Expand Down
Loading
Loading