Skip to content

Commit

Permalink
RUMM-2536: Use SDK v2 configuration interfaces for features
Browse files Browse the repository at this point in the history
  • Loading branch information
0xnm committed Oct 11, 2022
1 parent 3200133 commit 3b40dae
Show file tree
Hide file tree
Showing 48 changed files with 712 additions and 915 deletions.
10 changes: 3 additions & 7 deletions dd-sdk-android/src/main/kotlin/com/datadog/android/Datadog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ import com.datadog.android.core.internal.utils.telemetry
import com.datadog.android.core.model.UserInfo
import com.datadog.android.privacy.TrackingConsent
import com.datadog.android.rum.GlobalRum
import com.datadog.android.rum.internal.RumFeature
import com.datadog.android.rum.internal.monitor.DatadogRumMonitor
import com.datadog.android.sessionreplay.internal.SessionReplayFeature
import com.datadog.android.v2.api.NoOpSdkCore
import com.datadog.android.v2.api.SdkCore
import com.datadog.android.v2.core.DatadogCore
Expand Down Expand Up @@ -206,7 +204,7 @@ object Datadog {
*/
@JvmStatic
fun enableRumDebugging(enable: Boolean) {
val rumFeature = ((globalSdkCore as? DatadogCore)?.rumFeature) as? RumFeature
val rumFeature = (globalSdkCore as? DatadogCore)?.rumFeature
if (enable) {
rumFeature?.enableDebugging()
} else {
Expand All @@ -221,8 +219,7 @@ object Datadog {
* sessions.
*/
fun stopSessionRecording() {
((globalSdkCore as? DatadogCore)?.sessionReplayFeature as? SessionReplayFeature)
?.stopRecording()
(globalSdkCore as? DatadogCore)?.sessionReplayFeature?.stopRecording()
}

/**
Expand All @@ -232,8 +229,7 @@ object Datadog {
* sessions.
*/
fun startSessionRecording() {
((globalSdkCore as? DatadogCore)?.sessionReplayFeature as? SessionReplayFeature)
?.startRecording()
(globalSdkCore as? DatadogCore)?.sessionReplayFeature?.startRecording()
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,64 @@
package com.datadog.android.core.internal

import android.content.Context
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.core.internal.data.upload.NoOpUploadScheduler
import com.datadog.android.core.internal.data.upload.UploadScheduler
import com.datadog.android.core.internal.persistence.NoOpPersistenceStrategy
import com.datadog.android.core.internal.persistence.PersistenceStrategy
import com.datadog.android.core.internal.persistence.file.FileMover
import com.datadog.android.core.internal.persistence.file.FileOrchestrator
import com.datadog.android.core.internal.persistence.file.FileReaderWriter
import com.datadog.android.core.internal.persistence.file.NoOpFileOrchestrator
import com.datadog.android.core.internal.persistence.file.advanced.FeatureFileOrchestrator
import com.datadog.android.core.internal.persistence.file.batch.BatchFileReaderWriter
import com.datadog.android.core.internal.privacy.ConsentProvider
import com.datadog.android.core.internal.utils.sdkLogger
import com.datadog.android.plugin.DatadogPlugin
import com.datadog.android.plugin.DatadogPluginConfig
import com.datadog.android.v2.api.EventBatchWriter
import com.datadog.android.v2.api.FeatureScope
import com.datadog.android.v2.api.FeatureStorageConfiguration
import com.datadog.android.v2.api.FeatureUploadConfiguration
import com.datadog.android.v2.api.NoOpInternalLogger
import com.datadog.android.v2.api.context.DatadogContext
import com.datadog.android.v2.core.internal.NoOpContextProvider
import com.datadog.android.v2.core.internal.data.upload.DataFlusher
import com.datadog.android.v2.core.internal.data.upload.DataUploadScheduler
import com.datadog.android.v2.core.internal.net.DataOkHttpUploader
import com.datadog.android.v2.core.internal.net.DataUploader
import com.datadog.android.v2.core.internal.net.NoOpDataUploader
import com.datadog.android.v2.core.internal.storage.ConsentAwareStorage
import com.datadog.android.v2.core.internal.storage.NoOpStorage
import com.datadog.android.v2.core.internal.storage.Storage
import java.util.concurrent.atomic.AtomicBoolean

@Suppress("TooManyFunctions")
internal abstract class SdkFeature<T : Any, C : Configuration.Feature>(
internal class SdkFeature(
internal val coreFeature: CoreFeature,
internal val storage: Storage,
internal val uploader: DataUploader
) {
private val featureName: String,
private val storageConfiguration: FeatureStorageConfiguration,
private val uploadConfiguration: FeatureUploadConfiguration
) : FeatureScope {

internal val initialized = AtomicBoolean(false)

internal var persistenceStrategy: PersistenceStrategy<T> = NoOpPersistenceStrategy()
internal var storage: Storage = NoOpStorage()
internal var uploader: DataUploader = NoOpDataUploader()
internal var uploadScheduler: UploadScheduler = NoOpUploadScheduler()
internal var fileOrchestrator: FileOrchestrator = NoOpFileOrchestrator()
private val featurePlugins: MutableList<DatadogPlugin> = mutableListOf()

// region SDK Feature

fun initialize(context: Context, configuration: C) {
fun initialize(context: Context, plugins: List<DatadogPlugin>) {
if (initialized.get()) {
return
}

persistenceStrategy = createPersistenceStrategy(context, storage, configuration)
storage = createStorage(featureName, storageConfiguration)

setupUploader()

registerPlugins(
configuration.plugins,
plugins,
DatadogPluginConfig(
context = context,
storageDir = coreFeature.storageDir,
Expand All @@ -58,11 +77,11 @@ internal abstract class SdkFeature<T : Any, C : Configuration.Feature>(
coreFeature.trackingConsentProvider
)

onInitialize(context, configuration)
onInitialize()

initialized.set(true)

onPostInitialized(context)
onPostInitialized()
}

fun isInitialized(): Boolean {
Expand All @@ -78,8 +97,10 @@ internal abstract class SdkFeature<T : Any, C : Configuration.Feature>(
if (initialized.get()) {
unregisterPlugins()
uploadScheduler.stopScheduling()
persistenceStrategy = NoOpPersistenceStrategy()
uploadScheduler = NoOpUploadScheduler()
storage = NoOpStorage()
uploader = NoOpDataUploader()
fileOrchestrator = NoOpFileOrchestrator()

onStop()

Expand All @@ -95,21 +116,37 @@ internal abstract class SdkFeature<T : Any, C : Configuration.Feature>(

// endregion

// region Abstract
// region FeatureScope

// TODO RUMM-0000 there is no thread switch here, it stays the same.
// Need to clarify the threading. We either switch thread here or in Storage.
// Or give the ability to specify the executor to the caller.
@Suppress("ThreadSafety")
override fun withWriteContext(callback: (DatadogContext, EventBatchWriter) -> Unit) {
val contextProvider = coreFeature.contextProvider
if (contextProvider is NoOpContextProvider) return
val context = contextProvider.context
storage.writeCurrentBatch(context) {
callback(context, it)
}
}

open fun onInitialize(context: Context, configuration: C) {}
// endregion

open fun onPostInitialized(context: Context) {}
// region Lifecycle

open fun onStop() {}
// TODO RUMM-0000 Should be moved out, to the public API of feature registration
@Suppress("EmptyFunctionBlock")
fun onInitialize() {}

open fun onPostStopped() {}
@Suppress("EmptyFunctionBlock")
fun onPostInitialized() {}

abstract fun createPersistenceStrategy(
context: Context,
storage: Storage,
configuration: C
): PersistenceStrategy<T>
@Suppress("EmptyFunctionBlock")
fun onStop() {}

@Suppress("EmptyFunctionBlock")
fun onPostStopped() {}

// endregion

Expand All @@ -136,6 +173,7 @@ internal abstract class SdkFeature<T : Any, C : Configuration.Feature>(

private fun setupUploader() {
uploadScheduler = if (coreFeature.isMainProcess) {
uploader = createUploader(uploadConfiguration)
DataUploadScheduler(
storage,
uploader,
Expand All @@ -151,10 +189,68 @@ internal abstract class SdkFeature<T : Any, C : Configuration.Feature>(
uploadScheduler.startScheduling()
}

// region Feature setup

private fun createStorage(
featureName: String,
storageConfiguration: FeatureStorageConfiguration
): Storage {
val fileOrchestrator = FeatureFileOrchestrator(
consentProvider = coreFeature.trackingConsentProvider,
storageDir = coreFeature.storageDir,
featureName = featureName,
executorService = coreFeature.persistenceExecutorService,
internalLogger = sdkLogger
)
this.fileOrchestrator = fileOrchestrator

return ConsentAwareStorage(
grantedOrchestrator = fileOrchestrator.grantedOrchestrator,
pendingOrchestrator = fileOrchestrator.pendingOrchestrator,
batchEventsReaderWriter = BatchFileReaderWriter.create(
internalLogger = sdkLogger,
encryption = coreFeature.localDataEncryption
),
batchMetadataReaderWriter = FileReaderWriter.create(
internalLogger = sdkLogger,
encryption = coreFeature.localDataEncryption
),
fileMover = FileMover(sdkLogger),
// TODO RUMM-0000 create internal logger
internalLogger = NoOpInternalLogger(),
filePersistenceConfig = coreFeature.buildFilePersistenceConfig().copy(
maxBatchSize = storageConfiguration.maxBatchSize,
maxItemSize = storageConfiguration.maxItemSize,
maxItemsPerBatch = storageConfiguration.maxItemsPerBatch,
oldFileThreshold = storageConfiguration.oldBatchThreshold
)
)
}

private fun createUploader(uploadConfiguration: FeatureUploadConfiguration): DataUploader {
return DataOkHttpUploader(
requestFactory = uploadConfiguration.requestFactory,
internalLogger = sdkLogger,
callFactory = coreFeature.okHttpClient,
sdkVersion = coreFeature.sdkVersion,
androidInfoProvider = coreFeature.androidInfoProvider
)
}

// endregion

// Used for nightly tests only
internal fun flushStoredData() {
// TODO RUMM-0000 should it just accept storage?
val flusher = DataFlusher(
coreFeature.contextProvider,
fileOrchestrator,
BatchFileReaderWriter.create(sdkLogger, coreFeature.localDataEncryption),
FileReaderWriter.create(sdkLogger, coreFeature.localDataEncryption),
FileMover(sdkLogger)
)
@Suppress("ThreadSafety")
persistenceStrategy.getFlusher().flush(uploader)
flusher.flush(uploader)
}

// endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import androidx.annotation.WorkerThread
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.datadog.android.Datadog
import com.datadog.android.core.internal.SdkFeature
import com.datadog.android.core.internal.net.UploadStatus
import com.datadog.android.core.internal.utils.devLogger
import com.datadog.android.v2.api.context.DatadogContext
import com.datadog.android.v2.core.DatadogCore
import com.datadog.android.v2.core.DatadogFeature
import com.datadog.android.v2.core.internal.net.DataUploader
import java.util.LinkedList
import java.util.Queue
Expand Down Expand Up @@ -47,7 +47,7 @@ internal class UploadWorker(
// be uploaded we put retry task to the end of queue, so that batches of other features
// have a chance to go.
val features =
globalSdkCore.getAllFeatures().mapNotNull { it as? DatadogFeature }.shuffled()
globalSdkCore.getAllFeatures().mapNotNull { it as? SdkFeature }.shuffled()

val tasksQueue = LinkedList<UploadNextBatchTask>()

Expand All @@ -71,7 +71,7 @@ internal class UploadWorker(
class UploadNextBatchTask(
private val taskQueue: Queue<UploadNextBatchTask>,
private val datadogCore: DatadogCore,
private val feature: DatadogFeature
private val feature: SdkFeature
) : Runnable {

@WorkerThread
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

package com.datadog.android.core.internal.persistence

import com.datadog.android.v2.core.internal.data.upload.Flusher
import com.datadog.android.v2.core.internal.storage.Storage
import com.datadog.tools.annotation.NoOpImplementation

/**
Expand All @@ -18,8 +16,4 @@ import com.datadog.tools.annotation.NoOpImplementation
internal interface PersistenceStrategy<T : Any> {

fun getWriter(): DataWriter<T>

fun getFlusher(): Flusher

fun getStorage(): Storage
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,17 @@ package com.datadog.android.core.internal.persistence.file.batch
import com.datadog.android.core.internal.persistence.DataWriter
import com.datadog.android.core.internal.persistence.PersistenceStrategy
import com.datadog.android.core.internal.persistence.Serializer
import com.datadog.android.core.internal.persistence.file.FileMover
import com.datadog.android.core.internal.persistence.file.FilePersistenceConfig
import com.datadog.android.core.internal.persistence.file.FileReaderWriter
import com.datadog.android.core.internal.persistence.file.advanced.ConsentAwareFileOrchestrator
import com.datadog.android.core.internal.persistence.file.advanced.ScheduledWriter
import com.datadog.android.log.Logger
import com.datadog.android.v2.core.internal.ContextProvider
import com.datadog.android.v2.core.internal.data.upload.DataFlusher
import com.datadog.android.v2.core.internal.data.upload.Flusher
import com.datadog.android.v2.core.internal.storage.Storage
import java.util.concurrent.ExecutorService

internal open class BatchFilePersistenceStrategy<T : Any>(
private val contextProvider: ContextProvider,
private val fileOrchestrator: ConsentAwareFileOrchestrator,
private val executorService: ExecutorService,
serializer: Serializer<T>,
internal val internalLogger: Logger,
internal val fileReaderWriter: BatchFileReaderWriter,
internal val metadataFileReaderWriter: FileReaderWriter,
internal val fileMover: FileMover,
internal val filePersistenceConfig: FilePersistenceConfig,
private val storage: Storage
) : PersistenceStrategy<T> {

Expand All @@ -48,20 +37,6 @@ internal open class BatchFilePersistenceStrategy<T : Any>(
return dataWriter
}

override fun getStorage(): Storage {
return storage
}

override fun getFlusher(): Flusher {
return DataFlusher(
contextProvider,
fileOrchestrator,
fileReaderWriter,
metadataFileReaderWriter,
fileMover
)
}

// endregion

// region Open
Expand Down
Loading

0 comments on commit 3b40dae

Please sign in to comment.