Skip to content

Commit

Permalink
RUMM-2172 Implement SDKv2 SingleStorage
Browse files Browse the repository at this point in the history
  • Loading branch information
xgouchet committed May 17, 2022
1 parent df077f0 commit 771eb8a
Show file tree
Hide file tree
Showing 16 changed files with 1,253 additions and 334 deletions.
41 changes: 41 additions & 0 deletions dd-sdk-android/apiSurface
Original file line number Diff line number Diff line change
Expand Up @@ -1494,6 +1494,20 @@ data class com.datadog.android.tracing.model.SpanEvent
fun toJson(): com.google.gson.JsonElement
companion object
fun fromJson(kotlin.String): SimCarrier
interface com.datadog.android.v2.api.EventBatchWriter
fun currentMetadata(): ByteArray?
fun write(ByteArray, String, ByteArray)
interface com.datadog.android.v2.api.InternalLogger
enum Level
- DEBUG
- INFO
- WARN
- ERROR
enum Target
- USER
- MAINTAINER
- TELEMETRY
fun log(Level, Target, String, Throwable?, Map<String, Any>)
interface com.datadog.android.v2.api.SDKCore
fun registerFeature(String, SDKFeatureStorageConfiguration, SDKFeatureUploadConfiguration)
fun getFeature(String): SDKFeature?
Expand All @@ -1510,6 +1524,33 @@ interface com.datadog.android.v2.api.SDKFeatureConfiguration
class com.datadog.android.v2.api.SDKFeatureStorageConfiguration
data class com.datadog.android.v2.api.SDKFeatureUploadConfiguration
constructor(String)
data class com.datadog.android.v2.api.context.ApplicationInfo
constructor(String, String, Int)
data class com.datadog.android.v2.api.context.CarrierInfo
constructor(String?, String?)
data class com.datadog.android.v2.api.context.DatadogContext
constructor(TimeInfo, ApplicationInfo, ProcessInfo, NetworkInfo, UserInfo, com.datadog.android.privacy.TrackingConsent, Map<String, Any>)
data class com.datadog.android.v2.api.context.NetworkInfo
constructor(Connectivity, CarrierInfo?)
enum Connectivity
- NETWORK_NOT_CONNECTED
- NETWORK_ETHERNET
- NETWORK_WIFI
- NETWORK_WIMAX
- NETWORK_BLUETOOTH
- NETWORK_2G
- NETWORK_3G
- NETWORK_4G
- NETWORK_5G
- NETWORK_MOBILE_OTHER
- NETWORK_CELLULAR
- NETWORK_OTHER
data class com.datadog.android.v2.api.context.ProcessInfo
constructor(Boolean, Int)
data class com.datadog.android.v2.api.context.TimeInfo
constructor(Long, Long)
data class com.datadog.android.v2.api.context.UserInfo
constructor(String?, String?, String?, Map<String, Any>)
class com.datadog.android.v2.core.DatadogCore : com.datadog.android.v2.api.SDKCore
constructor(android.content.Context, com.datadog.android.core.configuration.Credentials, com.datadog.android.core.configuration.Configuration)
override fun registerFeature(String, com.datadog.android.v2.api.SDKFeatureStorageConfiguration, com.datadog.android.v2.api.SDKFeatureUploadConfiguration)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.v2.api

/**
* A Listener to be notified when an event is actually written in the storage,
* or when a write operation failed.
*/
internal interface BatchWriterListener {
/**
* Called whenever data is written successfully.
* @param eventId the id of the written event
*/
fun onDataWritten(eventId: String)

/**
* Called whenever data failed to be written.
* @param eventId the id of the event that failed
*/
fun onDataWriteFailed(eventId: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.v2.api

/**
* Utility allowing [FeatureScope] to write events in the storage to be uploaded asynchronously.
*/
interface EventBatchWriter {

/**
* @return the metadata of the current writeable file
*/
fun currentMetadata(): ByteArray?

/**
* Writes the content of the event to the current available batch.
* @param event the event to write
* @param eventId a unique identifier for the event (used to identify events in
* the [BatchWriterListener] callbacks).
* @param newMetadata the updated metadata
*/
fun write(
event: ByteArray,
eventId: String,
newMetadata: ByteArray
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.v2.api

import com.datadog.tools.annotation.NoOpImplementation

/**
* A Logger used to log messages from the internal implementation of the Datadog SDKs.
*/
@NoOpImplementation
interface InternalLogger {

/**
* The severity level of a logged message.
*/
enum class Level {
DEBUG,
INFO,
WARN,
ERROR;
}

/**
* The target handler for a log message.
*/
enum class Target {
USER,
MAINTAINER,
TELEMETRY
}

/**
* Logs a message from the internal implementation.
* @param level the severity level of the log
* @param target the target handler for the log
* @param message the log message
* @param error an optional throwable error
* @param attributes an optional map of custom attributes
*/
fun log(
level: Level,
target: Target,
message: String,
error: Throwable?,
attributes: Map<String, Any>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import com.datadog.android.privacy.TrackingConsent
* @property featuresContext agnostic dictionary with information from all features registered to
* the parent SDK instance
*/
data class SDKContext(
data class DatadogContext(
val time: TimeInfo,
val applicationInfo: ApplicationInfo,
val processInfo: ProcessInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ package com.datadog.android.v2.api.context
/**
* Holds information about the current local and server time.
* @property deviceTimeNs the current time as known by the System on the device (nanoseconds)
* @property serverTimeNs the current time synchronized with our NTP server(s) (nanoseconds)
* @property serverTimeNs the current time synchronized with Datadog's NTP server(s) (nanoseconds)
*/
data class TimeInfo(
val deviceTimeNs: Long,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.v2.core.internal.storage

internal fun interface BatchConfirmation {
fun markAsRead(deleteBatch: Boolean)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.v2.core.internal.storage

import java.io.File

internal data class BatchId(
val id: String
) {

fun matchesFile(file: File): Boolean {
return file.extractFileId() == id
}

companion object {

fun fromFile(file: File): BatchId {
return BatchId(file.extractFileId())
}

private fun File.extractFileId(): String {
return absolutePath
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.v2.core.internal.storage

internal fun interface BatchReader {

fun read(batchId: BatchId): List<ByteArray>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.v2.core.internal.storage

import com.datadog.android.v2.api.EventBatchWriter

internal interface BatchWriter : EventBatchWriter
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.v2.core.internal.storage

import com.datadog.android.core.internal.persistence.file.FileHandler
import com.datadog.android.core.internal.persistence.file.FileOrchestrator
import com.datadog.android.privacy.TrackingConsent
import com.datadog.android.v2.api.BatchWriterListener
import com.datadog.android.v2.api.InternalLogger
import com.datadog.android.v2.api.context.DatadogContext
import java.io.File
import java.util.Locale

internal class ConsentAwareStorage(
private val grantedOrchestrator: FileOrchestrator,
private val pendingOrchestrator: FileOrchestrator,
private val handler: FileHandler,
private val listener: BatchWriterListener,
private val internalLogger: InternalLogger
) : Storage {

/**
* Keeps track of files currently being read.
*/
private val lockedFiles: MutableSet<File> = mutableSetOf()

/** @inheritdoc */
override fun writeCurrentBatch(
datadogContext: DatadogContext,
callback: (BatchWriter) -> Unit
) {
val orchestrator = when (datadogContext.trackingConsent) {
TrackingConsent.GRANTED -> grantedOrchestrator
TrackingConsent.PENDING -> pendingOrchestrator
TrackingConsent.NOT_GRANTED -> null
}

val writer = object : BatchWriter {
override fun currentMetadata(): ByteArray? {
// TODO RUMM-2186 handle writing/updating batch metadata in separate file
return null
}

override fun write(event: ByteArray, eventId: String, newMetadata: ByteArray) {
// prevent useless operation for empty event / null orchestrator
if (event.isEmpty() || orchestrator == null) {
listener.onDataWritten(eventId)
return
}

val file = orchestrator.getWritableFile(event.size)

if (file != null && handler.writeData(file, event, true)) {
listener.onDataWritten(eventId)
} else {
listener.onDataWriteFailed(eventId)
}
}
}
callback.invoke(writer)
}

/** @inheritdoc */
override fun readNextBatch(
datadogContext: DatadogContext,
callback: (BatchId, BatchReader) -> Unit
) {
val batchFile = synchronized(lockedFiles) {
grantedOrchestrator.getReadableFile(lockedFiles)?.also {
lockedFiles.add(it)
} ?: return
}

val batchId = BatchId.fromFile(batchFile)
val reader = BatchReader { handler.readData(batchFile) }
callback(batchId, reader)
}

/** @inheritdoc */
override fun confirmBatchRead(batchId: BatchId, callback: (BatchConfirmation) -> Unit) {
val batchFile = synchronized(lockedFiles) {
lockedFiles.firstOrNull { batchId.matchesFile(it) }
} ?: return
val confirmation = BatchConfirmation { delete ->
if (delete) {
val result = handler.delete(batchFile)
if (!result) {
internalLogger.log(
InternalLogger.Level.WARN,
InternalLogger.Target.MAINTAINER,
WARNING_DELETE_FAILED.format(Locale.US, batchFile.path),
null,
emptyMap()
)
}
}
synchronized(lockedFiles) {
lockedFiles.remove(batchFile)
}
}
callback(confirmation)
}

companion object {
internal const val WARNING_DELETE_FAILED = "Unable to delete file: %s"
}
}
Loading

0 comments on commit 771eb8a

Please sign in to comment.