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
1 change: 1 addition & 0 deletions apps/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ buildscript {
classpath Plugins.FIREBASE_CRASHLYTICS
if (project.coverageEnabled) { classpath Plugins.JACOCO_ANDROID }
classpath Plugins.HILT
classpath Plugins.DATADOG
}
}

Expand Down
3 changes: 3 additions & 0 deletions apps/buildSrc/src/main/java/GlobalDependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ object Versions {
const val DATASTORE = "1.1.1"
const val LOTTIE = "6.5.2"
const val ENCRYPTED_SHARED_PREFERENCES = "1.0.0"
const val DATADOG = "1.22.0"
}

object Libs {
Expand Down Expand Up @@ -200,4 +201,6 @@ object Plugins {
const val GOOGLE_SERVICES = "com.google.gms:google-services:${Versions.GOOGLE_SERVICES}"
const val JACOCO_ANDROID = "com.dicedmelon.gradle:jacoco-android:${Versions.JACOCO_ANDROID}"
const val HILT = "com.google.dagger:hilt-android-gradle-plugin:${Versions.HILT}"

const val DATADOG = "com.datadoghq:dd-sdk-android-gradle-plugin:${Versions.DATADOG}"
}
9 changes: 8 additions & 1 deletion apps/student/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ android {
testInstrumentationRunnerArguments disableAnalytics: 'true'
buildConfigField "boolean", "IS_TESTING", "false"
buildConfigField "String", "BUGFENDER_KEY", "\"${Keys.BUGFENDER_KEY}\""

buildConfigField "String", "DATADOG_CLIENT_TOKEN", "\"${Keys.DATADOG_CLIENT_TOKEN}\""
buildConfigField "String", "DATADOG_APPLICATION_ID", "\"${Keys.DATADOG_APPLICATION_ID}\""

/* Add private data */
PrivateData.merge(project, "student")
Expand Down Expand Up @@ -359,6 +360,12 @@ dependencies {
implementation "com.amazonaws:aws-android-sdk-lambda:2.71.0"
implementation "com.amazonaws:aws-android-sdk-sns:2.71.0"
implementation("com.bugfender.sdk:android:3.0.17")

//DATADOG
implementation("com.datadoghq:dd-sdk-android-rum:3.8.0")
implementation("com.datadoghq:dd-sdk-android-logs:3.8.0")
implementation("com.datadoghq:dd-sdk-android-okhttp:3.8.0")
implementation("com.datadoghq:dd-sdk-android-trace:3.8.0")
}

// Comment out this line if the reporting logic starts going wonky.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.work.WorkInfo.State
import androidx.work.WorkManager
import androidx.work.WorkQuery
import com.datadog.android.Datadog
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.instructure.canvasapi2.managers.CourseNicknameManager
import com.instructure.canvasapi2.managers.UserManager
Expand Down Expand Up @@ -568,6 +569,7 @@ class DashboardFragment : ParentFragment() {
private fun initFirebase() {
val user = ApiPrefs.user ?: return
FirebaseAnalytics.identifyUser(user.id)
Datadog.setUserInfo(user.id.toString(), null, null)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.instructure.student.util

import android.content.Intent
import android.util.Log
import androidx.core.content.ContextCompat
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Constraints
Expand All @@ -27,6 +28,14 @@ import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.WorkerFactory
import com.bugfender.sdk.Bugfender
import com.datadog.android.Datadog
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.log.Logger
import com.datadog.android.log.Logs
import com.datadog.android.log.LogsConfiguration
import com.datadog.android.privacy.TrackingConsent
import com.datadog.android.rum.RumConfiguration
import com.datadog.android.trace.DatadogTracing
import com.instructure.canvasapi2.utils.MasqueradeHelper
import com.instructure.loginapi.login.tasks.LogoutTask
import com.instructure.pandautils.analytics.pageview.PageViewUploadWorker
Expand All @@ -47,9 +56,14 @@ import com.twou.offline.util.BaseOfflineUtils.Companion.isOnline
import com.twou.offline.util.OfflineLoggerType
import com.twou.offline.util.OfflineLogs
import dagger.hilt.android.HiltAndroidApp
import sdk.pendo.io.Pendo
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import com.datadog.android.trace.GlobalDatadogTracer
import com.datadog.android.trace.Trace
import com.datadog.android.trace.TraceConfiguration
import com.datadog.android.trace.event.SpanEventMapper
import com.datadog.android.trace.model.SpanEvent
import com.datadog.android.rum.Rum

@HiltAndroidApp
class AppManager : BaseAppManager() {
Expand All @@ -68,6 +82,7 @@ class AppManager : BaseAppManager() {

@Inject
lateinit var workManager: WorkManager
lateinit var logger: Logger

override fun onCreate() {
super.onCreate()
Expand Down Expand Up @@ -197,8 +212,70 @@ class AppManager : BaseAppManager() {

schedulePandataUpload()
initPendo()
setupDataDog()
}

private fun setupDataDog() {
val configuration = Configuration.Builder(
clientToken = BuildConfig.DATADOG_CLIENT_TOKEN,
env = if (BuildConfig.BUILD_TYPE == "release") "production" else "staging",
service = "degrees-mobile"
).build()

Datadog.initialize(this, configuration, trackingConsent = TrackingConsent.GRANTED)

Trace.equals(
TraceConfiguration.Builder().setEventMapper(object : SpanEventMapper {
override fun map(event: SpanEvent): SpanEvent {
val originalUrl = event.resource
event.resource = redactSensitiveData(originalUrl)
return event
}
})
.build()
)
Comment on lines +227 to +236

GlobalDatadogTracer.registerIfAbsent(
DatadogTracing.newTracerBuilder()
.build()
)

Datadog.setVerbosity(Log.INFO)

val logsConfig = LogsConfiguration.Builder().build()
Logs.enable(logsConfig)

logger = Logger.Builder()
.setNetworkInfoEnabled(true)
.setLogcatLogsEnabled(true)
.setName("degrees-android")
.build()

val rumConfig = RumConfiguration.Builder(BuildConfig.DATADOG_APPLICATION_ID)
.setResourceEventMapper { event ->
val originalUrl = event.resource.url
event.resource.url = redactSensitiveData(originalUrl)
event
}
.setErrorEventMapper { event ->
event.error.message = redactSensitiveData(event.error.message)
event.error.resource?.url = redactSensitiveData(event.error.resource?.url.orEmpty())
event
}
.trackUserInteractions()
.trackAnonymousUser(true)
.trackLongTasks()
.trackBackgroundEvents(true)
.trackNonFatalAnrs(true)
.build()
Rum.enable(rumConfig)
}
private fun redactSensitiveData(message: String) = message.replace(
Regex(
"(username|password|wstoken|token)=[^&]*",
RegexOption.IGNORE_CASE
), "$1=****"
)
private fun initPendo() {
// val options = Pendo.PendoOptions.Builder().setJetpackComposeBeta(true).build()
// Pendo.setup(this, BuildConfig.PENDO_TOKEN, options, null)
Expand Down
3 changes: 3 additions & 0 deletions automation/dataseedingapi/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ dependencies {
implementation 'com.github.javafaker:javafaker:0.17.2'
implementation Libs.APOLLO_RUNTIME

/* Datadog */
implementation 'com.datadoghq:dd-sdk-android-okhttp:3.8.0'
implementation("com.datadoghq:dd-sdk-android-trace:3.8.0")
Comment on lines +50 to +52

/* Test Dependencies */
testImplementation Libs.JUNIT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package com.instructure.dataseeding.util

import com.apollographql.apollo.ApolloClient
import com.apollographql.apollo.network.okHttpClient
import com.datadog.android.okhttp.DatadogEventListener
import com.datadog.android.okhttp.DatadogInterceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
Expand Down Expand Up @@ -48,38 +50,46 @@ object CanvasNetworkAdapter {
return loggingInterceptor
}

private fun createClientBuilder(
token: String? = null,
retryOnConnectionFailure: Boolean,
includeRestRetry: Boolean,
): OkHttpClient.Builder {
val builder = OkHttpClient.Builder()
.retryOnConnectionFailure(retryOnConnectionFailure)
.addInterceptor(DatadogInterceptor.Builder(listOf("*.com")).build())
.eventListenerFactory(DatadogEventListener.Factory())
.addInterceptor(getLoggingInterceptor())
.readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)

token?.let { builder.addInterceptor(AuthRequestInterceptor(it)) }
if (includeRestRetry) builder.addInterceptor(RestRetryInterceptor)

return builder
}

private val adminOkHttpClient: OkHttpClient by lazy {
val authInterceptor = AuthRequestInterceptor(adminToken)

OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.addInterceptor(authInterceptor)
.addInterceptor(getLoggingInterceptor())
.addInterceptor(RestRetryInterceptor)
.readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)
.build()
createClientBuilder(
token = adminToken,
retryOnConnectionFailure = true,
includeRestRetry = true,
).build()
}

private fun okHttpClientWithToken(token: String): OkHttpClient {
val authInterceptor = AuthRequestInterceptor(token)

return OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.addInterceptor(authInterceptor)
.addInterceptor(getLoggingInterceptor())
.addInterceptor(RestRetryInterceptor)
.readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)
.build()
return createClientBuilder(
token = token,
retryOnConnectionFailure = true,
includeRestRetry = true,
).build()
}

private fun okHttpClientForApollo(token: String): OkHttpClient {
val authInterceptor = AuthRequestInterceptor(token)

return OkHttpClient.Builder()
.addInterceptor(authInterceptor)
.addInterceptor(getLoggingInterceptor())
.readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)
.build()
return createClientBuilder(
token = token,
retryOnConnectionFailure = false,
includeRestRetry = false,
).build()
}

fun getApolloClient(token: String): ApolloClient {
Expand All @@ -90,12 +100,10 @@ object CanvasNetworkAdapter {
}

private val noAuthOkHttpClient: OkHttpClient by lazy {
OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.addInterceptor(getLoggingInterceptor())
.addInterceptor(RestRetryInterceptor)
.readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)
.build()
createClientBuilder(
retryOnConnectionFailure = true,
includeRestRetry = true,
).build()
}

val adminRetrofit: Retrofit by lazy {
Expand Down
4 changes: 4 additions & 0 deletions libs/canvas-api-2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ dependencies {
implementation Libs.OKHTTP_URL_CONNECTION
implementation Libs.OKIO

/* Datadog */
implementation 'com.datadoghq:dd-sdk-android-okhttp:3.8.0'
implementation("com.datadoghq:dd-sdk-android-trace:3.8.0")

/* GraphQL */
/* NOTE: Newer versions of OkHttp affect the encoding of square brackets in @Query names. We're excluding the
* okhttp module here to avoid updating to a newer version until we're ready to handle the change. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package com.instructure.canvasapi2

import android.net.http.HttpResponseCache
import com.datadog.android.okhttp.DatadogEventListener
import com.datadog.android.okhttp.DatadogInterceptor
import com.google.gson.GsonBuilder
import com.instructure.canvasapi2.builders.RestParams
import com.instructure.canvasapi2.calladapter.DataResultCallAdapterFactory
Expand Down Expand Up @@ -65,6 +67,8 @@ protected constructor(var statusCallback: StatusCallback<*>?, private val authUs
OkHttpClient.Builder()
.addNetworkInterceptor(PactRequestInterceptor(authUser))
.addNetworkInterceptor(ResponseInterceptor())
.addInterceptor(DatadogInterceptor.Builder(listOf("*.com")).build())
.eventListenerFactory(DatadogEventListener.Factory())
.readTimeout(TIMEOUT_IN_SECONDS.toLong(), TimeUnit.SECONDS)
.authenticator(canvasAuthenticator)
.dispatcher(mDispatcher)
Expand Down Expand Up @@ -169,6 +173,8 @@ protected constructor(var statusCallback: StatusCallback<*>?, private val authUs
OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.addInterceptor(RollCallInterceptor())
.addInterceptor(DatadogInterceptor.Builder(listOf("*.com")).build())
.eventListenerFactory(DatadogEventListener.Factory())
.authenticator(canvasAuthenticator)
.readTimeout(TIMEOUT_IN_SECONDS.toLong(), TimeUnit.SECONDS)
.dispatcher(mDispatcher)
Expand Down Expand Up @@ -310,6 +316,8 @@ protected constructor(var statusCallback: StatusCallback<*>?, private val authUs
.addInterceptor(loggingInterceptor)
.addInterceptor(RequestInterceptor())
.addNetworkInterceptor(ResponseInterceptor())
.addInterceptor(DatadogInterceptor.Builder(listOf("*.com")).build())
.eventListenerFactory(DatadogEventListener.Factory())
.readTimeout(TIMEOUT_IN_SECONDS.toLong(), TimeUnit.SECONDS)
.dispatcher(mDispatcher)
.authenticator(canvasAuthenticator)
Expand Down
Loading