diff --git a/build-logic/src/main/kotlin/com/datadog/gradle/plugin/jsonschema/generator/FileGenerator.kt b/build-logic/src/main/kotlin/com/datadog/gradle/plugin/jsonschema/generator/FileGenerator.kt index ea0acd3ea5..8b3afcde93 100644 --- a/build-logic/src/main/kotlin/com/datadog/gradle/plugin/jsonschema/generator/FileGenerator.kt +++ b/build-logic/src/main/kotlin/com/datadog/gradle/plugin/jsonschema/generator/FileGenerator.kt @@ -23,7 +23,7 @@ class FileGenerator( private val classGenerator = ClassGenerator(packageName, knownTypes) private val enumGenerator = EnumClassGenerator(packageName, knownTypes) - private val oneOfPrimitiveOptionGenerator = OneOfPrimitiveOptionGenerator(packageName) + private val oneOfPrimitiveOptionGenerator = OneOfPrimitiveOptionGenerator(packageName, knownTypes) private val multiClassGenerator = MultiClassGenerator( classGenerator = classGenerator, diff --git a/build-logic/src/main/kotlin/com/datadog/gradle/plugin/jsonschema/generator/OneOfPrimitiveOptionGenerator.kt b/build-logic/src/main/kotlin/com/datadog/gradle/plugin/jsonschema/generator/OneOfPrimitiveOptionGenerator.kt index bb8980192a..761dbdd875 100644 --- a/build-logic/src/main/kotlin/com/datadog/gradle/plugin/jsonschema/generator/OneOfPrimitiveOptionGenerator.kt +++ b/build-logic/src/main/kotlin/com/datadog/gradle/plugin/jsonschema/generator/OneOfPrimitiveOptionGenerator.kt @@ -21,10 +21,11 @@ import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.jvm.throws class OneOfPrimitiveOptionGenerator( - packageName: String + packageName: String, + knownTypes: MutableSet = mutableSetOf() ) : TypeSpecGenerator( packageName, - mutableSetOf() + knownTypes ) { override fun generate( definition: TypeDefinition.Primitive, diff --git a/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/JsonSchemaReaderTest.kt b/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/JsonSchemaReaderTest.kt index 44ac4547ef..975fda4540 100644 --- a/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/JsonSchemaReaderTest.kt +++ b/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/JsonSchemaReaderTest.kt @@ -79,7 +79,10 @@ class JsonSchemaReaderTest { arrayOf("one_of_nested", WeirdCombo), arrayOf("required_for_other_all_of", RequiredForOtherAllOf), arrayOf("path_array_with_integer", PathArrayWithInteger), - arrayOf("path_array_with_number", PathArrayWithNumber) + arrayOf("path_array_with_number", PathArrayWithNumber), + arrayOf("one_of_primitive_ref", OneOfPrimitiveRef), + arrayOf("cross_file_one_of_primitive_a", CrossFileOneOfPrimitiveA), + arrayOf("cross_file_one_of_primitive_b", CrossFileOneOfPrimitiveB) ) } } diff --git a/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/ModelValidationTest.kt b/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/ModelValidationTest.kt index ff8f7cfb6a..ab2096aff9 100644 --- a/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/ModelValidationTest.kt +++ b/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/ModelValidationTest.kt @@ -211,7 +211,10 @@ class ModelValidationTest { arrayOf("sets", OutputInfo("Video")), arrayOf("one_of_nested", OutputInfo("WeirdCombo")), arrayOf("path_array_with_integer", OutputInfo("PathArrayWithInteger")), - arrayOf("path_array_with_number", OutputInfo("PathArrayWithNumber")) + arrayOf("path_array_with_number", OutputInfo("PathArrayWithNumber")), + arrayOf("one_of_primitive_ref", OutputInfo("OneOfPrimitiveRef")), + arrayOf("cross_file_one_of_primitive_a", OutputInfo("CrossFileOneOfPrimitiveA")), + arrayOf("cross_file_one_of_primitive_b", OutputInfo("CrossFileOneOfPrimitiveB")) ) } } diff --git a/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/TestDefinitions.kt b/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/TestDefinitions.kt index f25595aa6c..ba24c5e765 100644 --- a/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/TestDefinitions.kt +++ b/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/TestDefinitions.kt @@ -1112,3 +1112,47 @@ val PathArrayWithNumber = TypeDefinition.Class( ), required = setOf("path") ) + +val OneOfPrimitivePath = TypeDefinition.OneOfClass( + name = "Path", + options = listOf( + TypeDefinition.OneOfClass.Option.Primitive( + primitive = TypeDefinition.Primitive( + type = JsonPrimitiveType.STRING, + description = "string element" + ) + ), + TypeDefinition.OneOfClass.Option.Primitive( + primitive = TypeDefinition.Primitive( + type = JsonPrimitiveType.INTEGER, + description = "integer element" + ) + ) + ), + description = "This is a definition of a path" +) + +val OneOfPrimitiveRef = TypeDefinition.Class( + name = "OneOfPrimitiveRef", + properties = listOf( + TypeProperty("from", OneOfPrimitivePath), + TypeProperty("to", OneOfPrimitivePath) + ), + required = setOf("from") +) + +val CrossFileOneOfPrimitiveA = TypeDefinition.Class( + name = "CrossFileOneOfPrimitiveA", + properties = listOf( + TypeProperty("path", OneOfPrimitivePath) + ), + required = setOf("path") +) + +val CrossFileOneOfPrimitiveB = TypeDefinition.Class( + name = "CrossFileOneOfPrimitiveB", + properties = listOf( + TypeProperty("path", OneOfPrimitivePath) + ), + required = setOf("path") +) diff --git a/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/generator/FileGeneratorTest.kt b/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/generator/FileGeneratorTest.kt index 6e63ba6119..1bf88334db 100644 --- a/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/generator/FileGeneratorTest.kt +++ b/build-logic/src/test/kotlin/com/datadog/gradle/plugin/jsonschema/generator/FileGeneratorTest.kt @@ -13,6 +13,8 @@ import com.datadog.gradle.plugin.jsonschema.Book import com.datadog.gradle.plugin.jsonschema.Comment import com.datadog.gradle.plugin.jsonschema.Company import com.datadog.gradle.plugin.jsonschema.Conflict +import com.datadog.gradle.plugin.jsonschema.CrossFileOneOfPrimitiveA +import com.datadog.gradle.plugin.jsonschema.CrossFileOneOfPrimitiveB import com.datadog.gradle.plugin.jsonschema.Customer import com.datadog.gradle.plugin.jsonschema.DateTime import com.datadog.gradle.plugin.jsonschema.Delivery @@ -23,6 +25,7 @@ import com.datadog.gradle.plugin.jsonschema.Jacket import com.datadog.gradle.plugin.jsonschema.Location import com.datadog.gradle.plugin.jsonschema.Message import com.datadog.gradle.plugin.jsonschema.NoOpLogger +import com.datadog.gradle.plugin.jsonschema.OneOfPrimitiveRef import com.datadog.gradle.plugin.jsonschema.Opus import com.datadog.gradle.plugin.jsonschema.Order import com.datadog.gradle.plugin.jsonschema.Paper @@ -124,7 +127,10 @@ class FileGeneratorTest { arrayOf(Video, "Video"), arrayOf(WeirdCombo, "WeirdCombo"), arrayOf(PathArrayWithInteger, "PathArrayWithInteger"), - arrayOf(PathArrayWithNumber, "PathArrayWithNumber") + arrayOf(PathArrayWithNumber, "PathArrayWithNumber"), + arrayOf(OneOfPrimitiveRef, "OneOfPrimitiveRef"), + arrayOf(CrossFileOneOfPrimitiveA, "CrossFileOneOfPrimitiveA"), + arrayOf(CrossFileOneOfPrimitiveB, "CrossFileOneOfPrimitiveB") ) } } diff --git a/build-logic/src/test/kotlin/com/example/forgery/CrossFileOneOfPrimitiveAForgeryFactory.kt b/build-logic/src/test/kotlin/com/example/forgery/CrossFileOneOfPrimitiveAForgeryFactory.kt new file mode 100644 index 0000000000..068d3de755 --- /dev/null +++ b/build-logic/src/test/kotlin/com/example/forgery/CrossFileOneOfPrimitiveAForgeryFactory.kt @@ -0,0 +1,24 @@ +/* + * 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.example.forgery + +import com.example.model.CrossFileOneOfPrimitiveA +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.ForgeryFactory + +internal class CrossFileOneOfPrimitiveAForgeryFactory : ForgeryFactory { + override fun getForgery(forge: Forge): CrossFileOneOfPrimitiveA { + return CrossFileOneOfPrimitiveA( + path = forge.anElementFrom( + listOf( + CrossFileOneOfPrimitiveA.Path.String(forge.aString()), + CrossFileOneOfPrimitiveA.Path.Long(forge.aLong()) + ) + ) + ) + } +} diff --git a/build-logic/src/test/kotlin/com/example/forgery/CrossFileOneOfPrimitiveBForgeryFactory.kt b/build-logic/src/test/kotlin/com/example/forgery/CrossFileOneOfPrimitiveBForgeryFactory.kt new file mode 100644 index 0000000000..eea6fbefe6 --- /dev/null +++ b/build-logic/src/test/kotlin/com/example/forgery/CrossFileOneOfPrimitiveBForgeryFactory.kt @@ -0,0 +1,24 @@ +/* + * 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.example.forgery + +import com.example.model.CrossFileOneOfPrimitiveB +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.ForgeryFactory + +internal class CrossFileOneOfPrimitiveBForgeryFactory : ForgeryFactory { + override fun getForgery(forge: Forge): CrossFileOneOfPrimitiveB { + return CrossFileOneOfPrimitiveB( + path = forge.anElementFrom( + listOf( + CrossFileOneOfPrimitiveB.Path.String(forge.aString()), + CrossFileOneOfPrimitiveB.Path.Long(forge.aLong()) + ) + ) + ) + } +} diff --git a/build-logic/src/test/kotlin/com/example/forgery/ModelForgeryConfigurator.kt b/build-logic/src/test/kotlin/com/example/forgery/ModelForgeryConfigurator.kt index 70967f529d..60919d0adf 100644 --- a/build-logic/src/test/kotlin/com/example/forgery/ModelForgeryConfigurator.kt +++ b/build-logic/src/test/kotlin/com/example/forgery/ModelForgeryConfigurator.kt @@ -40,5 +40,8 @@ internal class ModelForgeryConfigurator : ForgeConfigurator { forge.addFactory(WeirdComboForgeryFactory()) forge.addFactory(PathArrayWithIntegerForgeryFactory()) forge.addFactory(PathArrayWithNumberForgeryFactory()) + forge.addFactory(OneOfPrimitiveRefForgeryFactory()) + forge.addFactory(CrossFileOneOfPrimitiveAForgeryFactory()) + forge.addFactory(CrossFileOneOfPrimitiveBForgeryFactory()) } } diff --git a/build-logic/src/test/kotlin/com/example/forgery/OneOfPrimitiveRefForgeryFactory.kt b/build-logic/src/test/kotlin/com/example/forgery/OneOfPrimitiveRefForgeryFactory.kt new file mode 100644 index 0000000000..000a5e8575 --- /dev/null +++ b/build-logic/src/test/kotlin/com/example/forgery/OneOfPrimitiveRefForgeryFactory.kt @@ -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.example.forgery + +import com.example.model.OneOfPrimitiveRef +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.ForgeryFactory + +internal class OneOfPrimitiveRefForgeryFactory : ForgeryFactory { + override fun getForgery(forge: Forge): OneOfPrimitiveRef { + return OneOfPrimitiveRef( + from = forge.aPath(), + to = forge.aNullable { aPath() } + ) + } + + private fun Forge.aPath(): OneOfPrimitiveRef.Path { + return anElementFrom( + listOf( + OneOfPrimitiveRef.Path.String(aString()), + OneOfPrimitiveRef.Path.Long(aLong()) + ) + ) + } +} diff --git a/build-logic/src/test/kotlin/com/example/model/CrossFileOneOfPrimitiveA.kt b/build-logic/src/test/kotlin/com/example/model/CrossFileOneOfPrimitiveA.kt new file mode 100644 index 0000000000..cd669c459c --- /dev/null +++ b/build-logic/src/test/kotlin/com/example/model/CrossFileOneOfPrimitiveA.kt @@ -0,0 +1,208 @@ +package com.example.model + +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.google.gson.JsonParseException +import com.google.gson.JsonParser +import com.google.gson.JsonPrimitive +import java.lang.IllegalStateException +import java.lang.NullPointerException +import java.lang.NumberFormatException +import java.lang.UnsupportedOperationException +import kotlin.String +import kotlin.jvm.JvmStatic +import kotlin.jvm.Throws + +/** + * @param path This is a definition of a path + */ +public data class CrossFileOneOfPrimitiveA( + public val path: Path, +) { + public fun toJson(): JsonElement { + val json = JsonObject() + json.add("path", path.toJson()) + return json + } + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: String): CrossFileOneOfPrimitiveA { + try { + val jsonObject = JsonParser.parseString(jsonString).asJsonObject + return fromJsonObject(jsonObject) + } catch (e: IllegalStateException) { + throw JsonParseException( + "Unable to parse json into type CrossFileOneOfPrimitiveA", + e + ) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonObject(jsonObject: JsonObject): CrossFileOneOfPrimitiveA { + try { + val path = jsonObject.get("path").let { + Path.fromJsonElement(it) + } + return CrossFileOneOfPrimitiveA(path) + } catch (e: IllegalStateException) { + throw JsonParseException( + "Unable to parse json into type CrossFileOneOfPrimitiveA", + e + ) + } catch (e: NumberFormatException) { + throw JsonParseException( + "Unable to parse json into type CrossFileOneOfPrimitiveA", + e + ) + } catch (e: NullPointerException) { + throw JsonParseException( + "Unable to parse json into type CrossFileOneOfPrimitiveA", + e + ) + } + } + } + + /** + * This is a definition of a path + */ + public sealed class Path { + public abstract fun toJson(): JsonElement + + /** + * string element + */ + public data class String( + public val item: kotlin.String, + ) : Path() { + override fun toJson(): JsonElement = JsonPrimitive(item) + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: kotlin.String): String { + val jsonElement = JsonParser.parseString(jsonString) + try { + return fromJsonPrimitive(jsonElement.asJsonPrimitive) + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type String", e) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonPrimitive(jsonPrimitive: JsonPrimitive): String { + try { + if (jsonPrimitive.isString) { + return String(jsonPrimitive.asString) + } else { + throw JsonParseException("Can't convert jsonPrimitive to String") + } + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type String", e) + } catch (e: UnsupportedOperationException) { + throw JsonParseException("Unable to parse json into type String", e) + } + } + } + } + + /** + * integer element + */ + public data class Long( + public val item: kotlin.Long, + ) : Path() { + override fun toJson(): JsonElement = JsonPrimitive(item) + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: kotlin.String): Long { + val jsonElement = JsonParser.parseString(jsonString) + try { + return fromJsonPrimitive(jsonElement.asJsonPrimitive) + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type Long", e) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonPrimitive(jsonPrimitive: JsonPrimitive): Long { + try { + if (jsonPrimitive.isNumber) { + return Long(jsonPrimitive.asLong) + } else { + throw JsonParseException("Can't convert jsonPrimitive to Long") + } + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type Long", e) + } catch (e: NumberFormatException) { + throw JsonParseException("Unable to parse json into type Long", e) + } catch (e: UnsupportedOperationException) { + throw JsonParseException("Unable to parse json into type Long", e) + } + } + } + } + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: kotlin.String): Path { + try { + val jsonElement = JsonParser.parseString(jsonString) + return fromJsonElement(jsonElement) + } catch (e: IllegalStateException) { + throw JsonParseException( + "Unable to parse json into one of type Path", + e + ) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonElement(jsonElement: JsonElement): Path { + val errors = mutableListOf() + val asString = try { + if (jsonElement is JsonPrimitive) { + String.fromJsonPrimitive(jsonElement) + } else { + throw JsonParseException("Unable to parse json into type " + + "kotlin.String") + } + } catch (e: JsonParseException) { + errors.add(e) + null + } + val asLong = try { + if (jsonElement is JsonPrimitive) { + Long.fromJsonPrimitive(jsonElement) + } else { + throw JsonParseException("Unable to parse json into type " + + "kotlin.Long") + } + } catch (e: JsonParseException) { + errors.add(e) + null + } + val result = arrayOf( + asString, + asLong, + ).firstOrNull { it != null } + if (result == null) { + val message = "Unable to parse json into one of type \n" + "Path\n" + + errors.joinToString("\n") { it.message.toString() } + throw JsonParseException(message) + } + return result + } + } + } +} diff --git a/build-logic/src/test/kotlin/com/example/model/CrossFileOneOfPrimitiveB.kt b/build-logic/src/test/kotlin/com/example/model/CrossFileOneOfPrimitiveB.kt new file mode 100644 index 0000000000..650f48256f --- /dev/null +++ b/build-logic/src/test/kotlin/com/example/model/CrossFileOneOfPrimitiveB.kt @@ -0,0 +1,208 @@ +package com.example.model + +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.google.gson.JsonParseException +import com.google.gson.JsonParser +import com.google.gson.JsonPrimitive +import java.lang.IllegalStateException +import java.lang.NullPointerException +import java.lang.NumberFormatException +import java.lang.UnsupportedOperationException +import kotlin.String +import kotlin.jvm.JvmStatic +import kotlin.jvm.Throws + +/** + * @param path This is a definition of a path + */ +public data class CrossFileOneOfPrimitiveB( + public val path: Path, +) { + public fun toJson(): JsonElement { + val json = JsonObject() + json.add("path", path.toJson()) + return json + } + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: String): CrossFileOneOfPrimitiveB { + try { + val jsonObject = JsonParser.parseString(jsonString).asJsonObject + return fromJsonObject(jsonObject) + } catch (e: IllegalStateException) { + throw JsonParseException( + "Unable to parse json into type CrossFileOneOfPrimitiveB", + e + ) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonObject(jsonObject: JsonObject): CrossFileOneOfPrimitiveB { + try { + val path = jsonObject.get("path").let { + Path.fromJsonElement(it) + } + return CrossFileOneOfPrimitiveB(path) + } catch (e: IllegalStateException) { + throw JsonParseException( + "Unable to parse json into type CrossFileOneOfPrimitiveB", + e + ) + } catch (e: NumberFormatException) { + throw JsonParseException( + "Unable to parse json into type CrossFileOneOfPrimitiveB", + e + ) + } catch (e: NullPointerException) { + throw JsonParseException( + "Unable to parse json into type CrossFileOneOfPrimitiveB", + e + ) + } + } + } + + /** + * This is a definition of a path + */ + public sealed class Path { + public abstract fun toJson(): JsonElement + + /** + * string element + */ + public data class String( + public val item: kotlin.String, + ) : Path() { + override fun toJson(): JsonElement = JsonPrimitive(item) + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: kotlin.String): String { + val jsonElement = JsonParser.parseString(jsonString) + try { + return fromJsonPrimitive(jsonElement.asJsonPrimitive) + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type String", e) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonPrimitive(jsonPrimitive: JsonPrimitive): String { + try { + if (jsonPrimitive.isString) { + return String(jsonPrimitive.asString) + } else { + throw JsonParseException("Can't convert jsonPrimitive to String") + } + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type String", e) + } catch (e: UnsupportedOperationException) { + throw JsonParseException("Unable to parse json into type String", e) + } + } + } + } + + /** + * integer element + */ + public data class Long( + public val item: kotlin.Long, + ) : Path() { + override fun toJson(): JsonElement = JsonPrimitive(item) + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: kotlin.String): Long { + val jsonElement = JsonParser.parseString(jsonString) + try { + return fromJsonPrimitive(jsonElement.asJsonPrimitive) + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type Long", e) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonPrimitive(jsonPrimitive: JsonPrimitive): Long { + try { + if (jsonPrimitive.isNumber) { + return Long(jsonPrimitive.asLong) + } else { + throw JsonParseException("Can't convert jsonPrimitive to Long") + } + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type Long", e) + } catch (e: NumberFormatException) { + throw JsonParseException("Unable to parse json into type Long", e) + } catch (e: UnsupportedOperationException) { + throw JsonParseException("Unable to parse json into type Long", e) + } + } + } + } + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: kotlin.String): Path { + try { + val jsonElement = JsonParser.parseString(jsonString) + return fromJsonElement(jsonElement) + } catch (e: IllegalStateException) { + throw JsonParseException( + "Unable to parse json into one of type Path", + e + ) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonElement(jsonElement: JsonElement): Path { + val errors = mutableListOf() + val asString = try { + if (jsonElement is JsonPrimitive) { + String.fromJsonPrimitive(jsonElement) + } else { + throw JsonParseException("Unable to parse json into type " + + "kotlin.String") + } + } catch (e: JsonParseException) { + errors.add(e) + null + } + val asLong = try { + if (jsonElement is JsonPrimitive) { + Long.fromJsonPrimitive(jsonElement) + } else { + throw JsonParseException("Unable to parse json into type " + + "kotlin.Long") + } + } catch (e: JsonParseException) { + errors.add(e) + null + } + val result = arrayOf( + asString, + asLong, + ).firstOrNull { it != null } + if (result == null) { + val message = "Unable to parse json into one of type \n" + "Path\n" + + errors.joinToString("\n") { it.message.toString() } + throw JsonParseException(message) + } + return result + } + } + } +} diff --git a/build-logic/src/test/kotlin/com/example/model/OneOfPrimitiveRef.kt b/build-logic/src/test/kotlin/com/example/model/OneOfPrimitiveRef.kt new file mode 100644 index 0000000000..c3b8b3754d --- /dev/null +++ b/build-logic/src/test/kotlin/com/example/model/OneOfPrimitiveRef.kt @@ -0,0 +1,216 @@ +package com.example.model + +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.google.gson.JsonParseException +import com.google.gson.JsonParser +import com.google.gson.JsonPrimitive +import java.lang.IllegalStateException +import java.lang.NullPointerException +import java.lang.NumberFormatException +import java.lang.UnsupportedOperationException +import kotlin.String +import kotlin.jvm.JvmStatic +import kotlin.jvm.Throws + +/** + * @param from This is a definition of a path + * @param to This is a definition of a path + */ +public data class OneOfPrimitiveRef( + public val from: Path, + public val to: Path? = null, +) { + public fun toJson(): JsonElement { + val json = JsonObject() + json.add("from", from.toJson()) + to?.let { toNonNull -> + json.add("to", toNonNull.toJson()) + } + return json + } + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: String): OneOfPrimitiveRef { + try { + val jsonObject = JsonParser.parseString(jsonString).asJsonObject + return fromJsonObject(jsonObject) + } catch (e: IllegalStateException) { + throw JsonParseException( + "Unable to parse json into type OneOfPrimitiveRef", + e + ) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonObject(jsonObject: JsonObject): OneOfPrimitiveRef { + try { + val from = jsonObject.get("from").let { + Path.fromJsonElement(it) + } + val to = jsonObject.get("to")?.let { + Path.fromJsonElement(it) + } + return OneOfPrimitiveRef(from, to) + } catch (e: IllegalStateException) { + throw JsonParseException( + "Unable to parse json into type OneOfPrimitiveRef", + e + ) + } catch (e: NumberFormatException) { + throw JsonParseException( + "Unable to parse json into type OneOfPrimitiveRef", + e + ) + } catch (e: NullPointerException) { + throw JsonParseException( + "Unable to parse json into type OneOfPrimitiveRef", + e + ) + } + } + } + + /** + * This is a definition of a path + */ + public sealed class Path { + public abstract fun toJson(): JsonElement + + /** + * string element + */ + public data class String( + public val item: kotlin.String, + ) : Path() { + override fun toJson(): JsonElement = JsonPrimitive(item) + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: kotlin.String): String { + val jsonElement = JsonParser.parseString(jsonString) + try { + return fromJsonPrimitive(jsonElement.asJsonPrimitive) + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type String", e) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonPrimitive(jsonPrimitive: JsonPrimitive): String { + try { + if (jsonPrimitive.isString) { + return String(jsonPrimitive.asString) + } else { + throw JsonParseException("Can't convert jsonPrimitive to String") + } + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type String", e) + } catch (e: UnsupportedOperationException) { + throw JsonParseException("Unable to parse json into type String", e) + } + } + } + } + + /** + * integer element + */ + public data class Long( + public val item: kotlin.Long, + ) : Path() { + override fun toJson(): JsonElement = JsonPrimitive(item) + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: kotlin.String): Long { + val jsonElement = JsonParser.parseString(jsonString) + try { + return fromJsonPrimitive(jsonElement.asJsonPrimitive) + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type Long", e) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonPrimitive(jsonPrimitive: JsonPrimitive): Long { + try { + if (jsonPrimitive.isNumber) { + return Long(jsonPrimitive.asLong) + } else { + throw JsonParseException("Can't convert jsonPrimitive to Long") + } + } catch (e: IllegalStateException) { + throw JsonParseException("Unable to parse json into type Long", e) + } catch (e: NumberFormatException) { + throw JsonParseException("Unable to parse json into type Long", e) + } catch (e: UnsupportedOperationException) { + throw JsonParseException("Unable to parse json into type Long", e) + } + } + } + } + + public companion object { + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJson(jsonString: kotlin.String): Path { + try { + val jsonElement = JsonParser.parseString(jsonString) + return fromJsonElement(jsonElement) + } catch (e: IllegalStateException) { + throw JsonParseException( + "Unable to parse json into one of type Path", + e + ) + } + } + + @JvmStatic + @Throws(JsonParseException::class) + public fun fromJsonElement(jsonElement: JsonElement): Path { + val errors = mutableListOf() + val asString = try { + if (jsonElement is JsonPrimitive) { + String.fromJsonPrimitive(jsonElement) + } else { + throw JsonParseException("Unable to parse json into type " + + "kotlin.String") + } + } catch (e: JsonParseException) { + errors.add(e) + null + } + val asLong = try { + if (jsonElement is JsonPrimitive) { + Long.fromJsonPrimitive(jsonElement) + } else { + throw JsonParseException("Unable to parse json into type " + + "kotlin.Long") + } + } catch (e: JsonParseException) { + errors.add(e) + null + } + val result = arrayOf( + asString, + asLong, + ).firstOrNull { it != null } + if (result == null) { + val message = "Unable to parse json into one of type \n" + "Path\n" + + errors.joinToString("\n") { it.message.toString() } + throw JsonParseException(message) + } + return result + } + } + } +} diff --git a/build-logic/src/test/resources/input/cross_file_one_of_primitive.json b/build-logic/src/test/resources/input/cross_file_one_of_primitive.json new file mode 100644 index 0000000000..7744920ad8 --- /dev/null +++ b/build-logic/src/test/resources/input/cross_file_one_of_primitive.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Path", + "description": "This is a definition of a path", + "oneOf": [ + { + "type": "string", + "description": "string element" + }, + { + "type": "integer", + "description": "integer element" + } + ] +} diff --git a/build-logic/src/test/resources/input/cross_file_one_of_primitive_a.json b/build-logic/src/test/resources/input/cross_file_one_of_primitive_a.json new file mode 100644 index 0000000000..d1765a0547 --- /dev/null +++ b/build-logic/src/test/resources/input/cross_file_one_of_primitive_a.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CrossFileOneOfPrimitiveA", + "type": "object", + "required": ["path"], + "properties": { + "path": { "$ref": "cross_file_one_of_primitive.json" } + } +} diff --git a/build-logic/src/test/resources/input/cross_file_one_of_primitive_b.json b/build-logic/src/test/resources/input/cross_file_one_of_primitive_b.json new file mode 100644 index 0000000000..13f6141fe8 --- /dev/null +++ b/build-logic/src/test/resources/input/cross_file_one_of_primitive_b.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CrossFileOneOfPrimitiveB", + "type": "object", + "required": ["path"], + "properties": { + "path": { "$ref": "cross_file_one_of_primitive.json" } + } +} diff --git a/build-logic/src/test/resources/input/one_of_primitive_ref.json b/build-logic/src/test/resources/input/one_of_primitive_ref.json new file mode 100644 index 0000000000..839a44364e --- /dev/null +++ b/build-logic/src/test/resources/input/one_of_primitive_ref.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "OneOfPrimitiveRef", + "type": "object", + "properties": { + "from": { "$ref": "#/definitions/path" }, + "to": { "$ref": "#/definitions/path" } + }, + "required": ["from"], + "definitions": { + "path": { + "title": "Path", + "description": "This is a definition of a path", + "oneOf": [ + { + "type": "string", + "description": "string element" + }, + { + "type": "integer", + "description": "integer element" + } + ] + } + } +} diff --git a/dd-sdk-android-core/src/testFixtures/kotlin/com/datadog/android/utils/assertj/InternalApiUsageEventAssert.kt b/dd-sdk-android-core/src/testFixtures/kotlin/com/datadog/android/utils/assertj/InternalApiUsageEventAssert.kt index 8abbfa9c5f..0b6b9e7d00 100644 --- a/dd-sdk-android-core/src/testFixtures/kotlin/com/datadog/android/utils/assertj/InternalApiUsageEventAssert.kt +++ b/dd-sdk-android-core/src/testFixtures/kotlin/com/datadog/android/utils/assertj/InternalApiUsageEventAssert.kt @@ -35,6 +35,12 @@ class InternalApiUsageEventAssert(actual: InternalTelemetryEvent.ApiUsage) : .isEqualTo(expected as InternalTelemetryEvent.ApiUsage.TrackWebView) } + is InternalTelemetryEvent.ApiUsage.Timeseries -> { + InternalTimeseriesEventAssert + .assertThat(actual as InternalTelemetryEvent.ApiUsage.Timeseries) + .isEqualTo(expected as InternalTelemetryEvent.ApiUsage.Timeseries) + } + is InternalTelemetryEvent.ApiUsage.NetworkInstrumentation -> { InternalApiUsageNetworkInstrumentationEventAssert .assertThat(actual as InternalTelemetryEvent.ApiUsage.NetworkInstrumentation) diff --git a/dd-sdk-android-core/src/testFixtures/kotlin/com/datadog/android/utils/assertj/InternalTimeseriesEventAssert.kt b/dd-sdk-android-core/src/testFixtures/kotlin/com/datadog/android/utils/assertj/InternalTimeseriesEventAssert.kt new file mode 100644 index 0000000000..af16a19dad --- /dev/null +++ b/dd-sdk-android-core/src/testFixtures/kotlin/com/datadog/android/utils/assertj/InternalTimeseriesEventAssert.kt @@ -0,0 +1,37 @@ +/* + * 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.utils.assertj + +import com.datadog.android.internal.telemetry.InternalTelemetryEvent +import org.assertj.core.api.AbstractAssert +import org.assertj.core.api.Assertions + +private typealias TimeseriesApiUsage = InternalTelemetryEvent.ApiUsage.Timeseries + +internal class InternalTimeseriesEventAssert(actual: TimeseriesApiUsage) : + AbstractAssert( + actual, + InternalTimeseriesEventAssert::class.java + ) { + + fun isEqualTo(expected: TimeseriesApiUsage) { + hasAdditionalProperties(expected.additionalProperties) + } + + private fun hasAdditionalProperties(expected: Map) = apply { + Assertions.assertThat(actual.additionalProperties) + .overridingErrorMessage( + "Expected Timeseries event to have" + + " additionalProperties $expected but was ${actual.additionalProperties}" + ) + .isEqualTo(expected) + } + + companion object { + fun assertThat(actual: TimeseriesApiUsage) = InternalTimeseriesEventAssert(actual) + } +} diff --git a/dd-sdk-android-internal/api/apiSurface b/dd-sdk-android-internal/api/apiSurface index 43a3cd6aa2..97eba0c7a9 100644 --- a/dd-sdk-android-internal/api/apiSurface +++ b/dd-sdk-android-internal/api/apiSurface @@ -247,6 +247,8 @@ sealed class com.datadog.android.internal.telemetry.InternalTelemetryEvent - CRONET - OKHTTP - LEGACY_OKHTTP + class Timeseries : ApiUsage + constructor(MutableMap = mutableMapOf()) object InterceptorInstantiated : InternalTelemetryEvent class ResourceHeadersTrackingConfigured : InternalTelemetryEvent constructor(Mode) diff --git a/dd-sdk-android-internal/api/dd-sdk-android-internal.api b/dd-sdk-android-internal/api/dd-sdk-android-internal.api index 6621a0b49a..4237a2e82e 100644 --- a/dd-sdk-android-internal/api/dd-sdk-android-internal.api +++ b/dd-sdk-android-internal/api/dd-sdk-android-internal.api @@ -543,6 +543,12 @@ public final class com/datadog/android/internal/telemetry/InternalTelemetryEvent public static fun values ()[Lcom/datadog/android/internal/telemetry/InternalTelemetryEvent$ApiUsage$NetworkInstrumentation$LibraryType; } +public final class com/datadog/android/internal/telemetry/InternalTelemetryEvent$ApiUsage$Timeseries : com/datadog/android/internal/telemetry/InternalTelemetryEvent$ApiUsage { + public fun ()V + public fun (Ljava/util/Map;)V + public synthetic fun (Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +} + public final class com/datadog/android/internal/telemetry/InternalTelemetryEvent$ApiUsage$TrackWebView : com/datadog/android/internal/telemetry/InternalTelemetryEvent$ApiUsage { public fun ()V public fun (Ljava/util/Map;)V diff --git a/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/telemetry/InternalTelemetryEvent.kt b/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/telemetry/InternalTelemetryEvent.kt index 1fd9f4fb75..02c0caf1d9 100644 --- a/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/telemetry/InternalTelemetryEvent.kt +++ b/dd-sdk-android-internal/src/main/java/com/datadog/android/internal/telemetry/InternalTelemetryEvent.kt @@ -82,6 +82,10 @@ sealed class InternalTelemetryEvent { LEGACY_OKHTTP } } + + class Timeseries( + additionalProperties: MutableMap = mutableMapOf() + ) : ApiUsage(additionalProperties) } object InterceptorInstantiated : InternalTelemetryEvent() diff --git a/dd-sdk-android-internal/src/testFixtures/kotlin/com/datadog/android/internal/tests/elmyr/InternalTelemetryApiUsageForgeryFactory.kt b/dd-sdk-android-internal/src/testFixtures/kotlin/com/datadog/android/internal/tests/elmyr/InternalTelemetryApiUsageForgeryFactory.kt index 43b3768042..0de1fffb2d 100644 --- a/dd-sdk-android-internal/src/testFixtures/kotlin/com/datadog/android/internal/tests/elmyr/InternalTelemetryApiUsageForgeryFactory.kt +++ b/dd-sdk-android-internal/src/testFixtures/kotlin/com/datadog/android/internal/tests/elmyr/InternalTelemetryApiUsageForgeryFactory.kt @@ -35,6 +35,9 @@ class InternalTelemetryApiUsageForgeryFactory : ForgeryFactory tickPaint is TimelineEvent.LongTask -> longTaskPaint is TimelineEvent.Action -> actionsFramesPaint + is TimelineEvent.Timeseries -> timeseriesFramesPaint is TimelineEvent.SlowFrame -> slowFramesPaint is TimelineEvent.Resource -> resourceFramesPaint } canvas.drawRect(xOffset, 0f, xOffset + barSize, height.toFloat(), paint) - if (item.durationNs.ms > 0 || (item !is TimelineEvent.Tick && item !is TimelineEvent.Action)) { + if (item.text.isNotEmpty()) { canvas.withRotation(degrees = 90f, pivotX = xOffset, pivotY = 0f) { - val text = item.durationNs.ms.toString() - @Suppress("UnsafeThirdPartyFunctionCall") // measureText() is called on a non-null string - val textWidth = durationPaint.measureText(text) - drawText(text, xOffset + height.toFloat() - textWidth, 0f, durationPaint) + val textWidth = durationPaint.measureText(item.text) + drawText(item.text, xOffset + height.toFloat() - textWidth, 0f, durationPaint) } } diff --git a/features/dd-sdk-android-rum-debug-widget/src/main/res/values-night/colors.xml b/features/dd-sdk-android-rum-debug-widget/src/main/res/values-night/colors.xml index fa1e14e83a..453f727d66 100644 --- a/features/dd-sdk-android-rum-debug-widget/src/main/res/values-night/colors.xml +++ b/features/dd-sdk-android-rum-debug-widget/src/main/res/values-night/colors.xml @@ -13,4 +13,5 @@ #FFFF00 #FF0000 #00FF00 + #66CCFF diff --git a/features/dd-sdk-android-rum-debug-widget/src/main/res/values/colors.xml b/features/dd-sdk-android-rum-debug-widget/src/main/res/values/colors.xml index 87057a92ba..2287d29207 100644 --- a/features/dd-sdk-android-rum-debug-widget/src/main/res/values/colors.xml +++ b/features/dd-sdk-android-rum-debug-widget/src/main/res/values/colors.xml @@ -14,6 +14,7 @@ #B8860B #CC0000 #228B22 + #0077CC #228B22 #9E9E9E - \ No newline at end of file + diff --git a/features/dd-sdk-android-rum-debug-widget/src/test/kotlin/com/datadog/android/insights/internal/DefaultInsightsCollectorTest.kt b/features/dd-sdk-android-rum-debug-widget/src/test/kotlin/com/datadog/android/insights/internal/DefaultInsightsCollectorTest.kt index 3eada26eb3..8a84ed2727 100644 --- a/features/dd-sdk-android-rum-debug-widget/src/test/kotlin/com/datadog/android/insights/internal/DefaultInsightsCollectorTest.kt +++ b/features/dd-sdk-android-rum-debug-widget/src/test/kotlin/com/datadog/android/insights/internal/DefaultInsightsCollectorTest.kt @@ -33,7 +33,6 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import org.mockito.quality.Strictness -@Suppress("OPT_IN_USAGE") @Extensions( ExtendWith(MockitoExtension::class), ExtendWith(ForgeExtension::class) @@ -110,7 +109,7 @@ internal class DefaultInsightsCollectorTest { verify(mockInsightsUpdatesListener).onDataUpdated() val e = testedInsightsCollector.eventsState.single() assertThat(e).isInstanceOf(TimelineEvent.SlowFrame::class.java) - assertThat(e.durationNs).isEqualTo(fakeDurationNs) + assertThat(e.text).isEqualTo((fakeDurationNs / NANOS_PER_MILLI).toString()) } @Test @@ -122,7 +121,7 @@ internal class DefaultInsightsCollectorTest { verify(mockInsightsUpdatesListener).onDataUpdated() val e = testedInsightsCollector.eventsState.single() assertThat(e is TimelineEvent.LongTask).isTrue - assertThat(e.durationNs).isEqualTo(fakeDurationNs) + assertThat(e.text).isEqualTo((fakeDurationNs / NANOS_PER_MILLI).toString()) } @Test @@ -134,7 +133,20 @@ internal class DefaultInsightsCollectorTest { verify(mockInsightsUpdatesListener).onDataUpdated() val e = testedInsightsCollector.eventsState.single() assertThat(e is TimelineEvent.Resource).isTrue - assertThat(e.durationNs).isEqualTo(fakeDurationNs) + assertThat(e.text).isEqualTo((fakeDurationNs / NANOS_PER_MILLI).toString()) + } + + @Test + fun `M append Timeseries event W onTimeseries()`() { + // Given + val fakeName = "view.memory" + + // When + testedInsightsCollector.onTimeseries(fakeName) + + // Then + verify(mockInsightsUpdatesListener).onDataUpdated() + assertThat(testedInsightsCollector.eventsState).containsExactly(TimelineEvent.Timeseries(fakeName)) } @Test @@ -258,4 +270,8 @@ internal class DefaultInsightsCollectorTest { // Then assertThat(testedInsightsCollector.gcCallsPerSecond).isNaN } + + private companion object { + private const val NANOS_PER_MILLI = 1_000_000L + } } diff --git a/features/dd-sdk-android-rum/api/apiSurface b/features/dd-sdk-android-rum/api/apiSurface index d12ed04b88..18939bd2a3 100644 --- a/features/dd-sdk-android-rum/api/apiSurface +++ b/features/dd-sdk-android-rum/api/apiSurface @@ -90,6 +90,7 @@ data class com.datadog.android.rum.RumConfiguration fun setSlowFramesConfiguration(com.datadog.android.rum.configuration.SlowFramesConfiguration?): Builder fun trackAnonymousUser(Boolean): Builder fun setAppStartupActivityPredicate(com.datadog.android.rum.startup.AppStartupActivityPredicate): Builder + fun setTimeseriesConfiguration(com.datadog.android.rum.timeseries.TimeseriesConfiguration): Builder fun build(): RumConfiguration enum com.datadog.android.rum.RumErrorSource - NETWORK @@ -225,6 +226,7 @@ interface com.datadog.android.rum.internal.instrumentation.insights.InsightsColl fun onCpuVital(Double?) fun onMemoryVital(Double?) fun onSlowFrameRate(Double?) + fun onTimeseries(String) fun bindSdkCore(com.datadog.android.api.feature.FeatureSdkCore) fun unbindSdkCore(com.datadog.android.api.feature.FeatureSdkCore) interface com.datadog.android.rum.internal.instrumentation.insights.InsightsUpdatesListener @@ -308,6 +310,15 @@ class com.datadog.android.rum.resource.RumResourceInputStream : java.io.InputStr override fun close() interface com.datadog.android.rum.startup.AppStartupActivityPredicate fun shouldTrackStartup(android.app.Activity): Boolean +class com.datadog.android.rum.timeseries.TimeseriesConfiguration + class Builder + fun collectOnly(TimeseriesType): Builder + fun build(): TimeseriesConfiguration + companion object + val DEFAULT: TimeseriesConfiguration +enum com.datadog.android.rum.timeseries.TimeseriesType + - CPU + - MEMORY open class com.datadog.android.rum.tracking.AcceptAllActivities : ComponentPredicate override fun accept(android.app.Activity): Boolean override fun getViewName(android.app.Activity): String? @@ -391,7 +402,7 @@ class com.datadog.android.sqlite.DatadogDatabaseErrorHandler : android.database. constructor(String? = null, android.database.DatabaseErrorHandler = DefaultDatabaseErrorHandler()) override fun onCorruption(android.database.sqlite.SQLiteDatabase) data class com.datadog.android.rum.model.ActionEvent - constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, ActionEventSession, ActionEventSource? = null, ActionEventView, Usr? = null, Account? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Container? = null, ActionEventAction) + constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, ActionEventSession, ActionEventSource? = null, ActionEventView? = null, Usr? = null, Account? = null, Tab? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Stream? = null, Container? = null, ActionEventAction) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -427,6 +438,12 @@ data class com.datadog.android.rum.model.ActionEvent companion object fun fromJson(kotlin.String): Account fun fromJsonObject(com.google.gson.JsonObject): Account + data class Tab + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Tab + fun fromJsonObject(com.google.gson.JsonObject): Tab data class Connectivity constructor(Status, kotlin.collections.List? = null, EffectiveType? = null, Cellular? = null) fun toJson(): com.google.gson.JsonElement @@ -476,6 +493,12 @@ data class com.datadog.android.rum.model.ActionEvent companion object fun fromJson(kotlin.String): Context fun fromJsonObject(com.google.gson.JsonObject): Context + data class Stream + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Stream + fun fromJsonObject(com.google.gson.JsonObject): Stream data class Container constructor(ContainerView, ActionEventSource) fun toJson(): com.google.gson.JsonElement @@ -507,7 +530,7 @@ data class com.datadog.android.rum.model.ActionEvent fun fromJson(kotlin.String): DdSession fun fromJsonObject(com.google.gson.JsonObject): DdSession data class Configuration - constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null) + constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.collections.List? = null) fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Configuration @@ -583,7 +606,7 @@ data class com.datadog.android.rum.model.ActionEvent - UNITY - KOTLIN_MULTIPLATFORM - ELECTRON - - RUM_CPP + - CPP - MAUI fun toJson(): com.google.gson.JsonElement companion object @@ -692,7 +715,7 @@ data class com.datadog.android.rum.model.ActionEvent companion object fun fromJson(kotlin.String): Type data class com.datadog.android.rum.model.ErrorEvent - constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, ErrorEventSession, ErrorEventSource? = null, ErrorEventView, Usr? = null, Account? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Action? = null, Container? = null, Error, Freeze? = null, Context? = null) + constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, ErrorEventSession, ErrorEventSource? = null, ErrorEventView? = null, Usr? = null, Account? = null, Tab? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Stream? = null, Action? = null, Container? = null, Error, Freeze? = null, Context? = null) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -728,6 +751,12 @@ data class com.datadog.android.rum.model.ErrorEvent companion object fun fromJson(kotlin.String): Account fun fromJsonObject(com.google.gson.JsonObject): Account + data class Tab + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Tab + fun fromJsonObject(com.google.gson.JsonObject): Tab data class Connectivity constructor(ConnectivityStatus, kotlin.collections.List? = null, EffectiveType? = null, Cellular? = null) fun toJson(): com.google.gson.JsonElement @@ -777,6 +806,12 @@ data class com.datadog.android.rum.model.ErrorEvent companion object fun fromJson(kotlin.String): Context fun fromJsonObject(com.google.gson.JsonObject): Context + data class Stream + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Stream + fun fromJsonObject(com.google.gson.JsonObject): Stream data class Action constructor(kotlin.collections.List) fun toJson(): com.google.gson.JsonElement @@ -820,7 +855,7 @@ data class com.datadog.android.rum.model.ErrorEvent fun fromJson(kotlin.String): DdSession fun fromJsonObject(com.google.gson.JsonObject): DdSession data class Configuration - constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null) + constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.collections.List? = null) fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Configuration @@ -890,7 +925,7 @@ data class com.datadog.android.rum.model.ErrorEvent - UNITY - KOTLIN_MULTIPLATFORM - ELECTRON - - RUM_CPP + - CPP - MAUI fun toJson(): com.google.gson.JsonElement companion object @@ -1073,7 +1108,7 @@ data class com.datadog.android.rum.model.ErrorEvent companion object fun fromJson(kotlin.String): ProviderType data class com.datadog.android.rum.model.LongTaskEvent - constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, LongTaskEventSession, LongTaskEventSource? = null, LongTaskEventView, Usr? = null, Account? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Action? = null, Container? = null, LongTask) + constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, LongTaskEventSession, LongTaskEventSource? = null, LongTaskEventView? = null, Usr? = null, Account? = null, Tab? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Stream? = null, Action? = null, Container? = null, LongTask) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -1109,6 +1144,12 @@ data class com.datadog.android.rum.model.LongTaskEvent companion object fun fromJson(kotlin.String): Account fun fromJsonObject(com.google.gson.JsonObject): Account + data class Tab + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Tab + fun fromJsonObject(com.google.gson.JsonObject): Tab data class Connectivity constructor(ConnectivityStatus, kotlin.collections.List? = null, EffectiveType? = null, Cellular? = null) fun toJson(): com.google.gson.JsonElement @@ -1158,6 +1199,12 @@ data class com.datadog.android.rum.model.LongTaskEvent companion object fun fromJson(kotlin.String): Context fun fromJsonObject(com.google.gson.JsonObject): Context + data class Stream + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Stream + fun fromJsonObject(com.google.gson.JsonObject): Stream data class Action constructor(kotlin.collections.List) fun toJson(): com.google.gson.JsonElement @@ -1195,7 +1242,7 @@ data class com.datadog.android.rum.model.LongTaskEvent fun fromJson(kotlin.String): DdSession fun fromJsonObject(com.google.gson.JsonObject): DdSession data class Configuration - constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null) + constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.collections.List? = null) fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Configuration @@ -1229,7 +1276,7 @@ data class com.datadog.android.rum.model.LongTaskEvent - UNITY - KOTLIN_MULTIPLATFORM - ELECTRON - - RUM_CPP + - CPP - MAUI fun toJson(): com.google.gson.JsonElement companion object @@ -1341,7 +1388,7 @@ data class com.datadog.android.rum.model.LongTaskEvent companion object fun fromJson(kotlin.String): InvokerType data class com.datadog.android.rum.model.ResourceEvent - constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, ResourceEventSession, ResourceEventSource? = null, ResourceEventView, Usr? = null, Account? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Action? = null, Container? = null, Resource) + constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, ResourceEventSession, ResourceEventSource? = null, ResourceEventView? = null, Usr? = null, Account? = null, Tab? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Stream? = null, Action? = null, Container? = null, Resource) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -1377,6 +1424,12 @@ data class com.datadog.android.rum.model.ResourceEvent companion object fun fromJson(kotlin.String): Account fun fromJsonObject(com.google.gson.JsonObject): Account + data class Tab + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Tab + fun fromJsonObject(com.google.gson.JsonObject): Tab data class Connectivity constructor(Status, kotlin.collections.List? = null, EffectiveType? = null, Cellular? = null) fun toJson(): com.google.gson.JsonElement @@ -1426,6 +1479,12 @@ data class com.datadog.android.rum.model.ResourceEvent companion object fun fromJson(kotlin.String): Context fun fromJsonObject(com.google.gson.JsonObject): Context + data class Stream + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Stream + fun fromJsonObject(com.google.gson.JsonObject): Stream data class Action constructor(kotlin.collections.List) fun toJson(): com.google.gson.JsonElement @@ -1463,7 +1522,7 @@ data class com.datadog.android.rum.model.ResourceEvent fun fromJson(kotlin.String): DdSession fun fromJsonObject(com.google.gson.JsonObject): DdSession data class Configuration - constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null) + constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.collections.List? = null) fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Configuration @@ -1586,7 +1645,7 @@ data class com.datadog.android.rum.model.ResourceEvent - UNITY - KOTLIN_MULTIPLATFORM - ELECTRON - - RUM_CPP + - CPP - MAUI fun toJson(): com.google.gson.JsonElement companion object @@ -1733,8 +1792,464 @@ data class com.datadog.android.rum.model.ResourceEvent fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): OperationType +data class com.datadog.android.rum.model.TimeseriesCpuEvent + constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, TimeseriesCpuEventSession, Source? = null, View? = null, Usr? = null, Account? = null, Tab? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Stream? = null, Timeseries) + val type: kotlin.String + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): TimeseriesCpuEvent + fun fromJsonObject(com.google.gson.JsonObject): TimeseriesCpuEvent + data class Application + constructor(kotlin.String, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Application + fun fromJsonObject(com.google.gson.JsonObject): Application + data class TimeseriesCpuEventSession + constructor(kotlin.String, TimeseriesCpuEventSessionType, kotlin.Boolean? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): TimeseriesCpuEventSession + fun fromJsonObject(com.google.gson.JsonObject): TimeseriesCpuEventSession + data class View + constructor(kotlin.String, kotlin.String? = null, kotlin.String, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): View + fun fromJsonObject(com.google.gson.JsonObject): View + data class Usr + constructor(kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.collections.MutableMap = mutableMapOf()) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Usr + fun fromJsonObject(com.google.gson.JsonObject): Usr + data class Account + constructor(kotlin.String, kotlin.String? = null, kotlin.collections.MutableMap = mutableMapOf()) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Account + fun fromJsonObject(com.google.gson.JsonObject): Account + data class Tab + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Tab + fun fromJsonObject(com.google.gson.JsonObject): Tab + data class Connectivity + constructor(Status, kotlin.collections.List? = null, EffectiveType? = null, Cellular? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Connectivity + fun fromJsonObject(com.google.gson.JsonObject): Connectivity + data class Display + constructor(Viewport? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Display + fun fromJsonObject(com.google.gson.JsonObject): Display + data class Synthetics + constructor(kotlin.String, kotlin.String, kotlin.Boolean? = null, kotlin.collections.MutableMap = mutableMapOf()) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Synthetics + fun fromJsonObject(com.google.gson.JsonObject): Synthetics + data class CiTest + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): CiTest + fun fromJsonObject(com.google.gson.JsonObject): CiTest + data class Os + constructor(kotlin.String, kotlin.String, kotlin.String? = null, kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Os + fun fromJsonObject(com.google.gson.JsonObject): Os + data class Device + constructor(DeviceType? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.collections.List? = null, kotlin.String? = null, kotlin.Number? = null, kotlin.Boolean? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.Boolean? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Device + fun fromJsonObject(com.google.gson.JsonObject): Device + data class Dd + constructor(DdSession? = null, Configuration? = null, kotlin.String? = null, kotlin.String? = null) + val formatVersion: kotlin.Long + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Dd + fun fromJsonObject(com.google.gson.JsonObject): Dd + data class Context + constructor(kotlin.collections.MutableMap = mutableMapOf()) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Context + fun fromJsonObject(com.google.gson.JsonObject): Context + data class Stream + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Stream + fun fromJsonObject(com.google.gson.JsonObject): Stream + data class Timeseries + constructor(kotlin.String, kotlin.Long, kotlin.Long, Data) + val name: kotlin.String + val schema: kotlin.String + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Timeseries + fun fromJsonObject(com.google.gson.JsonObject): Timeseries + data class Cellular + constructor(kotlin.String? = null, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Cellular + fun fromJsonObject(com.google.gson.JsonObject): Cellular + data class Viewport + constructor(kotlin.Number, kotlin.Number) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Viewport + fun fromJsonObject(com.google.gson.JsonObject): Viewport + data class DdSession + constructor(Plan? = null, SessionPrecondition? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): DdSession + fun fromJsonObject(com.google.gson.JsonObject): DdSession + data class Configuration + constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.collections.List? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Configuration + fun fromJsonObject(com.google.gson.JsonObject): Configuration + data class Data + constructor(kotlin.collections.List, Values) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Data + fun fromJsonObject(com.google.gson.JsonObject): Data + data class Values + constructor(kotlin.collections.List) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Values + fun fromJsonObject(com.google.gson.JsonObject): Values + enum Source + constructor(kotlin.String) + - ANDROID + - IOS + - BROWSER + - FLUTTER + - REACT_NATIVE + - ROKU + - UNITY + - KOTLIN_MULTIPLATFORM + - ELECTRON + - CPP + - MAUI + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Source + enum TimeseriesCpuEventSessionType + constructor(kotlin.String) + - USER + - SYNTHETICS + - CI_TEST + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): TimeseriesCpuEventSessionType + enum Status + constructor(kotlin.String) + - CONNECTED + - NOT_CONNECTED + - MAYBE + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Status + enum Interface + constructor(kotlin.String) + - BLUETOOTH + - CELLULAR + - ETHERNET + - WIFI + - WIMAX + - MIXED + - OTHER + - UNKNOWN + - NONE + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Interface + enum EffectiveType + constructor(kotlin.String) + - SLOW_2G + - `2G` + - `3G` + - `4G` + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): EffectiveType + enum DeviceType + constructor(kotlin.String) + - MOBILE + - DESKTOP + - TABLET + - TV + - GAMING_CONSOLE + - BOT + - OTHER + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): DeviceType + enum Plan + constructor(kotlin.Number) + - PLAN_1 + - PLAN_2 + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Plan + enum SessionPrecondition + constructor(kotlin.String) + - USER_APP_LAUNCH + - INACTIVITY_TIMEOUT + - MAX_DURATION + - BACKGROUND_LAUNCH + - PREWARM + - FROM_NON_INTERACTIVE_SESSION + - EXPLICIT_STOP + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): SessionPrecondition +data class com.datadog.android.rum.model.TimeseriesMemoryEvent + constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, TimeseriesMemoryEventSession, Source? = null, View? = null, Usr? = null, Account? = null, Tab? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Stream? = null, Timeseries) + val type: kotlin.String + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): TimeseriesMemoryEvent + fun fromJsonObject(com.google.gson.JsonObject): TimeseriesMemoryEvent + data class Application + constructor(kotlin.String, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Application + fun fromJsonObject(com.google.gson.JsonObject): Application + data class TimeseriesMemoryEventSession + constructor(kotlin.String, TimeseriesMemoryEventSessionType, kotlin.Boolean? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): TimeseriesMemoryEventSession + fun fromJsonObject(com.google.gson.JsonObject): TimeseriesMemoryEventSession + data class View + constructor(kotlin.String, kotlin.String? = null, kotlin.String, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): View + fun fromJsonObject(com.google.gson.JsonObject): View + data class Usr + constructor(kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.collections.MutableMap = mutableMapOf()) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Usr + fun fromJsonObject(com.google.gson.JsonObject): Usr + data class Account + constructor(kotlin.String, kotlin.String? = null, kotlin.collections.MutableMap = mutableMapOf()) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Account + fun fromJsonObject(com.google.gson.JsonObject): Account + data class Tab + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Tab + fun fromJsonObject(com.google.gson.JsonObject): Tab + data class Connectivity + constructor(Status, kotlin.collections.List? = null, EffectiveType? = null, Cellular? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Connectivity + fun fromJsonObject(com.google.gson.JsonObject): Connectivity + data class Display + constructor(Viewport? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Display + fun fromJsonObject(com.google.gson.JsonObject): Display + data class Synthetics + constructor(kotlin.String, kotlin.String, kotlin.Boolean? = null, kotlin.collections.MutableMap = mutableMapOf()) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Synthetics + fun fromJsonObject(com.google.gson.JsonObject): Synthetics + data class CiTest + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): CiTest + fun fromJsonObject(com.google.gson.JsonObject): CiTest + data class Os + constructor(kotlin.String, kotlin.String, kotlin.String? = null, kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Os + fun fromJsonObject(com.google.gson.JsonObject): Os + data class Device + constructor(DeviceType? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.collections.List? = null, kotlin.String? = null, kotlin.Number? = null, kotlin.Boolean? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.Boolean? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Device + fun fromJsonObject(com.google.gson.JsonObject): Device + data class Dd + constructor(DdSession? = null, Configuration? = null, kotlin.String? = null, kotlin.String? = null) + val formatVersion: kotlin.Long + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Dd + fun fromJsonObject(com.google.gson.JsonObject): Dd + data class Context + constructor(kotlin.collections.MutableMap = mutableMapOf()) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Context + fun fromJsonObject(com.google.gson.JsonObject): Context + data class Stream + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Stream + fun fromJsonObject(com.google.gson.JsonObject): Stream + data class Timeseries + constructor(kotlin.String, kotlin.Long, kotlin.Long, Data) + val name: kotlin.String + val schema: kotlin.String + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Timeseries + fun fromJsonObject(com.google.gson.JsonObject): Timeseries + data class Cellular + constructor(kotlin.String? = null, kotlin.String? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Cellular + fun fromJsonObject(com.google.gson.JsonObject): Cellular + data class Viewport + constructor(kotlin.Number, kotlin.Number) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Viewport + fun fromJsonObject(com.google.gson.JsonObject): Viewport + data class DdSession + constructor(Plan? = null, SessionPrecondition? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): DdSession + fun fromJsonObject(com.google.gson.JsonObject): DdSession + data class Configuration + constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.collections.List? = null) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Configuration + fun fromJsonObject(com.google.gson.JsonObject): Configuration + data class Data + constructor(kotlin.collections.List, Values) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Data + fun fromJsonObject(com.google.gson.JsonObject): Data + data class Values + constructor(kotlin.collections.List, kotlin.collections.List) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Values + fun fromJsonObject(com.google.gson.JsonObject): Values + enum Source + constructor(kotlin.String) + - ANDROID + - IOS + - BROWSER + - FLUTTER + - REACT_NATIVE + - ROKU + - UNITY + - KOTLIN_MULTIPLATFORM + - ELECTRON + - CPP + - MAUI + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Source + enum TimeseriesMemoryEventSessionType + constructor(kotlin.String) + - USER + - SYNTHETICS + - CI_TEST + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): TimeseriesMemoryEventSessionType + enum Status + constructor(kotlin.String) + - CONNECTED + - NOT_CONNECTED + - MAYBE + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Status + enum Interface + constructor(kotlin.String) + - BLUETOOTH + - CELLULAR + - ETHERNET + - WIFI + - WIMAX + - MIXED + - OTHER + - UNKNOWN + - NONE + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Interface + enum EffectiveType + constructor(kotlin.String) + - SLOW_2G + - `2G` + - `3G` + - `4G` + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): EffectiveType + enum DeviceType + constructor(kotlin.String) + - MOBILE + - DESKTOP + - TABLET + - TV + - GAMING_CONSOLE + - BOT + - OTHER + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): DeviceType + enum Plan + constructor(kotlin.Number) + - PLAN_1 + - PLAN_2 + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Plan + enum SessionPrecondition + constructor(kotlin.String) + - USER_APP_LAUNCH + - INACTIVITY_TIMEOUT + - MAX_DURATION + - BACKGROUND_LAUNCH + - PREWARM + - FROM_NON_INTERACTIVE_SESSION + - EXPLICIT_STOP + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): SessionPrecondition data class com.datadog.android.rum.model.ViewEvent - constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, ViewEventSession, ViewEventSource? = null, ViewEventView, Usr? = null, Account? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Container? = null, Context? = null, Privacy? = null) + constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, ViewEventSession, ViewEventSource? = null, ViewEventView, Usr? = null, Account? = null, Tab? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Stream? = null, Container? = null, Context? = null, Privacy? = null) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -1770,6 +2285,12 @@ data class com.datadog.android.rum.model.ViewEvent companion object fun fromJson(kotlin.String): Account fun fromJsonObject(com.google.gson.JsonObject): Account + data class Tab + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Tab + fun fromJsonObject(com.google.gson.JsonObject): Tab data class Connectivity constructor(ConnectivityStatus, kotlin.collections.List? = null, EffectiveType? = null, Cellular? = null) fun toJson(): com.google.gson.JsonElement @@ -1819,6 +2340,12 @@ data class com.datadog.android.rum.model.ViewEvent companion object fun fromJson(kotlin.String): Context fun fromJsonObject(com.google.gson.JsonObject): Context + data class Stream + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Stream + fun fromJsonObject(com.google.gson.JsonObject): Stream data class Container constructor(ContainerView, ViewEventSource) fun toJson(): com.google.gson.JsonElement @@ -1934,7 +2461,7 @@ data class com.datadog.android.rum.model.ViewEvent fun fromJson(kotlin.String): DdSession fun fromJsonObject(com.google.gson.JsonObject): DdSession data class Configuration - constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.Boolean? = null) + constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.collections.List? = null, kotlin.Boolean? = null) fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Configuration @@ -2034,7 +2561,7 @@ data class com.datadog.android.rum.model.ViewEvent - UNITY - KOTLIN_MULTIPLATFORM - ELECTRON - - RUM_CPP + - CPP - MAUI fun toJson(): com.google.gson.JsonElement companion object @@ -2159,7 +2686,7 @@ data class com.datadog.android.rum.model.ViewEvent companion object fun fromJson(kotlin.String): ErrorReason data class com.datadog.android.rum.model.VitalAppLaunchEvent - constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, VitalAppLaunchEventSession, VitalAppLaunchEventSource? = null, VitalAppLaunchEventView, Usr? = null, Account? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Container? = null, Vital) + constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, VitalAppLaunchEventSession, VitalAppLaunchEventSource? = null, VitalAppLaunchEventView? = null, Usr? = null, Account? = null, Tab? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Stream? = null, Container? = null, Vital) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -2195,6 +2722,12 @@ data class com.datadog.android.rum.model.VitalAppLaunchEvent companion object fun fromJson(kotlin.String): Account fun fromJsonObject(com.google.gson.JsonObject): Account + data class Tab + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Tab + fun fromJsonObject(com.google.gson.JsonObject): Tab data class Connectivity constructor(ConnectivityStatus, kotlin.collections.List? = null, EffectiveType? = null, Cellular? = null) fun toJson(): com.google.gson.JsonElement @@ -2244,6 +2777,12 @@ data class com.datadog.android.rum.model.VitalAppLaunchEvent companion object fun fromJson(kotlin.String): Context fun fromJsonObject(com.google.gson.JsonObject): Context + data class Stream + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Stream + fun fromJsonObject(com.google.gson.JsonObject): Stream data class Container constructor(ContainerView, VitalAppLaunchEventSource) fun toJson(): com.google.gson.JsonElement @@ -2276,7 +2815,7 @@ data class com.datadog.android.rum.model.VitalAppLaunchEvent fun fromJson(kotlin.String): DdSession fun fromJsonObject(com.google.gson.JsonObject): DdSession data class Configuration - constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null) + constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.collections.List? = null) fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Configuration @@ -2304,7 +2843,7 @@ data class com.datadog.android.rum.model.VitalAppLaunchEvent - UNITY - KOTLIN_MULTIPLATFORM - ELECTRON - - RUM_CPP + - CPP - MAUI fun toJson(): com.google.gson.JsonElement companion object @@ -2412,7 +2951,7 @@ data class com.datadog.android.rum.model.VitalAppLaunchEvent companion object fun fromJson(kotlin.String): ErrorReason data class com.datadog.android.rum.model.VitalOperationStepEvent - constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, VitalOperationStepEventSession, VitalOperationStepEventSource? = null, VitalOperationStepEventView, Usr? = null, Account? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Container? = null, Vital) + constructor(kotlin.Long, Application, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, kotlin.String? = null, VitalOperationStepEventSession, VitalOperationStepEventSource? = null, VitalOperationStepEventView? = null, Usr? = null, Account? = null, Tab? = null, Connectivity? = null, Display? = null, Synthetics? = null, CiTest? = null, Os? = null, Device? = null, Dd, Context? = null, Stream? = null, Container? = null, Vital) val type: kotlin.String fun toJson(): com.google.gson.JsonElement companion object @@ -2448,6 +2987,12 @@ data class com.datadog.android.rum.model.VitalOperationStepEvent companion object fun fromJson(kotlin.String): Account fun fromJsonObject(com.google.gson.JsonObject): Account + data class Tab + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Tab + fun fromJsonObject(com.google.gson.JsonObject): Tab data class Connectivity constructor(ConnectivityStatus, kotlin.collections.List? = null, EffectiveType? = null, Cellular? = null) fun toJson(): com.google.gson.JsonElement @@ -2497,6 +3042,12 @@ data class com.datadog.android.rum.model.VitalOperationStepEvent companion object fun fromJson(kotlin.String): Context fun fromJsonObject(com.google.gson.JsonObject): Context + data class Stream + constructor(kotlin.String) + fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Stream + fun fromJsonObject(com.google.gson.JsonObject): Stream data class Container constructor(ContainerView, VitalOperationStepEventSource) fun toJson(): com.google.gson.JsonElement @@ -2529,7 +3080,7 @@ data class com.datadog.android.rum.model.VitalOperationStepEvent fun fromJson(kotlin.String): DdSession fun fromJsonObject(com.google.gson.JsonObject): DdSession data class Configuration - constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null) + constructor(kotlin.Number, kotlin.Number? = null, kotlin.Number? = null, kotlin.Number? = null, kotlin.collections.List? = null) fun toJson(): com.google.gson.JsonElement companion object fun fromJson(kotlin.String): Configuration @@ -2557,7 +3108,7 @@ data class com.datadog.android.rum.model.VitalOperationStepEvent - UNITY - KOTLIN_MULTIPLATFORM - ELECTRON - - RUM_CPP + - CPP - MAUI fun toJson(): com.google.gson.JsonElement companion object @@ -3241,6 +3792,12 @@ data class com.datadog.android.telemetry.model.TelemetryUsageEvent companion object fun fromJson(kotlin.String): TrackWebView fun fromJsonObject(com.google.gson.JsonObject): TrackWebView + class Timeseries : Usage + val feature: kotlin.String + override fun toJson(): com.google.gson.JsonElement + companion object + fun fromJson(kotlin.String): Timeseries + fun fromJsonObject(com.google.gson.JsonObject): Timeseries data class AndroidNetworkInstrumentation : Usage constructor(Type) val feature: kotlin.String diff --git a/features/dd-sdk-android-rum/api/dd-sdk-android-rum.api b/features/dd-sdk-android-rum/api/dd-sdk-android-rum.api index 169e0d059b..e49fc0f8aa 100644 --- a/features/dd-sdk-android-rum/api/dd-sdk-android-rum.api +++ b/features/dd-sdk-android-rum/api/dd-sdk-android-rum.api @@ -117,6 +117,7 @@ public final class com/datadog/android/rum/RumConfiguration$Builder { public final fun setSessionSampleRate (F)Lcom/datadog/android/rum/RumConfiguration$Builder; public final fun setSlowFramesConfiguration (Lcom/datadog/android/rum/configuration/SlowFramesConfiguration;)Lcom/datadog/android/rum/RumConfiguration$Builder; public final fun setTelemetrySampleRate (F)Lcom/datadog/android/rum/RumConfiguration$Builder; + public final fun setTimeseriesConfiguration (Lcom/datadog/android/rum/timeseries/TimeseriesConfiguration;)Lcom/datadog/android/rum/RumConfiguration$Builder; public final fun setViewEventMapper (Lcom/datadog/android/rum/event/ViewEventMapper;)Lcom/datadog/android/rum/RumConfiguration$Builder; public final fun setVitalEventMapper (Lcom/datadog/android/event/EventMapper;)Lcom/datadog/android/rum/RumConfiguration$Builder; public final fun setVitalEventMapper (Lcom/datadog/android/event/EventMapper;Lcom/datadog/android/event/EventMapper;)Lcom/datadog/android/rum/RumConfiguration$Builder; @@ -389,6 +390,7 @@ public abstract interface class com/datadog/android/rum/internal/instrumentation public abstract fun onNewView (Ljava/lang/String;)V public abstract fun onSlowFrame (J)V public abstract fun onSlowFrameRate (Ljava/lang/Double;)V + public abstract fun onTimeseries (Ljava/lang/String;)V public abstract fun removeUpdateListener (Lcom/datadog/android/rum/internal/instrumentation/insights/InsightsUpdatesListener;)V public abstract fun setMaxSize (I)V public abstract fun setUpdateIntervalMs (J)V @@ -515,23 +517,25 @@ public final class com/datadog/android/rum/metric/networksettled/TimeBasedInitia public final class com/datadog/android/rum/model/ActionEvent { public static final field Companion Lcom/datadog/android/rum/model/ActionEvent$Companion; - public fun (JLcom/datadog/android/rum/model/ActionEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource;Lcom/datadog/android/rum/model/ActionEvent$ActionEventView;Lcom/datadog/android/rum/model/ActionEvent$Usr;Lcom/datadog/android/rum/model/ActionEvent$Account;Lcom/datadog/android/rum/model/ActionEvent$Connectivity;Lcom/datadog/android/rum/model/ActionEvent$Display;Lcom/datadog/android/rum/model/ActionEvent$Synthetics;Lcom/datadog/android/rum/model/ActionEvent$CiTest;Lcom/datadog/android/rum/model/ActionEvent$Os;Lcom/datadog/android/rum/model/ActionEvent$Device;Lcom/datadog/android/rum/model/ActionEvent$Dd;Lcom/datadog/android/rum/model/ActionEvent$Context;Lcom/datadog/android/rum/model/ActionEvent$Container;Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction;)V - public synthetic fun (JLcom/datadog/android/rum/model/ActionEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource;Lcom/datadog/android/rum/model/ActionEvent$ActionEventView;Lcom/datadog/android/rum/model/ActionEvent$Usr;Lcom/datadog/android/rum/model/ActionEvent$Account;Lcom/datadog/android/rum/model/ActionEvent$Connectivity;Lcom/datadog/android/rum/model/ActionEvent$Display;Lcom/datadog/android/rum/model/ActionEvent$Synthetics;Lcom/datadog/android/rum/model/ActionEvent$CiTest;Lcom/datadog/android/rum/model/ActionEvent$Os;Lcom/datadog/android/rum/model/ActionEvent$Device;Lcom/datadog/android/rum/model/ActionEvent$Dd;Lcom/datadog/android/rum/model/ActionEvent$Context;Lcom/datadog/android/rum/model/ActionEvent$Container;Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (JLcom/datadog/android/rum/model/ActionEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource;Lcom/datadog/android/rum/model/ActionEvent$ActionEventView;Lcom/datadog/android/rum/model/ActionEvent$Usr;Lcom/datadog/android/rum/model/ActionEvent$Account;Lcom/datadog/android/rum/model/ActionEvent$Tab;Lcom/datadog/android/rum/model/ActionEvent$Connectivity;Lcom/datadog/android/rum/model/ActionEvent$Display;Lcom/datadog/android/rum/model/ActionEvent$Synthetics;Lcom/datadog/android/rum/model/ActionEvent$CiTest;Lcom/datadog/android/rum/model/ActionEvent$Os;Lcom/datadog/android/rum/model/ActionEvent$Device;Lcom/datadog/android/rum/model/ActionEvent$Dd;Lcom/datadog/android/rum/model/ActionEvent$Context;Lcom/datadog/android/rum/model/ActionEvent$Stream;Lcom/datadog/android/rum/model/ActionEvent$Container;Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction;)V + public synthetic fun (JLcom/datadog/android/rum/model/ActionEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource;Lcom/datadog/android/rum/model/ActionEvent$ActionEventView;Lcom/datadog/android/rum/model/ActionEvent$Usr;Lcom/datadog/android/rum/model/ActionEvent$Account;Lcom/datadog/android/rum/model/ActionEvent$Tab;Lcom/datadog/android/rum/model/ActionEvent$Connectivity;Lcom/datadog/android/rum/model/ActionEvent$Display;Lcom/datadog/android/rum/model/ActionEvent$Synthetics;Lcom/datadog/android/rum/model/ActionEvent$CiTest;Lcom/datadog/android/rum/model/ActionEvent$Os;Lcom/datadog/android/rum/model/ActionEvent$Device;Lcom/datadog/android/rum/model/ActionEvent$Dd;Lcom/datadog/android/rum/model/ActionEvent$Context;Lcom/datadog/android/rum/model/ActionEvent$Stream;Lcom/datadog/android/rum/model/ActionEvent$Container;Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()J public final fun component10 ()Lcom/datadog/android/rum/model/ActionEvent$ActionEventView; public final fun component11 ()Lcom/datadog/android/rum/model/ActionEvent$Usr; public final fun component12 ()Lcom/datadog/android/rum/model/ActionEvent$Account; - public final fun component13 ()Lcom/datadog/android/rum/model/ActionEvent$Connectivity; - public final fun component14 ()Lcom/datadog/android/rum/model/ActionEvent$Display; - public final fun component15 ()Lcom/datadog/android/rum/model/ActionEvent$Synthetics; - public final fun component16 ()Lcom/datadog/android/rum/model/ActionEvent$CiTest; - public final fun component17 ()Lcom/datadog/android/rum/model/ActionEvent$Os; - public final fun component18 ()Lcom/datadog/android/rum/model/ActionEvent$Device; - public final fun component19 ()Lcom/datadog/android/rum/model/ActionEvent$Dd; + public final fun component13 ()Lcom/datadog/android/rum/model/ActionEvent$Tab; + public final fun component14 ()Lcom/datadog/android/rum/model/ActionEvent$Connectivity; + public final fun component15 ()Lcom/datadog/android/rum/model/ActionEvent$Display; + public final fun component16 ()Lcom/datadog/android/rum/model/ActionEvent$Synthetics; + public final fun component17 ()Lcom/datadog/android/rum/model/ActionEvent$CiTest; + public final fun component18 ()Lcom/datadog/android/rum/model/ActionEvent$Os; + public final fun component19 ()Lcom/datadog/android/rum/model/ActionEvent$Device; public final fun component2 ()Lcom/datadog/android/rum/model/ActionEvent$Application; - public final fun component20 ()Lcom/datadog/android/rum/model/ActionEvent$Context; - public final fun component21 ()Lcom/datadog/android/rum/model/ActionEvent$Container; - public final fun component22 ()Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction; + public final fun component20 ()Lcom/datadog/android/rum/model/ActionEvent$Dd; + public final fun component21 ()Lcom/datadog/android/rum/model/ActionEvent$Context; + public final fun component22 ()Lcom/datadog/android/rum/model/ActionEvent$Stream; + public final fun component23 ()Lcom/datadog/android/rum/model/ActionEvent$Container; + public final fun component24 ()Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; @@ -539,8 +543,8 @@ public final class com/datadog/android/rum/model/ActionEvent { public final fun component7 ()Ljava/lang/String; public final fun component8 ()Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession; public final fun component9 ()Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; - public final fun copy (JLcom/datadog/android/rum/model/ActionEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource;Lcom/datadog/android/rum/model/ActionEvent$ActionEventView;Lcom/datadog/android/rum/model/ActionEvent$Usr;Lcom/datadog/android/rum/model/ActionEvent$Account;Lcom/datadog/android/rum/model/ActionEvent$Connectivity;Lcom/datadog/android/rum/model/ActionEvent$Display;Lcom/datadog/android/rum/model/ActionEvent$Synthetics;Lcom/datadog/android/rum/model/ActionEvent$CiTest;Lcom/datadog/android/rum/model/ActionEvent$Os;Lcom/datadog/android/rum/model/ActionEvent$Device;Lcom/datadog/android/rum/model/ActionEvent$Dd;Lcom/datadog/android/rum/model/ActionEvent$Context;Lcom/datadog/android/rum/model/ActionEvent$Container;Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction;)Lcom/datadog/android/rum/model/ActionEvent; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ActionEvent;JLcom/datadog/android/rum/model/ActionEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource;Lcom/datadog/android/rum/model/ActionEvent$ActionEventView;Lcom/datadog/android/rum/model/ActionEvent$Usr;Lcom/datadog/android/rum/model/ActionEvent$Account;Lcom/datadog/android/rum/model/ActionEvent$Connectivity;Lcom/datadog/android/rum/model/ActionEvent$Display;Lcom/datadog/android/rum/model/ActionEvent$Synthetics;Lcom/datadog/android/rum/model/ActionEvent$CiTest;Lcom/datadog/android/rum/model/ActionEvent$Os;Lcom/datadog/android/rum/model/ActionEvent$Device;Lcom/datadog/android/rum/model/ActionEvent$Dd;Lcom/datadog/android/rum/model/ActionEvent$Context;Lcom/datadog/android/rum/model/ActionEvent$Container;Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ActionEvent; + public final fun copy (JLcom/datadog/android/rum/model/ActionEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource;Lcom/datadog/android/rum/model/ActionEvent$ActionEventView;Lcom/datadog/android/rum/model/ActionEvent$Usr;Lcom/datadog/android/rum/model/ActionEvent$Account;Lcom/datadog/android/rum/model/ActionEvent$Tab;Lcom/datadog/android/rum/model/ActionEvent$Connectivity;Lcom/datadog/android/rum/model/ActionEvent$Display;Lcom/datadog/android/rum/model/ActionEvent$Synthetics;Lcom/datadog/android/rum/model/ActionEvent$CiTest;Lcom/datadog/android/rum/model/ActionEvent$Os;Lcom/datadog/android/rum/model/ActionEvent$Device;Lcom/datadog/android/rum/model/ActionEvent$Dd;Lcom/datadog/android/rum/model/ActionEvent$Context;Lcom/datadog/android/rum/model/ActionEvent$Stream;Lcom/datadog/android/rum/model/ActionEvent$Container;Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction;)Lcom/datadog/android/rum/model/ActionEvent; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ActionEvent;JLcom/datadog/android/rum/model/ActionEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession;Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource;Lcom/datadog/android/rum/model/ActionEvent$ActionEventView;Lcom/datadog/android/rum/model/ActionEvent$Usr;Lcom/datadog/android/rum/model/ActionEvent$Account;Lcom/datadog/android/rum/model/ActionEvent$Tab;Lcom/datadog/android/rum/model/ActionEvent$Connectivity;Lcom/datadog/android/rum/model/ActionEvent$Display;Lcom/datadog/android/rum/model/ActionEvent$Synthetics;Lcom/datadog/android/rum/model/ActionEvent$CiTest;Lcom/datadog/android/rum/model/ActionEvent$Os;Lcom/datadog/android/rum/model/ActionEvent$Device;Lcom/datadog/android/rum/model/ActionEvent$Dd;Lcom/datadog/android/rum/model/ActionEvent$Context;Lcom/datadog/android/rum/model/ActionEvent$Stream;Lcom/datadog/android/rum/model/ActionEvent$Container;Lcom/datadog/android/rum/model/ActionEvent$ActionEventAction;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ActionEvent; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ActionEvent; @@ -562,7 +566,9 @@ public final class com/datadog/android/rum/model/ActionEvent { public final fun getService ()Ljava/lang/String; public final fun getSession ()Lcom/datadog/android/rum/model/ActionEvent$ActionEventSession; public final fun getSource ()Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; + public final fun getStream ()Lcom/datadog/android/rum/model/ActionEvent$Stream; public final fun getSynthetics ()Lcom/datadog/android/rum/model/ActionEvent$Synthetics; + public final fun getTab ()Lcom/datadog/android/rum/model/ActionEvent$Tab; public final fun getType ()Ljava/lang/String; public final fun getUsr ()Lcom/datadog/android/rum/model/ActionEvent$Usr; public final fun getVersion ()Ljava/lang/String; @@ -717,6 +723,7 @@ public final class com/datadog/android/rum/model/ActionEvent$ActionEventSessionT public final class com/datadog/android/rum/model/ActionEvent$ActionEventSource : java/lang/Enum { public static final field ANDROID Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; public static final field BROWSER Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; + public static final field CPP Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; public static final field Companion Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource$Companion; public static final field ELECTRON Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; public static final field FLUTTER Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; @@ -725,7 +732,6 @@ public final class com/datadog/android/rum/model/ActionEvent$ActionEventSource : public static final field MAUI Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; public static final field REACT_NATIVE Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; public static final field ROKU Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; - public static final field RUM_CPP Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; public static final field UNITY Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent$ActionEventSource; public final fun toJson ()Lcom/google/gson/JsonElement; @@ -843,18 +849,20 @@ public final class com/datadog/android/rum/model/ActionEvent$Companion { public final class com/datadog/android/rum/model/ActionEvent$Configuration { public static final field Companion Lcom/datadog/android/rum/model/ActionEvent$Configuration$Companion; - public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)V - public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)V + public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/Number; public final fun component2 ()Ljava/lang/Number; public final fun component3 ()Ljava/lang/Number; public final fun component4 ()Ljava/lang/Number; - public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/ActionEvent$Configuration; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ActionEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ActionEvent$Configuration; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)Lcom/datadog/android/rum/model/ActionEvent$Configuration; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ActionEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ActionEvent$Configuration; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent$Configuration; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ActionEvent$Configuration; public final fun getProfilingSampleRate ()Ljava/lang/Number; + public final fun getSessionReplayExperimentalFeatures ()Ljava/util/List; public final fun getSessionReplaySampleRate ()Ljava/lang/Number; public final fun getSessionSampleRate ()Ljava/lang/Number; public final fun getTraceSampleRate ()Ljava/lang/Number; @@ -1412,6 +1420,26 @@ public final class com/datadog/android/rum/model/ActionEvent$Status$Companion { public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent$Status; } +public final class com/datadog/android/rum/model/ActionEvent$Stream { + public static final field Companion Lcom/datadog/android/rum/model/ActionEvent$Stream$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent$Stream; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ActionEvent$Stream;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ActionEvent$Stream; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent$Stream; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ActionEvent$Stream; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ActionEvent$Stream$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent$Stream; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ActionEvent$Stream; +} + public final class com/datadog/android/rum/model/ActionEvent$Synthetics { public static final field Companion Lcom/datadog/android/rum/model/ActionEvent$Synthetics$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)V @@ -1439,6 +1467,26 @@ public final class com/datadog/android/rum/model/ActionEvent$Synthetics$Companio public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ActionEvent$Synthetics; } +public final class com/datadog/android/rum/model/ActionEvent$Tab { + public static final field Companion Lcom/datadog/android/rum/model/ActionEvent$Tab$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent$Tab; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ActionEvent$Tab;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ActionEvent$Tab; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent$Tab; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ActionEvent$Tab; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ActionEvent$Tab$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ActionEvent$Tab; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ActionEvent$Tab; +} + public final class com/datadog/android/rum/model/ActionEvent$Type : java/lang/Enum { public static final field Companion Lcom/datadog/android/rum/model/ActionEvent$Type$Companion; public static final field DEAD_CLICK Lcom/datadog/android/rum/model/ActionEvent$Type; @@ -1510,26 +1558,28 @@ public final class com/datadog/android/rum/model/ActionEvent$Viewport$Companion public final class com/datadog/android/rum/model/ErrorEvent { public static final field Companion Lcom/datadog/android/rum/model/ErrorEvent$Companion; - public fun (JLcom/datadog/android/rum/model/ErrorEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventView;Lcom/datadog/android/rum/model/ErrorEvent$Usr;Lcom/datadog/android/rum/model/ErrorEvent$Account;Lcom/datadog/android/rum/model/ErrorEvent$Connectivity;Lcom/datadog/android/rum/model/ErrorEvent$Display;Lcom/datadog/android/rum/model/ErrorEvent$Synthetics;Lcom/datadog/android/rum/model/ErrorEvent$CiTest;Lcom/datadog/android/rum/model/ErrorEvent$Os;Lcom/datadog/android/rum/model/ErrorEvent$Device;Lcom/datadog/android/rum/model/ErrorEvent$Dd;Lcom/datadog/android/rum/model/ErrorEvent$Context;Lcom/datadog/android/rum/model/ErrorEvent$Action;Lcom/datadog/android/rum/model/ErrorEvent$Container;Lcom/datadog/android/rum/model/ErrorEvent$Error;Lcom/datadog/android/rum/model/ErrorEvent$Freeze;Lcom/datadog/android/rum/model/ErrorEvent$Context;)V - public synthetic fun (JLcom/datadog/android/rum/model/ErrorEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventView;Lcom/datadog/android/rum/model/ErrorEvent$Usr;Lcom/datadog/android/rum/model/ErrorEvent$Account;Lcom/datadog/android/rum/model/ErrorEvent$Connectivity;Lcom/datadog/android/rum/model/ErrorEvent$Display;Lcom/datadog/android/rum/model/ErrorEvent$Synthetics;Lcom/datadog/android/rum/model/ErrorEvent$CiTest;Lcom/datadog/android/rum/model/ErrorEvent$Os;Lcom/datadog/android/rum/model/ErrorEvent$Device;Lcom/datadog/android/rum/model/ErrorEvent$Dd;Lcom/datadog/android/rum/model/ErrorEvent$Context;Lcom/datadog/android/rum/model/ErrorEvent$Action;Lcom/datadog/android/rum/model/ErrorEvent$Container;Lcom/datadog/android/rum/model/ErrorEvent$Error;Lcom/datadog/android/rum/model/ErrorEvent$Freeze;Lcom/datadog/android/rum/model/ErrorEvent$Context;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (JLcom/datadog/android/rum/model/ErrorEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventView;Lcom/datadog/android/rum/model/ErrorEvent$Usr;Lcom/datadog/android/rum/model/ErrorEvent$Account;Lcom/datadog/android/rum/model/ErrorEvent$Tab;Lcom/datadog/android/rum/model/ErrorEvent$Connectivity;Lcom/datadog/android/rum/model/ErrorEvent$Display;Lcom/datadog/android/rum/model/ErrorEvent$Synthetics;Lcom/datadog/android/rum/model/ErrorEvent$CiTest;Lcom/datadog/android/rum/model/ErrorEvent$Os;Lcom/datadog/android/rum/model/ErrorEvent$Device;Lcom/datadog/android/rum/model/ErrorEvent$Dd;Lcom/datadog/android/rum/model/ErrorEvent$Context;Lcom/datadog/android/rum/model/ErrorEvent$Stream;Lcom/datadog/android/rum/model/ErrorEvent$Action;Lcom/datadog/android/rum/model/ErrorEvent$Container;Lcom/datadog/android/rum/model/ErrorEvent$Error;Lcom/datadog/android/rum/model/ErrorEvent$Freeze;Lcom/datadog/android/rum/model/ErrorEvent$Context;)V + public synthetic fun (JLcom/datadog/android/rum/model/ErrorEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventView;Lcom/datadog/android/rum/model/ErrorEvent$Usr;Lcom/datadog/android/rum/model/ErrorEvent$Account;Lcom/datadog/android/rum/model/ErrorEvent$Tab;Lcom/datadog/android/rum/model/ErrorEvent$Connectivity;Lcom/datadog/android/rum/model/ErrorEvent$Display;Lcom/datadog/android/rum/model/ErrorEvent$Synthetics;Lcom/datadog/android/rum/model/ErrorEvent$CiTest;Lcom/datadog/android/rum/model/ErrorEvent$Os;Lcom/datadog/android/rum/model/ErrorEvent$Device;Lcom/datadog/android/rum/model/ErrorEvent$Dd;Lcom/datadog/android/rum/model/ErrorEvent$Context;Lcom/datadog/android/rum/model/ErrorEvent$Stream;Lcom/datadog/android/rum/model/ErrorEvent$Action;Lcom/datadog/android/rum/model/ErrorEvent$Container;Lcom/datadog/android/rum/model/ErrorEvent$Error;Lcom/datadog/android/rum/model/ErrorEvent$Freeze;Lcom/datadog/android/rum/model/ErrorEvent$Context;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()J public final fun component10 ()Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventView; public final fun component11 ()Lcom/datadog/android/rum/model/ErrorEvent$Usr; public final fun component12 ()Lcom/datadog/android/rum/model/ErrorEvent$Account; - public final fun component13 ()Lcom/datadog/android/rum/model/ErrorEvent$Connectivity; - public final fun component14 ()Lcom/datadog/android/rum/model/ErrorEvent$Display; - public final fun component15 ()Lcom/datadog/android/rum/model/ErrorEvent$Synthetics; - public final fun component16 ()Lcom/datadog/android/rum/model/ErrorEvent$CiTest; - public final fun component17 ()Lcom/datadog/android/rum/model/ErrorEvent$Os; - public final fun component18 ()Lcom/datadog/android/rum/model/ErrorEvent$Device; - public final fun component19 ()Lcom/datadog/android/rum/model/ErrorEvent$Dd; + public final fun component13 ()Lcom/datadog/android/rum/model/ErrorEvent$Tab; + public final fun component14 ()Lcom/datadog/android/rum/model/ErrorEvent$Connectivity; + public final fun component15 ()Lcom/datadog/android/rum/model/ErrorEvent$Display; + public final fun component16 ()Lcom/datadog/android/rum/model/ErrorEvent$Synthetics; + public final fun component17 ()Lcom/datadog/android/rum/model/ErrorEvent$CiTest; + public final fun component18 ()Lcom/datadog/android/rum/model/ErrorEvent$Os; + public final fun component19 ()Lcom/datadog/android/rum/model/ErrorEvent$Device; public final fun component2 ()Lcom/datadog/android/rum/model/ErrorEvent$Application; - public final fun component20 ()Lcom/datadog/android/rum/model/ErrorEvent$Context; - public final fun component21 ()Lcom/datadog/android/rum/model/ErrorEvent$Action; - public final fun component22 ()Lcom/datadog/android/rum/model/ErrorEvent$Container; - public final fun component23 ()Lcom/datadog/android/rum/model/ErrorEvent$Error; - public final fun component24 ()Lcom/datadog/android/rum/model/ErrorEvent$Freeze; - public final fun component25 ()Lcom/datadog/android/rum/model/ErrorEvent$Context; + public final fun component20 ()Lcom/datadog/android/rum/model/ErrorEvent$Dd; + public final fun component21 ()Lcom/datadog/android/rum/model/ErrorEvent$Context; + public final fun component22 ()Lcom/datadog/android/rum/model/ErrorEvent$Stream; + public final fun component23 ()Lcom/datadog/android/rum/model/ErrorEvent$Action; + public final fun component24 ()Lcom/datadog/android/rum/model/ErrorEvent$Container; + public final fun component25 ()Lcom/datadog/android/rum/model/ErrorEvent$Error; + public final fun component26 ()Lcom/datadog/android/rum/model/ErrorEvent$Freeze; + public final fun component27 ()Lcom/datadog/android/rum/model/ErrorEvent$Context; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; @@ -1537,8 +1587,8 @@ public final class com/datadog/android/rum/model/ErrorEvent { public final fun component7 ()Ljava/lang/String; public final fun component8 ()Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession; public final fun component9 ()Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; - public final fun copy (JLcom/datadog/android/rum/model/ErrorEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventView;Lcom/datadog/android/rum/model/ErrorEvent$Usr;Lcom/datadog/android/rum/model/ErrorEvent$Account;Lcom/datadog/android/rum/model/ErrorEvent$Connectivity;Lcom/datadog/android/rum/model/ErrorEvent$Display;Lcom/datadog/android/rum/model/ErrorEvent$Synthetics;Lcom/datadog/android/rum/model/ErrorEvent$CiTest;Lcom/datadog/android/rum/model/ErrorEvent$Os;Lcom/datadog/android/rum/model/ErrorEvent$Device;Lcom/datadog/android/rum/model/ErrorEvent$Dd;Lcom/datadog/android/rum/model/ErrorEvent$Context;Lcom/datadog/android/rum/model/ErrorEvent$Action;Lcom/datadog/android/rum/model/ErrorEvent$Container;Lcom/datadog/android/rum/model/ErrorEvent$Error;Lcom/datadog/android/rum/model/ErrorEvent$Freeze;Lcom/datadog/android/rum/model/ErrorEvent$Context;)Lcom/datadog/android/rum/model/ErrorEvent; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ErrorEvent;JLcom/datadog/android/rum/model/ErrorEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventView;Lcom/datadog/android/rum/model/ErrorEvent$Usr;Lcom/datadog/android/rum/model/ErrorEvent$Account;Lcom/datadog/android/rum/model/ErrorEvent$Connectivity;Lcom/datadog/android/rum/model/ErrorEvent$Display;Lcom/datadog/android/rum/model/ErrorEvent$Synthetics;Lcom/datadog/android/rum/model/ErrorEvent$CiTest;Lcom/datadog/android/rum/model/ErrorEvent$Os;Lcom/datadog/android/rum/model/ErrorEvent$Device;Lcom/datadog/android/rum/model/ErrorEvent$Dd;Lcom/datadog/android/rum/model/ErrorEvent$Context;Lcom/datadog/android/rum/model/ErrorEvent$Action;Lcom/datadog/android/rum/model/ErrorEvent$Container;Lcom/datadog/android/rum/model/ErrorEvent$Error;Lcom/datadog/android/rum/model/ErrorEvent$Freeze;Lcom/datadog/android/rum/model/ErrorEvent$Context;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ErrorEvent; + public final fun copy (JLcom/datadog/android/rum/model/ErrorEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventView;Lcom/datadog/android/rum/model/ErrorEvent$Usr;Lcom/datadog/android/rum/model/ErrorEvent$Account;Lcom/datadog/android/rum/model/ErrorEvent$Tab;Lcom/datadog/android/rum/model/ErrorEvent$Connectivity;Lcom/datadog/android/rum/model/ErrorEvent$Display;Lcom/datadog/android/rum/model/ErrorEvent$Synthetics;Lcom/datadog/android/rum/model/ErrorEvent$CiTest;Lcom/datadog/android/rum/model/ErrorEvent$Os;Lcom/datadog/android/rum/model/ErrorEvent$Device;Lcom/datadog/android/rum/model/ErrorEvent$Dd;Lcom/datadog/android/rum/model/ErrorEvent$Context;Lcom/datadog/android/rum/model/ErrorEvent$Stream;Lcom/datadog/android/rum/model/ErrorEvent$Action;Lcom/datadog/android/rum/model/ErrorEvent$Container;Lcom/datadog/android/rum/model/ErrorEvent$Error;Lcom/datadog/android/rum/model/ErrorEvent$Freeze;Lcom/datadog/android/rum/model/ErrorEvent$Context;)Lcom/datadog/android/rum/model/ErrorEvent; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ErrorEvent;JLcom/datadog/android/rum/model/ErrorEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource;Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventView;Lcom/datadog/android/rum/model/ErrorEvent$Usr;Lcom/datadog/android/rum/model/ErrorEvent$Account;Lcom/datadog/android/rum/model/ErrorEvent$Tab;Lcom/datadog/android/rum/model/ErrorEvent$Connectivity;Lcom/datadog/android/rum/model/ErrorEvent$Display;Lcom/datadog/android/rum/model/ErrorEvent$Synthetics;Lcom/datadog/android/rum/model/ErrorEvent$CiTest;Lcom/datadog/android/rum/model/ErrorEvent$Os;Lcom/datadog/android/rum/model/ErrorEvent$Device;Lcom/datadog/android/rum/model/ErrorEvent$Dd;Lcom/datadog/android/rum/model/ErrorEvent$Context;Lcom/datadog/android/rum/model/ErrorEvent$Stream;Lcom/datadog/android/rum/model/ErrorEvent$Action;Lcom/datadog/android/rum/model/ErrorEvent$Container;Lcom/datadog/android/rum/model/ErrorEvent$Error;Lcom/datadog/android/rum/model/ErrorEvent$Freeze;Lcom/datadog/android/rum/model/ErrorEvent$Context;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ErrorEvent; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ErrorEvent; @@ -1563,7 +1613,9 @@ public final class com/datadog/android/rum/model/ErrorEvent { public final fun getService ()Ljava/lang/String; public final fun getSession ()Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSession; public final fun getSource ()Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; + public final fun getStream ()Lcom/datadog/android/rum/model/ErrorEvent$Stream; public final fun getSynthetics ()Lcom/datadog/android/rum/model/ErrorEvent$Synthetics; + public final fun getTab ()Lcom/datadog/android/rum/model/ErrorEvent$Tab; public final fun getType ()Ljava/lang/String; public final fun getUsr ()Lcom/datadog/android/rum/model/ErrorEvent$Usr; public final fun getVersion ()Ljava/lang/String; @@ -1770,18 +1822,20 @@ public final class com/datadog/android/rum/model/ErrorEvent$Companion { public final class com/datadog/android/rum/model/ErrorEvent$Configuration { public static final field Companion Lcom/datadog/android/rum/model/ErrorEvent$Configuration$Companion; - public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)V - public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)V + public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/Number; public final fun component2 ()Ljava/lang/Number; public final fun component3 ()Ljava/lang/Number; public final fun component4 ()Ljava/lang/Number; - public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/ErrorEvent$Configuration; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ErrorEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ErrorEvent$Configuration; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)Lcom/datadog/android/rum/model/ErrorEvent$Configuration; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ErrorEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ErrorEvent$Configuration; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent$Configuration; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ErrorEvent$Configuration; public final fun getProfilingSampleRate ()Ljava/lang/Number; + public final fun getSessionReplayExperimentalFeatures ()Ljava/util/List; public final fun getSessionReplaySampleRate ()Ljava/lang/Number; public final fun getSessionSampleRate ()Ljava/lang/Number; public final fun getTraceSampleRate ()Ljava/lang/Number; @@ -2202,6 +2256,7 @@ public final class com/datadog/android/rum/model/ErrorEvent$ErrorEventSessionTyp public final class com/datadog/android/rum/model/ErrorEvent$ErrorEventSource : java/lang/Enum { public static final field ANDROID Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; public static final field BROWSER Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; + public static final field CPP Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; public static final field Companion Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource$Companion; public static final field ELECTRON Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; public static final field FLUTTER Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; @@ -2210,7 +2265,6 @@ public final class com/datadog/android/rum/model/ErrorEvent$ErrorEventSource : j public static final field MAUI Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; public static final field REACT_NATIVE Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; public static final field ROKU Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; - public static final field RUM_CPP Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; public static final field UNITY Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent$ErrorEventSource; public final fun toJson ()Lcom/google/gson/JsonElement; @@ -2609,6 +2663,26 @@ public final class com/datadog/android/rum/model/ErrorEvent$SourceType$Companion public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent$SourceType; } +public final class com/datadog/android/rum/model/ErrorEvent$Stream { + public static final field Companion Lcom/datadog/android/rum/model/ErrorEvent$Stream$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent$Stream; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ErrorEvent$Stream;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ErrorEvent$Stream; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent$Stream; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ErrorEvent$Stream; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ErrorEvent$Stream$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent$Stream; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ErrorEvent$Stream; +} + public final class com/datadog/android/rum/model/ErrorEvent$Synthetics { public static final field Companion Lcom/datadog/android/rum/model/ErrorEvent$Synthetics$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)V @@ -2636,6 +2710,26 @@ public final class com/datadog/android/rum/model/ErrorEvent$Synthetics$Companion public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ErrorEvent$Synthetics; } +public final class com/datadog/android/rum/model/ErrorEvent$Tab { + public static final field Companion Lcom/datadog/android/rum/model/ErrorEvent$Tab$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent$Tab; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ErrorEvent$Tab;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ErrorEvent$Tab; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent$Tab; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ErrorEvent$Tab; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ErrorEvent$Tab$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ErrorEvent$Tab; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ErrorEvent$Tab; +} + public final class com/datadog/android/rum/model/ErrorEvent$Thread { public static final field Companion Lcom/datadog/android/rum/model/ErrorEvent$Thread$Companion; public fun (Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V @@ -2717,24 +2811,26 @@ public final class com/datadog/android/rum/model/ErrorEvent$Viewport$Companion { public final class com/datadog/android/rum/model/LongTaskEvent { public static final field Companion Lcom/datadog/android/rum/model/LongTaskEvent$Companion; - public fun (JLcom/datadog/android/rum/model/LongTaskEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventView;Lcom/datadog/android/rum/model/LongTaskEvent$Usr;Lcom/datadog/android/rum/model/LongTaskEvent$Account;Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity;Lcom/datadog/android/rum/model/LongTaskEvent$Display;Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics;Lcom/datadog/android/rum/model/LongTaskEvent$CiTest;Lcom/datadog/android/rum/model/LongTaskEvent$Os;Lcom/datadog/android/rum/model/LongTaskEvent$Device;Lcom/datadog/android/rum/model/LongTaskEvent$Dd;Lcom/datadog/android/rum/model/LongTaskEvent$Context;Lcom/datadog/android/rum/model/LongTaskEvent$Action;Lcom/datadog/android/rum/model/LongTaskEvent$Container;Lcom/datadog/android/rum/model/LongTaskEvent$LongTask;)V - public synthetic fun (JLcom/datadog/android/rum/model/LongTaskEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventView;Lcom/datadog/android/rum/model/LongTaskEvent$Usr;Lcom/datadog/android/rum/model/LongTaskEvent$Account;Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity;Lcom/datadog/android/rum/model/LongTaskEvent$Display;Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics;Lcom/datadog/android/rum/model/LongTaskEvent$CiTest;Lcom/datadog/android/rum/model/LongTaskEvent$Os;Lcom/datadog/android/rum/model/LongTaskEvent$Device;Lcom/datadog/android/rum/model/LongTaskEvent$Dd;Lcom/datadog/android/rum/model/LongTaskEvent$Context;Lcom/datadog/android/rum/model/LongTaskEvent$Action;Lcom/datadog/android/rum/model/LongTaskEvent$Container;Lcom/datadog/android/rum/model/LongTaskEvent$LongTask;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (JLcom/datadog/android/rum/model/LongTaskEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventView;Lcom/datadog/android/rum/model/LongTaskEvent$Usr;Lcom/datadog/android/rum/model/LongTaskEvent$Account;Lcom/datadog/android/rum/model/LongTaskEvent$Tab;Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity;Lcom/datadog/android/rum/model/LongTaskEvent$Display;Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics;Lcom/datadog/android/rum/model/LongTaskEvent$CiTest;Lcom/datadog/android/rum/model/LongTaskEvent$Os;Lcom/datadog/android/rum/model/LongTaskEvent$Device;Lcom/datadog/android/rum/model/LongTaskEvent$Dd;Lcom/datadog/android/rum/model/LongTaskEvent$Context;Lcom/datadog/android/rum/model/LongTaskEvent$Stream;Lcom/datadog/android/rum/model/LongTaskEvent$Action;Lcom/datadog/android/rum/model/LongTaskEvent$Container;Lcom/datadog/android/rum/model/LongTaskEvent$LongTask;)V + public synthetic fun (JLcom/datadog/android/rum/model/LongTaskEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventView;Lcom/datadog/android/rum/model/LongTaskEvent$Usr;Lcom/datadog/android/rum/model/LongTaskEvent$Account;Lcom/datadog/android/rum/model/LongTaskEvent$Tab;Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity;Lcom/datadog/android/rum/model/LongTaskEvent$Display;Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics;Lcom/datadog/android/rum/model/LongTaskEvent$CiTest;Lcom/datadog/android/rum/model/LongTaskEvent$Os;Lcom/datadog/android/rum/model/LongTaskEvent$Device;Lcom/datadog/android/rum/model/LongTaskEvent$Dd;Lcom/datadog/android/rum/model/LongTaskEvent$Context;Lcom/datadog/android/rum/model/LongTaskEvent$Stream;Lcom/datadog/android/rum/model/LongTaskEvent$Action;Lcom/datadog/android/rum/model/LongTaskEvent$Container;Lcom/datadog/android/rum/model/LongTaskEvent$LongTask;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()J public final fun component10 ()Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventView; public final fun component11 ()Lcom/datadog/android/rum/model/LongTaskEvent$Usr; public final fun component12 ()Lcom/datadog/android/rum/model/LongTaskEvent$Account; - public final fun component13 ()Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity; - public final fun component14 ()Lcom/datadog/android/rum/model/LongTaskEvent$Display; - public final fun component15 ()Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics; - public final fun component16 ()Lcom/datadog/android/rum/model/LongTaskEvent$CiTest; - public final fun component17 ()Lcom/datadog/android/rum/model/LongTaskEvent$Os; - public final fun component18 ()Lcom/datadog/android/rum/model/LongTaskEvent$Device; - public final fun component19 ()Lcom/datadog/android/rum/model/LongTaskEvent$Dd; + public final fun component13 ()Lcom/datadog/android/rum/model/LongTaskEvent$Tab; + public final fun component14 ()Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity; + public final fun component15 ()Lcom/datadog/android/rum/model/LongTaskEvent$Display; + public final fun component16 ()Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics; + public final fun component17 ()Lcom/datadog/android/rum/model/LongTaskEvent$CiTest; + public final fun component18 ()Lcom/datadog/android/rum/model/LongTaskEvent$Os; + public final fun component19 ()Lcom/datadog/android/rum/model/LongTaskEvent$Device; public final fun component2 ()Lcom/datadog/android/rum/model/LongTaskEvent$Application; - public final fun component20 ()Lcom/datadog/android/rum/model/LongTaskEvent$Context; - public final fun component21 ()Lcom/datadog/android/rum/model/LongTaskEvent$Action; - public final fun component22 ()Lcom/datadog/android/rum/model/LongTaskEvent$Container; - public final fun component23 ()Lcom/datadog/android/rum/model/LongTaskEvent$LongTask; + public final fun component20 ()Lcom/datadog/android/rum/model/LongTaskEvent$Dd; + public final fun component21 ()Lcom/datadog/android/rum/model/LongTaskEvent$Context; + public final fun component22 ()Lcom/datadog/android/rum/model/LongTaskEvent$Stream; + public final fun component23 ()Lcom/datadog/android/rum/model/LongTaskEvent$Action; + public final fun component24 ()Lcom/datadog/android/rum/model/LongTaskEvent$Container; + public final fun component25 ()Lcom/datadog/android/rum/model/LongTaskEvent$LongTask; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; @@ -2742,8 +2838,8 @@ public final class com/datadog/android/rum/model/LongTaskEvent { public final fun component7 ()Ljava/lang/String; public final fun component8 ()Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession; public final fun component9 ()Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; - public final fun copy (JLcom/datadog/android/rum/model/LongTaskEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventView;Lcom/datadog/android/rum/model/LongTaskEvent$Usr;Lcom/datadog/android/rum/model/LongTaskEvent$Account;Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity;Lcom/datadog/android/rum/model/LongTaskEvent$Display;Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics;Lcom/datadog/android/rum/model/LongTaskEvent$CiTest;Lcom/datadog/android/rum/model/LongTaskEvent$Os;Lcom/datadog/android/rum/model/LongTaskEvent$Device;Lcom/datadog/android/rum/model/LongTaskEvent$Dd;Lcom/datadog/android/rum/model/LongTaskEvent$Context;Lcom/datadog/android/rum/model/LongTaskEvent$Action;Lcom/datadog/android/rum/model/LongTaskEvent$Container;Lcom/datadog/android/rum/model/LongTaskEvent$LongTask;)Lcom/datadog/android/rum/model/LongTaskEvent; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/LongTaskEvent;JLcom/datadog/android/rum/model/LongTaskEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventView;Lcom/datadog/android/rum/model/LongTaskEvent$Usr;Lcom/datadog/android/rum/model/LongTaskEvent$Account;Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity;Lcom/datadog/android/rum/model/LongTaskEvent$Display;Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics;Lcom/datadog/android/rum/model/LongTaskEvent$CiTest;Lcom/datadog/android/rum/model/LongTaskEvent$Os;Lcom/datadog/android/rum/model/LongTaskEvent$Device;Lcom/datadog/android/rum/model/LongTaskEvent$Dd;Lcom/datadog/android/rum/model/LongTaskEvent$Context;Lcom/datadog/android/rum/model/LongTaskEvent$Action;Lcom/datadog/android/rum/model/LongTaskEvent$Container;Lcom/datadog/android/rum/model/LongTaskEvent$LongTask;ILjava/lang/Object;)Lcom/datadog/android/rum/model/LongTaskEvent; + public final fun copy (JLcom/datadog/android/rum/model/LongTaskEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventView;Lcom/datadog/android/rum/model/LongTaskEvent$Usr;Lcom/datadog/android/rum/model/LongTaskEvent$Account;Lcom/datadog/android/rum/model/LongTaskEvent$Tab;Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity;Lcom/datadog/android/rum/model/LongTaskEvent$Display;Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics;Lcom/datadog/android/rum/model/LongTaskEvent$CiTest;Lcom/datadog/android/rum/model/LongTaskEvent$Os;Lcom/datadog/android/rum/model/LongTaskEvent$Device;Lcom/datadog/android/rum/model/LongTaskEvent$Dd;Lcom/datadog/android/rum/model/LongTaskEvent$Context;Lcom/datadog/android/rum/model/LongTaskEvent$Stream;Lcom/datadog/android/rum/model/LongTaskEvent$Action;Lcom/datadog/android/rum/model/LongTaskEvent$Container;Lcom/datadog/android/rum/model/LongTaskEvent$LongTask;)Lcom/datadog/android/rum/model/LongTaskEvent; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/LongTaskEvent;JLcom/datadog/android/rum/model/LongTaskEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource;Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventView;Lcom/datadog/android/rum/model/LongTaskEvent$Usr;Lcom/datadog/android/rum/model/LongTaskEvent$Account;Lcom/datadog/android/rum/model/LongTaskEvent$Tab;Lcom/datadog/android/rum/model/LongTaskEvent$Connectivity;Lcom/datadog/android/rum/model/LongTaskEvent$Display;Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics;Lcom/datadog/android/rum/model/LongTaskEvent$CiTest;Lcom/datadog/android/rum/model/LongTaskEvent$Os;Lcom/datadog/android/rum/model/LongTaskEvent$Device;Lcom/datadog/android/rum/model/LongTaskEvent$Dd;Lcom/datadog/android/rum/model/LongTaskEvent$Context;Lcom/datadog/android/rum/model/LongTaskEvent$Stream;Lcom/datadog/android/rum/model/LongTaskEvent$Action;Lcom/datadog/android/rum/model/LongTaskEvent$Container;Lcom/datadog/android/rum/model/LongTaskEvent$LongTask;ILjava/lang/Object;)Lcom/datadog/android/rum/model/LongTaskEvent; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/LongTaskEvent; @@ -2766,7 +2862,9 @@ public final class com/datadog/android/rum/model/LongTaskEvent { public final fun getService ()Ljava/lang/String; public final fun getSession ()Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSession; public final fun getSource ()Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; + public final fun getStream ()Lcom/datadog/android/rum/model/LongTaskEvent$Stream; public final fun getSynthetics ()Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics; + public final fun getTab ()Lcom/datadog/android/rum/model/LongTaskEvent$Tab; public final fun getType ()Ljava/lang/String; public final fun getUsr ()Lcom/datadog/android/rum/model/LongTaskEvent$Usr; public final fun getVersion ()Ljava/lang/String; @@ -2895,18 +2993,20 @@ public final class com/datadog/android/rum/model/LongTaskEvent$Companion { public final class com/datadog/android/rum/model/LongTaskEvent$Configuration { public static final field Companion Lcom/datadog/android/rum/model/LongTaskEvent$Configuration$Companion; - public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)V - public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)V + public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/Number; public final fun component2 ()Ljava/lang/Number; public final fun component3 ()Ljava/lang/Number; public final fun component4 ()Ljava/lang/Number; - public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/LongTaskEvent$Configuration; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/LongTaskEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/LongTaskEvent$Configuration; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)Lcom/datadog/android/rum/model/LongTaskEvent$Configuration; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/LongTaskEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/LongTaskEvent$Configuration; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent$Configuration; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/LongTaskEvent$Configuration; public final fun getProfilingSampleRate ()Ljava/lang/Number; + public final fun getSessionReplayExperimentalFeatures ()Ljava/util/List; public final fun getSessionReplaySampleRate ()Ljava/lang/Number; public final fun getSessionSampleRate ()Ljava/lang/Number; public final fun getTraceSampleRate ()Ljava/lang/Number; @@ -3339,6 +3439,7 @@ public final class com/datadog/android/rum/model/LongTaskEvent$LongTaskEventSess public final class com/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource : java/lang/Enum { public static final field ANDROID Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; public static final field BROWSER Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; + public static final field CPP Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; public static final field Companion Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource$Companion; public static final field ELECTRON Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; public static final field FLUTTER Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; @@ -3347,7 +3448,6 @@ public final class com/datadog/android/rum/model/LongTaskEvent$LongTaskEventSour public static final field MAUI Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; public static final field REACT_NATIVE Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; public static final field ROKU Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; - public static final field RUM_CPP Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; public static final field UNITY Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent$LongTaskEventSource; public final fun toJson ()Lcom/google/gson/JsonElement; @@ -3535,6 +3635,26 @@ public final class com/datadog/android/rum/model/LongTaskEvent$SessionPreconditi public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent$SessionPrecondition; } +public final class com/datadog/android/rum/model/LongTaskEvent$Stream { + public static final field Companion Lcom/datadog/android/rum/model/LongTaskEvent$Stream$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent$Stream; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/LongTaskEvent$Stream;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/LongTaskEvent$Stream; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent$Stream; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/LongTaskEvent$Stream; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/LongTaskEvent$Stream$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent$Stream; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/LongTaskEvent$Stream; +} + public final class com/datadog/android/rum/model/LongTaskEvent$Synthetics { public static final field Companion Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)V @@ -3562,6 +3682,26 @@ public final class com/datadog/android/rum/model/LongTaskEvent$Synthetics$Compan public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/LongTaskEvent$Synthetics; } +public final class com/datadog/android/rum/model/LongTaskEvent$Tab { + public static final field Companion Lcom/datadog/android/rum/model/LongTaskEvent$Tab$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent$Tab; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/LongTaskEvent$Tab;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/LongTaskEvent$Tab; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent$Tab; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/LongTaskEvent$Tab; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/LongTaskEvent$Tab$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/LongTaskEvent$Tab; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/LongTaskEvent$Tab; +} + public final class com/datadog/android/rum/model/LongTaskEvent$Usr { public static final field Companion Lcom/datadog/android/rum/model/LongTaskEvent$Usr$Companion; public fun ()V @@ -3616,24 +3756,26 @@ public final class com/datadog/android/rum/model/LongTaskEvent$Viewport$Companio public final class com/datadog/android/rum/model/ResourceEvent { public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Companion; - public fun (JLcom/datadog/android/rum/model/ResourceEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventView;Lcom/datadog/android/rum/model/ResourceEvent$Usr;Lcom/datadog/android/rum/model/ResourceEvent$Account;Lcom/datadog/android/rum/model/ResourceEvent$Connectivity;Lcom/datadog/android/rum/model/ResourceEvent$Display;Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Lcom/datadog/android/rum/model/ResourceEvent$CiTest;Lcom/datadog/android/rum/model/ResourceEvent$Os;Lcom/datadog/android/rum/model/ResourceEvent$Device;Lcom/datadog/android/rum/model/ResourceEvent$Dd;Lcom/datadog/android/rum/model/ResourceEvent$Context;Lcom/datadog/android/rum/model/ResourceEvent$Action;Lcom/datadog/android/rum/model/ResourceEvent$Container;Lcom/datadog/android/rum/model/ResourceEvent$Resource;)V - public synthetic fun (JLcom/datadog/android/rum/model/ResourceEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventView;Lcom/datadog/android/rum/model/ResourceEvent$Usr;Lcom/datadog/android/rum/model/ResourceEvent$Account;Lcom/datadog/android/rum/model/ResourceEvent$Connectivity;Lcom/datadog/android/rum/model/ResourceEvent$Display;Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Lcom/datadog/android/rum/model/ResourceEvent$CiTest;Lcom/datadog/android/rum/model/ResourceEvent$Os;Lcom/datadog/android/rum/model/ResourceEvent$Device;Lcom/datadog/android/rum/model/ResourceEvent$Dd;Lcom/datadog/android/rum/model/ResourceEvent$Context;Lcom/datadog/android/rum/model/ResourceEvent$Action;Lcom/datadog/android/rum/model/ResourceEvent$Container;Lcom/datadog/android/rum/model/ResourceEvent$Resource;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (JLcom/datadog/android/rum/model/ResourceEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventView;Lcom/datadog/android/rum/model/ResourceEvent$Usr;Lcom/datadog/android/rum/model/ResourceEvent$Account;Lcom/datadog/android/rum/model/ResourceEvent$Tab;Lcom/datadog/android/rum/model/ResourceEvent$Connectivity;Lcom/datadog/android/rum/model/ResourceEvent$Display;Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Lcom/datadog/android/rum/model/ResourceEvent$CiTest;Lcom/datadog/android/rum/model/ResourceEvent$Os;Lcom/datadog/android/rum/model/ResourceEvent$Device;Lcom/datadog/android/rum/model/ResourceEvent$Dd;Lcom/datadog/android/rum/model/ResourceEvent$Context;Lcom/datadog/android/rum/model/ResourceEvent$Stream;Lcom/datadog/android/rum/model/ResourceEvent$Action;Lcom/datadog/android/rum/model/ResourceEvent$Container;Lcom/datadog/android/rum/model/ResourceEvent$Resource;)V + public synthetic fun (JLcom/datadog/android/rum/model/ResourceEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventView;Lcom/datadog/android/rum/model/ResourceEvent$Usr;Lcom/datadog/android/rum/model/ResourceEvent$Account;Lcom/datadog/android/rum/model/ResourceEvent$Tab;Lcom/datadog/android/rum/model/ResourceEvent$Connectivity;Lcom/datadog/android/rum/model/ResourceEvent$Display;Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Lcom/datadog/android/rum/model/ResourceEvent$CiTest;Lcom/datadog/android/rum/model/ResourceEvent$Os;Lcom/datadog/android/rum/model/ResourceEvent$Device;Lcom/datadog/android/rum/model/ResourceEvent$Dd;Lcom/datadog/android/rum/model/ResourceEvent$Context;Lcom/datadog/android/rum/model/ResourceEvent$Stream;Lcom/datadog/android/rum/model/ResourceEvent$Action;Lcom/datadog/android/rum/model/ResourceEvent$Container;Lcom/datadog/android/rum/model/ResourceEvent$Resource;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()J public final fun component10 ()Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventView; public final fun component11 ()Lcom/datadog/android/rum/model/ResourceEvent$Usr; public final fun component12 ()Lcom/datadog/android/rum/model/ResourceEvent$Account; - public final fun component13 ()Lcom/datadog/android/rum/model/ResourceEvent$Connectivity; - public final fun component14 ()Lcom/datadog/android/rum/model/ResourceEvent$Display; - public final fun component15 ()Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; - public final fun component16 ()Lcom/datadog/android/rum/model/ResourceEvent$CiTest; - public final fun component17 ()Lcom/datadog/android/rum/model/ResourceEvent$Os; - public final fun component18 ()Lcom/datadog/android/rum/model/ResourceEvent$Device; - public final fun component19 ()Lcom/datadog/android/rum/model/ResourceEvent$Dd; + public final fun component13 ()Lcom/datadog/android/rum/model/ResourceEvent$Tab; + public final fun component14 ()Lcom/datadog/android/rum/model/ResourceEvent$Connectivity; + public final fun component15 ()Lcom/datadog/android/rum/model/ResourceEvent$Display; + public final fun component16 ()Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; + public final fun component17 ()Lcom/datadog/android/rum/model/ResourceEvent$CiTest; + public final fun component18 ()Lcom/datadog/android/rum/model/ResourceEvent$Os; + public final fun component19 ()Lcom/datadog/android/rum/model/ResourceEvent$Device; public final fun component2 ()Lcom/datadog/android/rum/model/ResourceEvent$Application; - public final fun component20 ()Lcom/datadog/android/rum/model/ResourceEvent$Context; - public final fun component21 ()Lcom/datadog/android/rum/model/ResourceEvent$Action; - public final fun component22 ()Lcom/datadog/android/rum/model/ResourceEvent$Container; - public final fun component23 ()Lcom/datadog/android/rum/model/ResourceEvent$Resource; + public final fun component20 ()Lcom/datadog/android/rum/model/ResourceEvent$Dd; + public final fun component21 ()Lcom/datadog/android/rum/model/ResourceEvent$Context; + public final fun component22 ()Lcom/datadog/android/rum/model/ResourceEvent$Stream; + public final fun component23 ()Lcom/datadog/android/rum/model/ResourceEvent$Action; + public final fun component24 ()Lcom/datadog/android/rum/model/ResourceEvent$Container; + public final fun component25 ()Lcom/datadog/android/rum/model/ResourceEvent$Resource; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; @@ -3641,8 +3783,8 @@ public final class com/datadog/android/rum/model/ResourceEvent { public final fun component7 ()Ljava/lang/String; public final fun component8 ()Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession; public final fun component9 ()Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; - public final fun copy (JLcom/datadog/android/rum/model/ResourceEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventView;Lcom/datadog/android/rum/model/ResourceEvent$Usr;Lcom/datadog/android/rum/model/ResourceEvent$Account;Lcom/datadog/android/rum/model/ResourceEvent$Connectivity;Lcom/datadog/android/rum/model/ResourceEvent$Display;Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Lcom/datadog/android/rum/model/ResourceEvent$CiTest;Lcom/datadog/android/rum/model/ResourceEvent$Os;Lcom/datadog/android/rum/model/ResourceEvent$Device;Lcom/datadog/android/rum/model/ResourceEvent$Dd;Lcom/datadog/android/rum/model/ResourceEvent$Context;Lcom/datadog/android/rum/model/ResourceEvent$Action;Lcom/datadog/android/rum/model/ResourceEvent$Container;Lcom/datadog/android/rum/model/ResourceEvent$Resource;)Lcom/datadog/android/rum/model/ResourceEvent; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent;JLcom/datadog/android/rum/model/ResourceEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventView;Lcom/datadog/android/rum/model/ResourceEvent$Usr;Lcom/datadog/android/rum/model/ResourceEvent$Account;Lcom/datadog/android/rum/model/ResourceEvent$Connectivity;Lcom/datadog/android/rum/model/ResourceEvent$Display;Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Lcom/datadog/android/rum/model/ResourceEvent$CiTest;Lcom/datadog/android/rum/model/ResourceEvent$Os;Lcom/datadog/android/rum/model/ResourceEvent$Device;Lcom/datadog/android/rum/model/ResourceEvent$Dd;Lcom/datadog/android/rum/model/ResourceEvent$Context;Lcom/datadog/android/rum/model/ResourceEvent$Action;Lcom/datadog/android/rum/model/ResourceEvent$Container;Lcom/datadog/android/rum/model/ResourceEvent$Resource;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent; + public final fun copy (JLcom/datadog/android/rum/model/ResourceEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventView;Lcom/datadog/android/rum/model/ResourceEvent$Usr;Lcom/datadog/android/rum/model/ResourceEvent$Account;Lcom/datadog/android/rum/model/ResourceEvent$Tab;Lcom/datadog/android/rum/model/ResourceEvent$Connectivity;Lcom/datadog/android/rum/model/ResourceEvent$Display;Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Lcom/datadog/android/rum/model/ResourceEvent$CiTest;Lcom/datadog/android/rum/model/ResourceEvent$Os;Lcom/datadog/android/rum/model/ResourceEvent$Device;Lcom/datadog/android/rum/model/ResourceEvent$Dd;Lcom/datadog/android/rum/model/ResourceEvent$Context;Lcom/datadog/android/rum/model/ResourceEvent$Stream;Lcom/datadog/android/rum/model/ResourceEvent$Action;Lcom/datadog/android/rum/model/ResourceEvent$Container;Lcom/datadog/android/rum/model/ResourceEvent$Resource;)Lcom/datadog/android/rum/model/ResourceEvent; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent;JLcom/datadog/android/rum/model/ResourceEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource;Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventView;Lcom/datadog/android/rum/model/ResourceEvent$Usr;Lcom/datadog/android/rum/model/ResourceEvent$Account;Lcom/datadog/android/rum/model/ResourceEvent$Tab;Lcom/datadog/android/rum/model/ResourceEvent$Connectivity;Lcom/datadog/android/rum/model/ResourceEvent$Display;Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Lcom/datadog/android/rum/model/ResourceEvent$CiTest;Lcom/datadog/android/rum/model/ResourceEvent$Os;Lcom/datadog/android/rum/model/ResourceEvent$Device;Lcom/datadog/android/rum/model/ResourceEvent$Dd;Lcom/datadog/android/rum/model/ResourceEvent$Context;Lcom/datadog/android/rum/model/ResourceEvent$Stream;Lcom/datadog/android/rum/model/ResourceEvent$Action;Lcom/datadog/android/rum/model/ResourceEvent$Container;Lcom/datadog/android/rum/model/ResourceEvent$Resource;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent; @@ -3665,7 +3807,9 @@ public final class com/datadog/android/rum/model/ResourceEvent { public final fun getService ()Ljava/lang/String; public final fun getSession ()Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSession; public final fun getSource ()Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; + public final fun getStream ()Lcom/datadog/android/rum/model/ResourceEvent$Stream; public final fun getSynthetics ()Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; + public final fun getTab ()Lcom/datadog/android/rum/model/ResourceEvent$Tab; public final fun getType ()Ljava/lang/String; public final fun getUsr ()Lcom/datadog/android/rum/model/ResourceEvent$Usr; public final fun getVersion ()Ljava/lang/String; @@ -3794,18 +3938,20 @@ public final class com/datadog/android/rum/model/ResourceEvent$Companion { public final class com/datadog/android/rum/model/ResourceEvent$Configuration { public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Configuration$Companion; - public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)V - public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)V + public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/Number; public final fun component2 ()Ljava/lang/Number; public final fun component3 ()Ljava/lang/Number; public final fun component4 ()Ljava/lang/Number; - public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/ResourceEvent$Configuration; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Configuration; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)Lcom/datadog/android/rum/model/ResourceEvent$Configuration; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Configuration; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Configuration; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Configuration; public final fun getProfilingSampleRate ()Ljava/lang/Number; + public final fun getSessionReplayExperimentalFeatures ()Ljava/util/List; public final fun getSessionReplaySampleRate ()Ljava/lang/Number; public final fun getSessionSampleRate ()Ljava/lang/Number; public final fun getTraceSampleRate ()Ljava/lang/Number; @@ -4661,6 +4807,7 @@ public final class com/datadog/android/rum/model/ResourceEvent$ResourceEventSess public final class com/datadog/android/rum/model/ResourceEvent$ResourceEventSource : java/lang/Enum { public static final field ANDROID Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; public static final field BROWSER Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; + public static final field CPP Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource$Companion; public static final field ELECTRON Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; public static final field FLUTTER Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; @@ -4669,7 +4816,6 @@ public final class com/datadog/android/rum/model/ResourceEvent$ResourceEventSour public static final field MAUI Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; public static final field REACT_NATIVE Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; public static final field ROKU Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; - public static final field RUM_CPP Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; public static final field UNITY Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$ResourceEventSource; public final fun toJson ()Lcom/google/gson/JsonElement; @@ -4751,80 +4897,1548 @@ public final class com/datadog/android/rum/model/ResourceEvent$Response { public fun toString ()Ljava/lang/String; } -public final class com/datadog/android/rum/model/ResourceEvent$Response$Companion { - public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Response; - public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Response; +public final class com/datadog/android/rum/model/ResourceEvent$Response$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Response; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Response; +} + +public final class com/datadog/android/rum/model/ResourceEvent$SessionPrecondition : java/lang/Enum { + public static final field BACKGROUND_LAUNCH Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition$Companion; + public static final field EXPLICIT_STOP Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public static final field FROM_NON_INTERACTIVE_SESSION Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public static final field INACTIVITY_TIMEOUT Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public static final field MAX_DURATION Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public static final field PREWARM Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public static final field USER_APP_LAUNCH Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public static fun values ()[Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; +} + +public final class com/datadog/android/rum/model/ResourceEvent$SessionPrecondition$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Ssl { + public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Ssl$Companion; + public fun (JJ)V + public final fun component1 ()J + public final fun component2 ()J + public final fun copy (JJ)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Ssl;JJILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; + public final fun getDuration ()J + public final fun getStart ()J + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Ssl$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Status : java/lang/Enum { + public static final field CONNECTED Lcom/datadog/android/rum/model/ResourceEvent$Status; + public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Status$Companion; + public static final field MAYBE Lcom/datadog/android/rum/model/ResourceEvent$Status; + public static final field NOT_CONNECTED Lcom/datadog/android/rum/model/ResourceEvent$Status; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Status; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Status; + public static fun values ()[Lcom/datadog/android/rum/model/ResourceEvent$Status; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Status$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Status; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Stream { + public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Stream$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Stream; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Stream;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Stream; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Stream; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Stream; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Stream$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Stream; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Stream; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Synthetics { + public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Synthetics$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/Boolean; + public final fun component4 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; + public final fun getAdditionalProperties ()Ljava/util/Map; + public final fun getInjected ()Ljava/lang/Boolean; + public final fun getResultId ()Ljava/lang/String; + public final fun getTestId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Synthetics$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Tab { + public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Tab$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Tab; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Tab;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Tab; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Tab; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Tab; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Tab$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Tab; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Tab; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Usr { + public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Usr$Companion; + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Usr;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; + public final fun getAdditionalProperties ()Ljava/util/Map; + public final fun getAnonymousId ()Ljava/lang/String; + public final fun getEmail ()Ljava/lang/String; + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Usr$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Viewport { + public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Viewport$Companion; + public fun (Ljava/lang/Number;Ljava/lang/Number;)V + public final fun component1 ()Ljava/lang/Number; + public final fun component2 ()Ljava/lang/Number; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Viewport;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; + public final fun getHeight ()Ljava/lang/Number; + public final fun getWidth ()Ljava/lang/Number; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Viewport$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Worker { + public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Worker$Companion; + public fun (JJ)V + public final fun component1 ()J + public final fun component2 ()J + public final fun copy (JJ)Lcom/datadog/android/rum/model/ResourceEvent$Worker; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Worker;JJILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; + public final fun getDuration ()J + public final fun getStart ()J + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ResourceEvent$Worker$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Companion; + public fun (JLcom/datadog/android/rum/model/TimeseriesCpuEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries;)V + public synthetic fun (JLcom/datadog/android/rum/model/TimeseriesCpuEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()J + public final fun component10 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View; + public final fun component11 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr; + public final fun component12 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account; + public final fun component13 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab; + public final fun component14 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity; + public final fun component15 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display; + public final fun component16 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics; + public final fun component17 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest; + public final fun component18 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os; + public final fun component19 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application; + public final fun component20 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd; + public final fun component21 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context; + public final fun component22 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream; + public final fun component23 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/lang/String; + public final fun component7 ()Ljava/lang/String; + public final fun component8 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession; + public final fun component9 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public final fun copy (JLcom/datadog/android/rum/model/TimeseriesCpuEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent;JLcom/datadog/android/rum/model/TimeseriesCpuEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent; + public final fun getAccount ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account; + public final fun getApplication ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application; + public final fun getBuildId ()Ljava/lang/String; + public final fun getBuildVersion ()Ljava/lang/String; + public final fun getCiTest ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest; + public final fun getConnectivity ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity; + public final fun getContext ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context; + public final fun getDate ()J + public final fun getDd ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd; + public final fun getDdtags ()Ljava/lang/String; + public final fun getDevice ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device; + public final fun getDisplay ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display; + public final fun getOs ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os; + public final fun getService ()Ljava/lang/String; + public final fun getSession ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession; + public final fun getSource ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public final fun getStream ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream; + public final fun getSynthetics ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics; + public final fun getTab ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab; + public final fun getTimeseries ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries; + public final fun getType ()Ljava/lang/String; + public final fun getUsr ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr; + public final fun getVersion ()Ljava/lang/String; + public final fun getView ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Account { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account; + public final fun getAdditionalProperties ()Ljava/util/Map; + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Account$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Account; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Application { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application; + public final fun getCurrentLocale ()Ljava/lang/String; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Application$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Application; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Cellular { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular$Companion; + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular; + public final fun getCarrierName ()Ljava/lang/String; + public final fun getTechnology ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Cellular$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$CiTest { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest; + public final fun getTestExecutionId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$CiTest$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$CiTest; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Configuration { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration$Companion; + public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)V + public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/Number; + public final fun component2 ()Ljava/lang/Number; + public final fun component3 ()Ljava/lang/Number; + public final fun component4 ()Ljava/lang/Number; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration; + public final fun getProfilingSampleRate ()Ljava/lang/Number; + public final fun getSessionReplayExperimentalFeatures ()Ljava/util/List; + public final fun getSessionReplaySampleRate ()Ljava/lang/Number; + public final fun getSessionSampleRate ()Ljava/lang/Number; + public final fun getTraceSampleRate ()Ljava/lang/Number; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Configuration$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity$Companion; + public fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status; + public final fun component2 ()Ljava/util/List; + public final fun component3 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; + public final fun component4 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity; + public final fun getCellular ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Cellular; + public final fun getEffectiveType ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; + public final fun getInterfaces ()Ljava/util/List; + public final fun getStatus ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Connectivity; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Context { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context$Companion; + public fun ()V + public fun (Ljava/util/Map;)V + public synthetic fun (Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/util/Map; + public final fun copy (Ljava/util/Map;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context; + public final fun getAdditionalProperties ()Ljava/util/Map; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Context$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Context; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Data { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data$Companion; + public fun (Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values;)V + public final fun component1 ()Ljava/util/List; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values; + public final fun copy (Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data; + public final fun getTimestamps ()Ljava/util/List; + public final fun getValues ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Data$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Dd { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd$Companion; + public fun ()V + public fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration;Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd; + public final fun getBrowserSdkVersion ()Ljava/lang/String; + public final fun getConfiguration ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Configuration; + public final fun getFormatVersion ()J + public final fun getSdkName ()Ljava/lang/String; + public final fun getSession ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Dd$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Dd; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$DdSession { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession$Companion; + public fun ()V + public fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession; + public final fun getPlan ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan; + public final fun getSessionPrecondition ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$DdSession$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DdSession; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Device { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device$Companion; + public fun ()V + public fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Boolean;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Boolean;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public final fun component10 ()Ljava/lang/Boolean; + public final fun component11 ()Ljava/lang/Number; + public final fun component12 ()Ljava/lang/Number; + public final fun component13 ()Ljava/lang/Number; + public final fun component14 ()Ljava/lang/Boolean; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/lang/String; + public final fun component7 ()Ljava/util/List; + public final fun component8 ()Ljava/lang/String; + public final fun component9 ()Ljava/lang/Number; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Boolean;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Boolean;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device; + public final fun getArchitecture ()Ljava/lang/String; + public final fun getBatteryLevel ()Ljava/lang/Number; + public final fun getBrand ()Ljava/lang/String; + public final fun getBrightnessLevel ()Ljava/lang/Number; + public final fun getLocale ()Ljava/lang/String; + public final fun getLocales ()Ljava/util/List; + public final fun getLogicalCpuCount ()Ljava/lang/Number; + public final fun getModel ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public final fun getPowerSavingMode ()Ljava/lang/Boolean; + public final fun getTimeZone ()Ljava/lang/String; + public final fun getTotalRam ()Ljava/lang/Number; + public final fun getType ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public fun hashCode ()I + public final fun isLowRam ()Ljava/lang/Boolean; + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Device$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Device; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType : java/lang/Enum { + public static final field BOT Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType$Companion; + public static final field DESKTOP Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public static final field GAMING_CONSOLE Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public static final field MOBILE Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public static final field OTHER Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public static final field TABLET Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public static final field TV Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$DeviceType; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Display { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display$Companion; + public fun ()V + public fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display; + public final fun getViewport ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Display$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Display; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType : java/lang/Enum { + public static final field 2G Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; + public static final field 3G Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; + public static final field 4G Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType$Companion; + public static final field SLOW_2G Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$EffectiveType; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Interface : java/lang/Enum { + public static final field BLUETOOTH Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static final field CELLULAR Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface$Companion; + public static final field ETHERNET Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static final field MIXED Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static final field NONE Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static final field OTHER Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static final field UNKNOWN Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static final field WIFI Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static final field WIMAX Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Interface$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Interface; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Os { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os; + public final fun getBuild ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public final fun getVersion ()Ljava/lang/String; + public final fun getVersionMajor ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Os$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Os; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Plan : java/lang/Enum { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan$Companion; + public static final field PLAN_1 Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan; + public static final field PLAN_2 Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Plan$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Plan; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition : java/lang/Enum { + public static final field BACKGROUND_LAUNCH Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition$Companion; + public static final field EXPLICIT_STOP Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public static final field FROM_NON_INTERACTIVE_SESSION Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public static final field INACTIVITY_TIMEOUT Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public static final field MAX_DURATION Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public static final field PREWARM Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public static final field USER_APP_LAUNCH Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$SessionPrecondition; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Source : java/lang/Enum { + public static final field ANDROID Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field BROWSER Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field CPP Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source$Companion; + public static final field ELECTRON Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field FLUTTER Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field IOS Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field KOTLIN_MULTIPLATFORM Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field MAUI Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field REACT_NATIVE Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field ROKU Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final field UNITY Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Source$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Source; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Status : java/lang/Enum { + public static final field CONNECTED Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status$Companion; + public static final field MAYBE Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status; + public static final field NOT_CONNECTED Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Status$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Status; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Stream { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Stream$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Stream; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/Boolean; + public final fun component4 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics; + public final fun getAdditionalProperties ()Ljava/util/Map; + public final fun getInjected ()Ljava/lang/Boolean; + public final fun getResultId ()Ljava/lang/String; + public final fun getTestId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Synthetics; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Tab { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Tab$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Tab; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries$Companion; + public fun (Ljava/lang/String;JJLcom/datadog/android/rum/model/TimeseriesCpuEvent$Data;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()J + public final fun component3 ()J + public final fun component4 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data; + public final fun copy (Ljava/lang/String;JJLcom/datadog/android/rum/model/TimeseriesCpuEvent$Data;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries;Ljava/lang/String;JJLcom/datadog/android/rum/model/TimeseriesCpuEvent$Data;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries; + public final fun getData ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Data; + public final fun getEnd ()J + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public final fun getSchema ()Ljava/lang/String; + public final fun getStart ()J + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Timeseries; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession$Companion; + public fun (Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType;Ljava/lang/Boolean;)V + public synthetic fun (Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType; + public final fun component3 ()Ljava/lang/Boolean; + public final fun copy (Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType;Ljava/lang/Boolean;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession; + public final fun getHasReplay ()Ljava/lang/Boolean; + public final fun getId ()Ljava/lang/String; + public final fun getType ()Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSession; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType : java/lang/Enum { + public static final field CI_TEST Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType$Companion; + public static final field SYNTHETICS Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType; + public static final field USER Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$TimeseriesCpuEventSessionType; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Usr { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr$Companion; + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr; + public final fun getAdditionalProperties ()Ljava/util/Map; + public final fun getAnonymousId ()Ljava/lang/String; + public final fun getEmail ()Ljava/lang/String; + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Usr$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Usr; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Values { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values$Companion; + public fun (Ljava/util/List;)V + public final fun component1 ()Ljava/util/List; + public final fun copy (Ljava/util/List;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values; + public final fun getCpuUsage ()Ljava/util/List; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Values$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Values; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$View { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View; + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public final fun getReferrer ()Ljava/lang/String; + public final fun getUrl ()Ljava/lang/String; + public fun hashCode ()I + public final fun setName (Ljava/lang/String;)V + public final fun setReferrer (Ljava/lang/String;)V + public final fun setUrl (Ljava/lang/String;)V + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$View$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$View; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Viewport { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport$Companion; + public fun (Ljava/lang/Number;Ljava/lang/Number;)V + public final fun component1 ()Ljava/lang/Number; + public final fun component2 ()Ljava/lang/Number; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport; + public final fun getHeight ()Ljava/lang/Number; + public final fun getWidth ()Ljava/lang/Number; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesCpuEvent$Viewport$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesCpuEvent$Viewport; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Companion; + public fun (JLcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries;)V + public synthetic fun (JLcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()J + public final fun component10 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View; + public final fun component11 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr; + public final fun component12 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account; + public final fun component13 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab; + public final fun component14 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity; + public final fun component15 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display; + public final fun component16 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics; + public final fun component17 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest; + public final fun component18 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os; + public final fun component19 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application; + public final fun component20 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd; + public final fun component21 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context; + public final fun component22 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream; + public final fun component23 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/lang/String; + public final fun component7 ()Ljava/lang/String; + public final fun component8 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession; + public final fun component9 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public final fun copy (JLcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent;JLcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent; + public final fun getAccount ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account; + public final fun getApplication ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application; + public final fun getBuildId ()Ljava/lang/String; + public final fun getBuildVersion ()Ljava/lang/String; + public final fun getCiTest ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest; + public final fun getConnectivity ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity; + public final fun getContext ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context; + public final fun getDate ()J + public final fun getDd ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd; + public final fun getDdtags ()Ljava/lang/String; + public final fun getDevice ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device; + public final fun getDisplay ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display; + public final fun getOs ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os; + public final fun getService ()Ljava/lang/String; + public final fun getSession ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession; + public final fun getSource ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public final fun getStream ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream; + public final fun getSynthetics ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics; + public final fun getTab ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab; + public final fun getTimeseries ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries; + public final fun getType ()Ljava/lang/String; + public final fun getUsr ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr; + public final fun getVersion ()Ljava/lang/String; + public final fun getView ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Account { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/util/Map; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account; + public final fun getAdditionalProperties ()Ljava/util/Map; + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Account$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Account; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Application { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application; + public final fun getCurrentLocale ()Ljava/lang/String; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Application$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Application; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular$Companion; + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular; + public final fun getCarrierName ()Ljava/lang/String; + public final fun getTechnology ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest; + public final fun getTestExecutionId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$CiTest; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration$Companion; + public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)V + public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/Number; + public final fun component2 ()Ljava/lang/Number; + public final fun component3 ()Ljava/lang/Number; + public final fun component4 ()Ljava/lang/Number; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration; + public final fun getProfilingSampleRate ()Ljava/lang/Number; + public final fun getSessionReplayExperimentalFeatures ()Ljava/util/List; + public final fun getSessionReplaySampleRate ()Ljava/lang/Number; + public final fun getSessionSampleRate ()Ljava/lang/Number; + public final fun getTraceSampleRate ()Ljava/lang/Number; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity$Companion; + public fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status; + public final fun component2 ()Ljava/util/List; + public final fun component3 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; + public final fun component4 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity; + public final fun getCellular ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Cellular; + public final fun getEffectiveType ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; + public final fun getInterfaces ()Ljava/util/List; + public final fun getStatus ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Connectivity; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Context { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context$Companion; + public fun ()V + public fun (Ljava/util/Map;)V + public synthetic fun (Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/util/Map; + public final fun copy (Ljava/util/Map;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context; + public final fun getAdditionalProperties ()Ljava/util/Map; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Context$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Context; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Data { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data$Companion; + public fun (Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values;)V + public final fun component1 ()Ljava/util/List; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values; + public final fun copy (Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data;Ljava/util/List;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data; + public final fun getTimestamps ()Ljava/util/List; + public final fun getValues ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Data$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Dd { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd$Companion; + public fun ()V + public fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration;Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd; + public final fun getBrowserSdkVersion ()Ljava/lang/String; + public final fun getConfiguration ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Configuration; + public final fun getFormatVersion ()J + public final fun getSdkName ()Ljava/lang/String; + public final fun getSession ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Dd$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Dd; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession$Companion; + public fun ()V + public fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession; + public final fun getPlan ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan; + public final fun getSessionPrecondition ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DdSession; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Device { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device$Companion; + public fun ()V + public fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Boolean;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Boolean;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public final fun component10 ()Ljava/lang/Boolean; + public final fun component11 ()Ljava/lang/Number; + public final fun component12 ()Ljava/lang/Number; + public final fun component13 ()Ljava/lang/Number; + public final fun component14 ()Ljava/lang/Boolean; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Ljava/lang/String; + public final fun component7 ()Ljava/util/List; + public final fun component8 ()Ljava/lang/String; + public final fun component9 ()Ljava/lang/Number; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Boolean;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Boolean;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device; + public final fun getArchitecture ()Ljava/lang/String; + public final fun getBatteryLevel ()Ljava/lang/Number; + public final fun getBrand ()Ljava/lang/String; + public final fun getBrightnessLevel ()Ljava/lang/Number; + public final fun getLocale ()Ljava/lang/String; + public final fun getLocales ()Ljava/util/List; + public final fun getLogicalCpuCount ()Ljava/lang/Number; + public final fun getModel ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public final fun getPowerSavingMode ()Ljava/lang/Boolean; + public final fun getTimeZone ()Ljava/lang/String; + public final fun getTotalRam ()Ljava/lang/Number; + public final fun getType ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public fun hashCode ()I + public final fun isLowRam ()Ljava/lang/Boolean; + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Device$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Device; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType : java/lang/Enum { + public static final field BOT Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType$Companion; + public static final field DESKTOP Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public static final field GAMING_CONSOLE Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public static final field MOBILE Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public static final field OTHER Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public static final field TABLET Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public static final field TV Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$DeviceType; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Display { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display$Companion; + public fun ()V + public fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport;)V + public synthetic fun (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport; + public final fun copy (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display; + public final fun getViewport ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Display$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Display; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType : java/lang/Enum { + public static final field 2G Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; + public static final field 3G Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; + public static final field 4G Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType$Companion; + public static final field SLOW_2G Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$EffectiveType; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Interface : java/lang/Enum { + public static final field BLUETOOTH Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static final field CELLULAR Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface$Companion; + public static final field ETHERNET Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static final field MIXED Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static final field NONE Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static final field OTHER Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static final field UNKNOWN Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static final field WIFI Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static final field WIMAX Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Interface$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Interface; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Os { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os; + public final fun getBuild ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public final fun getVersion ()Ljava/lang/String; + public final fun getVersionMajor ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Os$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Os; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Plan : java/lang/Enum { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan$Companion; + public static final field PLAN_1 Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan; + public static final field PLAN_2 Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Plan$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Plan; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition : java/lang/Enum { + public static final field BACKGROUND_LAUNCH Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition$Companion; + public static final field EXPLICIT_STOP Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public static final field FROM_NON_INTERACTIVE_SESSION Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public static final field INACTIVITY_TIMEOUT Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public static final field MAX_DURATION Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public static final field PREWARM Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public static final field USER_APP_LAUNCH Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$SessionPrecondition; } -public final class com/datadog/android/rum/model/ResourceEvent$SessionPrecondition : java/lang/Enum { - public static final field BACKGROUND_LAUNCH Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; - public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition$Companion; - public static final field EXPLICIT_STOP Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; - public static final field FROM_NON_INTERACTIVE_SESSION Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; - public static final field INACTIVITY_TIMEOUT Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; - public static final field MAX_DURATION Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; - public static final field PREWARM Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; - public static final field USER_APP_LAUNCH Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; - public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Source : java/lang/Enum { + public static final field ANDROID Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field BROWSER Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field CPP Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source$Companion; + public static final field ELECTRON Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field FLUTTER Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field IOS Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field KOTLIN_MULTIPLATFORM Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field MAUI Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field REACT_NATIVE Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field ROKU Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final field UNITY Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; public final fun toJson ()Lcom/google/gson/JsonElement; - public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; - public static fun values ()[Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; } -public final class com/datadog/android/rum/model/ResourceEvent$SessionPrecondition$Companion { - public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$SessionPrecondition; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Source$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Source; } -public final class com/datadog/android/rum/model/ResourceEvent$Ssl { - public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Ssl$Companion; - public fun (JJ)V - public final fun component1 ()J - public final fun component2 ()J - public final fun copy (JJ)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Ssl;JJILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; - public fun equals (Ljava/lang/Object;)Z - public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; - public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; - public final fun getDuration ()J - public final fun getStart ()J - public fun hashCode ()I +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Status : java/lang/Enum { + public static final field CONNECTED Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status$Companion; + public static final field MAYBE Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status; + public static final field NOT_CONNECTED Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status; public final fun toJson ()Lcom/google/gson/JsonElement; - public fun toString ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status; } -public final class com/datadog/android/rum/model/ResourceEvent$Ssl$Companion { - public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; - public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Ssl; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Status$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Status; } -public final class com/datadog/android/rum/model/ResourceEvent$Status : java/lang/Enum { - public static final field CONNECTED Lcom/datadog/android/rum/model/ResourceEvent$Status; - public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Status$Companion; - public static final field MAYBE Lcom/datadog/android/rum/model/ResourceEvent$Status; - public static final field NOT_CONNECTED Lcom/datadog/android/rum/model/ResourceEvent$Status; - public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Status; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Stream { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I public final fun toJson ()Lcom/google/gson/JsonElement; - public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Status; - public static fun values ()[Lcom/datadog/android/rum/model/ResourceEvent$Status; + public fun toString ()Ljava/lang/String; } -public final class com/datadog/android/rum/model/ResourceEvent$Status$Companion { - public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Status; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Stream$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Stream; } -public final class com/datadog/android/rum/model/ResourceEvent$Synthetics { - public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Synthetics$Companion; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)V public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/lang/Boolean; public final fun component4 ()Ljava/util/Map; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Synthetics;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics; public fun equals (Ljava/lang/Object;)Z - public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; - public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics; public final fun getAdditionalProperties ()Ljava/util/Map; public final fun getInjected ()Ljava/lang/Boolean; public final fun getResultId ()Ljava/lang/String; @@ -4834,13 +6448,101 @@ public final class com/datadog/android/rum/model/ResourceEvent$Synthetics { public fun toString ()Ljava/lang/String; } -public final class com/datadog/android/rum/model/ResourceEvent$Synthetics$Companion { - public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; - public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Synthetics; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Synthetics; } -public final class com/datadog/android/rum/model/ResourceEvent$Usr { - public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Usr$Companion; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Tab { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Tab$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Tab; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries$Companion; + public fun (Ljava/lang/String;JJLcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()J + public final fun component3 ()J + public final fun component4 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data; + public final fun copy (Ljava/lang/String;JJLcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries;Ljava/lang/String;JJLcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries; + public final fun getData ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Data; + public final fun getEnd ()J + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public final fun getSchema ()Ljava/lang/String; + public final fun getStart ()J + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Timeseries; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession$Companion; + public fun (Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType;Ljava/lang/Boolean;)V + public synthetic fun (Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType; + public final fun component3 ()Ljava/lang/Boolean; + public final fun copy (Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType;Ljava/lang/Boolean;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession;Ljava/lang/String;Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession; + public final fun getHasReplay ()Ljava/lang/Boolean; + public final fun getId ()Ljava/lang/String; + public final fun getType ()Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSession; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType : java/lang/Enum { + public static final field CI_TEST Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType; + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType$Companion; + public static final field SYNTHETICS Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType; + public static final field USER Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType; + public final fun toJson ()Lcom/google/gson/JsonElement; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType; + public static fun values ()[Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$TimeseriesMemoryEventSessionType; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Usr { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr$Companion; public fun ()V public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -4849,11 +6551,11 @@ public final class com/datadog/android/rum/model/ResourceEvent$Usr { public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/util/Map; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Usr;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr; public fun equals (Ljava/lang/Object;)Z - public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; - public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr; public final fun getAdditionalProperties ()Ljava/util/Map; public final fun getAnonymousId ()Ljava/lang/String; public final fun getEmail ()Ljava/lang/String; @@ -4864,75 +6566,107 @@ public final class com/datadog/android/rum/model/ResourceEvent$Usr { public fun toString ()Ljava/lang/String; } -public final class com/datadog/android/rum/model/ResourceEvent$Usr$Companion { - public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; - public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Usr; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Usr$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Usr; } -public final class com/datadog/android/rum/model/ResourceEvent$Viewport { - public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Viewport$Companion; - public fun (Ljava/lang/Number;Ljava/lang/Number;)V - public final fun component1 ()Ljava/lang/Number; - public final fun component2 ()Ljava/lang/Number; - public final fun copy (Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Viewport;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Values { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values$Companion; + public fun (Ljava/util/List;Ljava/util/List;)V + public final fun component1 ()Ljava/util/List; + public final fun component2 ()Ljava/util/List; + public final fun copy (Ljava/util/List;Ljava/util/List;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values; public fun equals (Ljava/lang/Object;)Z - public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; - public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; - public final fun getHeight ()Ljava/lang/Number; - public final fun getWidth ()Ljava/lang/Number; + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values; + public final fun getMemoryFootprint ()Ljava/util/List; + public final fun getMemoryPercent ()Ljava/util/List; public fun hashCode ()I public final fun toJson ()Lcom/google/gson/JsonElement; public fun toString ()Ljava/lang/String; } -public final class com/datadog/android/rum/model/ResourceEvent$Viewport$Companion { - public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; - public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Viewport; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Values$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Values; } -public final class com/datadog/android/rum/model/ResourceEvent$Worker { - public static final field Companion Lcom/datadog/android/rum/model/ResourceEvent$Worker$Companion; - public fun (JJ)V - public final fun component1 ()J - public final fun component2 ()J - public final fun copy (JJ)Lcom/datadog/android/rum/model/ResourceEvent$Worker; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ResourceEvent$Worker;JJILjava/lang/Object;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$View { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View; public fun equals (Ljava/lang/Object;)Z - public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; - public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; - public final fun getDuration ()J - public final fun getStart ()J + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View; + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public final fun getReferrer ()Ljava/lang/String; + public final fun getUrl ()Ljava/lang/String; public fun hashCode ()I + public final fun setName (Ljava/lang/String;)V + public final fun setReferrer (Ljava/lang/String;)V + public final fun setUrl (Ljava/lang/String;)V public final fun toJson ()Lcom/google/gson/JsonElement; public fun toString ()Ljava/lang/String; } -public final class com/datadog/android/rum/model/ResourceEvent$Worker$Companion { - public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; - public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ResourceEvent$Worker; +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$View$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$View; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport { + public static final field Companion Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport$Companion; + public fun (Ljava/lang/Number;Ljava/lang/Number;)V + public final fun component1 ()Ljava/lang/Number; + public final fun component2 ()Ljava/lang/Number; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport; + public final fun getHeight ()Ljava/lang/Number; + public final fun getWidth ()Ljava/lang/Number; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/TimeseriesMemoryEvent$Viewport; } public final class com/datadog/android/rum/model/ViewEvent { public static final field Companion Lcom/datadog/android/rum/model/ViewEvent$Companion; - public fun (JLcom/datadog/android/rum/model/ViewEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource;Lcom/datadog/android/rum/model/ViewEvent$ViewEventView;Lcom/datadog/android/rum/model/ViewEvent$Usr;Lcom/datadog/android/rum/model/ViewEvent$Account;Lcom/datadog/android/rum/model/ViewEvent$Connectivity;Lcom/datadog/android/rum/model/ViewEvent$Display;Lcom/datadog/android/rum/model/ViewEvent$Synthetics;Lcom/datadog/android/rum/model/ViewEvent$CiTest;Lcom/datadog/android/rum/model/ViewEvent$Os;Lcom/datadog/android/rum/model/ViewEvent$Device;Lcom/datadog/android/rum/model/ViewEvent$Dd;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Container;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Privacy;)V - public synthetic fun (JLcom/datadog/android/rum/model/ViewEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource;Lcom/datadog/android/rum/model/ViewEvent$ViewEventView;Lcom/datadog/android/rum/model/ViewEvent$Usr;Lcom/datadog/android/rum/model/ViewEvent$Account;Lcom/datadog/android/rum/model/ViewEvent$Connectivity;Lcom/datadog/android/rum/model/ViewEvent$Display;Lcom/datadog/android/rum/model/ViewEvent$Synthetics;Lcom/datadog/android/rum/model/ViewEvent$CiTest;Lcom/datadog/android/rum/model/ViewEvent$Os;Lcom/datadog/android/rum/model/ViewEvent$Device;Lcom/datadog/android/rum/model/ViewEvent$Dd;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Container;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Privacy;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (JLcom/datadog/android/rum/model/ViewEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource;Lcom/datadog/android/rum/model/ViewEvent$ViewEventView;Lcom/datadog/android/rum/model/ViewEvent$Usr;Lcom/datadog/android/rum/model/ViewEvent$Account;Lcom/datadog/android/rum/model/ViewEvent$Tab;Lcom/datadog/android/rum/model/ViewEvent$Connectivity;Lcom/datadog/android/rum/model/ViewEvent$Display;Lcom/datadog/android/rum/model/ViewEvent$Synthetics;Lcom/datadog/android/rum/model/ViewEvent$CiTest;Lcom/datadog/android/rum/model/ViewEvent$Os;Lcom/datadog/android/rum/model/ViewEvent$Device;Lcom/datadog/android/rum/model/ViewEvent$Dd;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Stream;Lcom/datadog/android/rum/model/ViewEvent$Container;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Privacy;)V + public synthetic fun (JLcom/datadog/android/rum/model/ViewEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource;Lcom/datadog/android/rum/model/ViewEvent$ViewEventView;Lcom/datadog/android/rum/model/ViewEvent$Usr;Lcom/datadog/android/rum/model/ViewEvent$Account;Lcom/datadog/android/rum/model/ViewEvent$Tab;Lcom/datadog/android/rum/model/ViewEvent$Connectivity;Lcom/datadog/android/rum/model/ViewEvent$Display;Lcom/datadog/android/rum/model/ViewEvent$Synthetics;Lcom/datadog/android/rum/model/ViewEvent$CiTest;Lcom/datadog/android/rum/model/ViewEvent$Os;Lcom/datadog/android/rum/model/ViewEvent$Device;Lcom/datadog/android/rum/model/ViewEvent$Dd;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Stream;Lcom/datadog/android/rum/model/ViewEvent$Container;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Privacy;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()J public final fun component10 ()Lcom/datadog/android/rum/model/ViewEvent$ViewEventView; public final fun component11 ()Lcom/datadog/android/rum/model/ViewEvent$Usr; public final fun component12 ()Lcom/datadog/android/rum/model/ViewEvent$Account; - public final fun component13 ()Lcom/datadog/android/rum/model/ViewEvent$Connectivity; - public final fun component14 ()Lcom/datadog/android/rum/model/ViewEvent$Display; - public final fun component15 ()Lcom/datadog/android/rum/model/ViewEvent$Synthetics; - public final fun component16 ()Lcom/datadog/android/rum/model/ViewEvent$CiTest; - public final fun component17 ()Lcom/datadog/android/rum/model/ViewEvent$Os; - public final fun component18 ()Lcom/datadog/android/rum/model/ViewEvent$Device; - public final fun component19 ()Lcom/datadog/android/rum/model/ViewEvent$Dd; + public final fun component13 ()Lcom/datadog/android/rum/model/ViewEvent$Tab; + public final fun component14 ()Lcom/datadog/android/rum/model/ViewEvent$Connectivity; + public final fun component15 ()Lcom/datadog/android/rum/model/ViewEvent$Display; + public final fun component16 ()Lcom/datadog/android/rum/model/ViewEvent$Synthetics; + public final fun component17 ()Lcom/datadog/android/rum/model/ViewEvent$CiTest; + public final fun component18 ()Lcom/datadog/android/rum/model/ViewEvent$Os; + public final fun component19 ()Lcom/datadog/android/rum/model/ViewEvent$Device; public final fun component2 ()Lcom/datadog/android/rum/model/ViewEvent$Application; - public final fun component20 ()Lcom/datadog/android/rum/model/ViewEvent$Context; - public final fun component21 ()Lcom/datadog/android/rum/model/ViewEvent$Container; - public final fun component22 ()Lcom/datadog/android/rum/model/ViewEvent$Context; - public final fun component23 ()Lcom/datadog/android/rum/model/ViewEvent$Privacy; + public final fun component20 ()Lcom/datadog/android/rum/model/ViewEvent$Dd; + public final fun component21 ()Lcom/datadog/android/rum/model/ViewEvent$Context; + public final fun component22 ()Lcom/datadog/android/rum/model/ViewEvent$Stream; + public final fun component23 ()Lcom/datadog/android/rum/model/ViewEvent$Container; + public final fun component24 ()Lcom/datadog/android/rum/model/ViewEvent$Context; + public final fun component25 ()Lcom/datadog/android/rum/model/ViewEvent$Privacy; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; @@ -4940,8 +6674,8 @@ public final class com/datadog/android/rum/model/ViewEvent { public final fun component7 ()Ljava/lang/String; public final fun component8 ()Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession; public final fun component9 ()Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; - public final fun copy (JLcom/datadog/android/rum/model/ViewEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource;Lcom/datadog/android/rum/model/ViewEvent$ViewEventView;Lcom/datadog/android/rum/model/ViewEvent$Usr;Lcom/datadog/android/rum/model/ViewEvent$Account;Lcom/datadog/android/rum/model/ViewEvent$Connectivity;Lcom/datadog/android/rum/model/ViewEvent$Display;Lcom/datadog/android/rum/model/ViewEvent$Synthetics;Lcom/datadog/android/rum/model/ViewEvent$CiTest;Lcom/datadog/android/rum/model/ViewEvent$Os;Lcom/datadog/android/rum/model/ViewEvent$Device;Lcom/datadog/android/rum/model/ViewEvent$Dd;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Container;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Privacy;)Lcom/datadog/android/rum/model/ViewEvent; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ViewEvent;JLcom/datadog/android/rum/model/ViewEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource;Lcom/datadog/android/rum/model/ViewEvent$ViewEventView;Lcom/datadog/android/rum/model/ViewEvent$Usr;Lcom/datadog/android/rum/model/ViewEvent$Account;Lcom/datadog/android/rum/model/ViewEvent$Connectivity;Lcom/datadog/android/rum/model/ViewEvent$Display;Lcom/datadog/android/rum/model/ViewEvent$Synthetics;Lcom/datadog/android/rum/model/ViewEvent$CiTest;Lcom/datadog/android/rum/model/ViewEvent$Os;Lcom/datadog/android/rum/model/ViewEvent$Device;Lcom/datadog/android/rum/model/ViewEvent$Dd;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Container;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Privacy;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ViewEvent; + public final fun copy (JLcom/datadog/android/rum/model/ViewEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource;Lcom/datadog/android/rum/model/ViewEvent$ViewEventView;Lcom/datadog/android/rum/model/ViewEvent$Usr;Lcom/datadog/android/rum/model/ViewEvent$Account;Lcom/datadog/android/rum/model/ViewEvent$Tab;Lcom/datadog/android/rum/model/ViewEvent$Connectivity;Lcom/datadog/android/rum/model/ViewEvent$Display;Lcom/datadog/android/rum/model/ViewEvent$Synthetics;Lcom/datadog/android/rum/model/ViewEvent$CiTest;Lcom/datadog/android/rum/model/ViewEvent$Os;Lcom/datadog/android/rum/model/ViewEvent$Device;Lcom/datadog/android/rum/model/ViewEvent$Dd;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Stream;Lcom/datadog/android/rum/model/ViewEvent$Container;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Privacy;)Lcom/datadog/android/rum/model/ViewEvent; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ViewEvent;JLcom/datadog/android/rum/model/ViewEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession;Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource;Lcom/datadog/android/rum/model/ViewEvent$ViewEventView;Lcom/datadog/android/rum/model/ViewEvent$Usr;Lcom/datadog/android/rum/model/ViewEvent$Account;Lcom/datadog/android/rum/model/ViewEvent$Tab;Lcom/datadog/android/rum/model/ViewEvent$Connectivity;Lcom/datadog/android/rum/model/ViewEvent$Display;Lcom/datadog/android/rum/model/ViewEvent$Synthetics;Lcom/datadog/android/rum/model/ViewEvent$CiTest;Lcom/datadog/android/rum/model/ViewEvent$Os;Lcom/datadog/android/rum/model/ViewEvent$Device;Lcom/datadog/android/rum/model/ViewEvent$Dd;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Stream;Lcom/datadog/android/rum/model/ViewEvent$Container;Lcom/datadog/android/rum/model/ViewEvent$Context;Lcom/datadog/android/rum/model/ViewEvent$Privacy;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ViewEvent; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ViewEvent; @@ -4964,7 +6698,9 @@ public final class com/datadog/android/rum/model/ViewEvent { public final fun getService ()Ljava/lang/String; public final fun getSession ()Lcom/datadog/android/rum/model/ViewEvent$ViewEventSession; public final fun getSource ()Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; + public final fun getStream ()Lcom/datadog/android/rum/model/ViewEvent$Stream; public final fun getSynthetics ()Lcom/datadog/android/rum/model/ViewEvent$Synthetics; + public final fun getTab ()Lcom/datadog/android/rum/model/ViewEvent$Tab; public final fun getType ()Ljava/lang/String; public final fun getUsr ()Lcom/datadog/android/rum/model/ViewEvent$Usr; public final fun getVersion ()Ljava/lang/String; @@ -5157,19 +6893,21 @@ public final class com/datadog/android/rum/model/ViewEvent$Companion { public final class com/datadog/android/rum/model/ViewEvent$Configuration { public static final field Companion Lcom/datadog/android/rum/model/ViewEvent$Configuration$Companion; - public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;)V - public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;Ljava/lang/Boolean;)V + public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/Number; public final fun component2 ()Ljava/lang/Number; public final fun component3 ()Ljava/lang/Number; public final fun component4 ()Ljava/lang/Number; - public final fun component5 ()Ljava/lang/Boolean; - public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;)Lcom/datadog/android/rum/model/ViewEvent$Configuration; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ViewEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ViewEvent$Configuration; + public final fun component5 ()Ljava/util/List; + public final fun component6 ()Ljava/lang/Boolean; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;Ljava/lang/Boolean;)Lcom/datadog/android/rum/model/ViewEvent$Configuration; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ViewEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ViewEvent$Configuration; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent$Configuration; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ViewEvent$Configuration; public final fun getProfilingSampleRate ()Ljava/lang/Number; + public final fun getSessionReplayExperimentalFeatures ()Ljava/util/List; public final fun getSessionReplaySampleRate ()Ljava/lang/Number; public final fun getSessionSampleRate ()Ljava/lang/Number; public final fun getStartSessionReplayRecordingManually ()Ljava/lang/Boolean; @@ -6236,6 +7974,26 @@ public final class com/datadog/android/rum/model/ViewEvent$State$Companion { public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent$State; } +public final class com/datadog/android/rum/model/ViewEvent$Stream { + public static final field Companion Lcom/datadog/android/rum/model/ViewEvent$Stream$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent$Stream; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ViewEvent$Stream;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ViewEvent$Stream; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent$Stream; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ViewEvent$Stream; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ViewEvent$Stream$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent$Stream; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ViewEvent$Stream; +} + public final class com/datadog/android/rum/model/ViewEvent$Synthetics { public static final field Companion Lcom/datadog/android/rum/model/ViewEvent$Synthetics$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)V @@ -6263,6 +8021,26 @@ public final class com/datadog/android/rum/model/ViewEvent$Synthetics$Companion public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ViewEvent$Synthetics; } +public final class com/datadog/android/rum/model/ViewEvent$Tab { + public static final field Companion Lcom/datadog/android/rum/model/ViewEvent$Tab$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent$Tab; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/ViewEvent$Tab;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/ViewEvent$Tab; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent$Tab; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ViewEvent$Tab; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/ViewEvent$Tab$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent$Tab; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/ViewEvent$Tab; +} + public final class com/datadog/android/rum/model/ViewEvent$Usr { public static final field Companion Lcom/datadog/android/rum/model/ViewEvent$Usr$Companion; public fun ()V @@ -6340,6 +8118,7 @@ public final class com/datadog/android/rum/model/ViewEvent$ViewEventSessionType$ public final class com/datadog/android/rum/model/ViewEvent$ViewEventSource : java/lang/Enum { public static final field ANDROID Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; public static final field BROWSER Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; + public static final field CPP Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; public static final field Companion Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource$Companion; public static final field ELECTRON Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; public static final field FLUTTER Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; @@ -6348,7 +8127,6 @@ public final class com/datadog/android/rum/model/ViewEvent$ViewEventSource : jav public static final field MAUI Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; public static final field REACT_NATIVE Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; public static final field ROKU Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; - public static final field RUM_CPP Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; public static final field UNITY Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/ViewEvent$ViewEventSource; public final fun toJson ()Lcom/google/gson/JsonElement; @@ -6508,23 +8286,25 @@ public final class com/datadog/android/rum/model/ViewEvent$Viewport$Companion { public final class com/datadog/android/rum/model/VitalAppLaunchEvent { public static final field Companion Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Companion; - public fun (JLcom/datadog/android/rum/model/VitalAppLaunchEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventView;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Account;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital;)V - public synthetic fun (JLcom/datadog/android/rum/model/VitalAppLaunchEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventView;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Account;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (JLcom/datadog/android/rum/model/VitalAppLaunchEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventView;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Account;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital;)V + public synthetic fun (JLcom/datadog/android/rum/model/VitalAppLaunchEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventView;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Account;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()J public final fun component10 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventView; public final fun component11 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr; public final fun component12 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Account; - public final fun component13 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity; - public final fun component14 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display; - public final fun component15 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics; - public final fun component16 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest; - public final fun component17 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os; - public final fun component18 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device; - public final fun component19 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd; + public final fun component13 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab; + public final fun component14 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity; + public final fun component15 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display; + public final fun component16 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics; + public final fun component17 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest; + public final fun component18 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os; + public final fun component19 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device; public final fun component2 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Application; - public final fun component20 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context; - public final fun component21 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container; - public final fun component22 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital; + public final fun component20 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd; + public final fun component21 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context; + public final fun component22 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream; + public final fun component23 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container; + public final fun component24 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; @@ -6532,8 +8312,8 @@ public final class com/datadog/android/rum/model/VitalAppLaunchEvent { public final fun component7 ()Ljava/lang/String; public final fun component8 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession; public final fun component9 ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; - public final fun copy (JLcom/datadog/android/rum/model/VitalAppLaunchEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventView;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Account;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalAppLaunchEvent;JLcom/datadog/android/rum/model/VitalAppLaunchEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventView;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Account;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent; + public final fun copy (JLcom/datadog/android/rum/model/VitalAppLaunchEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventView;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Account;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalAppLaunchEvent;JLcom/datadog/android/rum/model/VitalAppLaunchEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventView;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Account;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Connectivity;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Display;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$CiTest;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Os;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Device;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Dd;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Context;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Container;Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Vital;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent; @@ -6554,7 +8334,9 @@ public final class com/datadog/android/rum/model/VitalAppLaunchEvent { public final fun getService ()Ljava/lang/String; public final fun getSession ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSession; public final fun getSource ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; + public final fun getStream ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream; public final fun getSynthetics ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics; + public final fun getTab ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab; public final fun getType ()Ljava/lang/String; public final fun getUsr ()Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr; public final fun getVersion ()Ljava/lang/String; @@ -6678,18 +8460,20 @@ public final class com/datadog/android/rum/model/VitalAppLaunchEvent$Companion { public final class com/datadog/android/rum/model/VitalAppLaunchEvent$Configuration { public static final field Companion Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Configuration$Companion; - public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)V - public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)V + public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/Number; public final fun component2 ()Ljava/lang/Number; public final fun component3 ()Ljava/lang/Number; public final fun component4 ()Ljava/lang/Number; - public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Configuration; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Configuration; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Configuration; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Configuration; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Configuration; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Configuration; public final fun getProfilingSampleRate ()Ljava/lang/Number; + public final fun getSessionReplayExperimentalFeatures ()Ljava/util/List; public final fun getSessionReplaySampleRate ()Ljava/lang/Number; public final fun getSessionSampleRate ()Ljava/lang/Number; public final fun getTraceSampleRate ()Ljava/lang/Number; @@ -7124,6 +8908,26 @@ public final class com/datadog/android/rum/model/VitalAppLaunchEvent$StartupType public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$StartupType; } +public final class com/datadog/android/rum/model/VitalAppLaunchEvent$Stream { + public static final field Companion Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/VitalAppLaunchEvent$Stream$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Stream; +} + public final class com/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics { public static final field Companion Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)V @@ -7151,6 +8955,26 @@ public final class com/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics$ public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Synthetics; } +public final class com/datadog/android/rum/model/VitalAppLaunchEvent$Tab { + public static final field Companion Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/VitalAppLaunchEvent$Tab$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Tab; +} + public final class com/datadog/android/rum/model/VitalAppLaunchEvent$Usr { public static final field Companion Lcom/datadog/android/rum/model/VitalAppLaunchEvent$Usr$Companion; public fun ()V @@ -7282,6 +9106,7 @@ public final class com/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLau public final class com/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource : java/lang/Enum { public static final field ANDROID Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; public static final field BROWSER Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; + public static final field CPP Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; public static final field Companion Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource$Companion; public static final field ELECTRON Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; public static final field FLUTTER Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; @@ -7290,7 +9115,6 @@ public final class com/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLau public static final field MAUI Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; public static final field REACT_NATIVE Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; public static final field ROKU Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; - public static final field RUM_CPP Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; public static final field UNITY Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLaunchEventSource; public final fun toJson ()Lcom/google/gson/JsonElement; @@ -7334,23 +9158,25 @@ public final class com/datadog/android/rum/model/VitalAppLaunchEvent$VitalAppLau public final class com/datadog/android/rum/model/VitalOperationStepEvent { public static final field Companion Lcom/datadog/android/rum/model/VitalOperationStepEvent$Companion; - public fun (JLcom/datadog/android/rum/model/VitalOperationStepEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventView;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Account;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics;Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital;)V - public synthetic fun (JLcom/datadog/android/rum/model/VitalOperationStepEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventView;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Account;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics;Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (JLcom/datadog/android/rum/model/VitalOperationStepEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventView;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Account;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics;Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital;)V + public synthetic fun (JLcom/datadog/android/rum/model/VitalOperationStepEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventView;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Account;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics;Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()J public final fun component10 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventView; public final fun component11 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr; public final fun component12 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Account; - public final fun component13 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity; - public final fun component14 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display; - public final fun component15 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics; - public final fun component16 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest; - public final fun component17 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os; - public final fun component18 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device; - public final fun component19 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd; + public final fun component13 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab; + public final fun component14 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity; + public final fun component15 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display; + public final fun component16 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics; + public final fun component17 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest; + public final fun component18 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os; + public final fun component19 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device; public final fun component2 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Application; - public final fun component20 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context; - public final fun component21 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container; - public final fun component22 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital; + public final fun component20 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd; + public final fun component21 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context; + public final fun component22 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream; + public final fun component23 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container; + public final fun component24 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital; public final fun component3 ()Ljava/lang/String; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; @@ -7358,8 +9184,8 @@ public final class com/datadog/android/rum/model/VitalOperationStepEvent { public final fun component7 ()Ljava/lang/String; public final fun component8 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession; public final fun component9 ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; - public final fun copy (JLcom/datadog/android/rum/model/VitalOperationStepEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventView;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Account;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics;Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital;)Lcom/datadog/android/rum/model/VitalOperationStepEvent; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalOperationStepEvent;JLcom/datadog/android/rum/model/VitalOperationStepEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventView;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Account;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics;Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalOperationStepEvent; + public final fun copy (JLcom/datadog/android/rum/model/VitalOperationStepEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventView;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Account;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics;Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital;)Lcom/datadog/android/rum/model/VitalOperationStepEvent; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalOperationStepEvent;JLcom/datadog/android/rum/model/VitalOperationStepEvent$Application;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource;Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventView;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Account;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Connectivity;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Display;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics;Lcom/datadog/android/rum/model/VitalOperationStepEvent$CiTest;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Os;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Device;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Dd;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Context;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Container;Lcom/datadog/android/rum/model/VitalOperationStepEvent$Vital;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalOperationStepEvent; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalOperationStepEvent; @@ -7380,7 +9206,9 @@ public final class com/datadog/android/rum/model/VitalOperationStepEvent { public final fun getService ()Ljava/lang/String; public final fun getSession ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSession; public final fun getSource ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; + public final fun getStream ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream; public final fun getSynthetics ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics; + public final fun getTab ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab; public final fun getType ()Ljava/lang/String; public final fun getUsr ()Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr; public final fun getVersion ()Ljava/lang/String; @@ -7490,18 +9318,20 @@ public final class com/datadog/android/rum/model/VitalOperationStepEvent$Compani public final class com/datadog/android/rum/model/VitalOperationStepEvent$Configuration { public static final field Companion Lcom/datadog/android/rum/model/VitalOperationStepEvent$Configuration$Companion; - public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)V - public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)V + public synthetic fun (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/Number; public final fun component2 ()Ljava/lang/Number; public final fun component3 ()Ljava/lang/Number; public final fun component4 ()Ljava/lang/Number; - public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Configuration; - public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalOperationStepEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Configuration; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Configuration; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalOperationStepEvent$Configuration;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/lang/Number;Ljava/util/List;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Configuration; public fun equals (Ljava/lang/Object;)Z public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Configuration; public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Configuration; public final fun getProfilingSampleRate ()Ljava/lang/Number; + public final fun getSessionReplayExperimentalFeatures ()Ljava/util/List; public final fun getSessionReplaySampleRate ()Ljava/lang/Number; public final fun getSessionSampleRate ()Ljava/lang/Number; public final fun getTraceSampleRate ()Ljava/lang/Number; @@ -7953,6 +9783,26 @@ public final class com/datadog/android/rum/model/VitalOperationStepEvent$StepTyp public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$StepType; } +public final class com/datadog/android/rum/model/VitalOperationStepEvent$Stream { + public static final field Companion Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/VitalOperationStepEvent$Stream$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Stream; +} + public final class com/datadog/android/rum/model/VitalOperationStepEvent$Synthetics { public static final field Companion Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;)V @@ -7980,6 +9830,26 @@ public final class com/datadog/android/rum/model/VitalOperationStepEvent$Synthet public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Synthetics; } +public final class com/datadog/android/rum/model/VitalOperationStepEvent$Tab { + public static final field Companion Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab$Companion; + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab; + public static synthetic fun copy$default (Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab;Ljava/lang/String;ILjava/lang/Object;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab; + public fun equals (Ljava/lang/Object;)Z + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab; + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public final fun toJson ()Lcom/google/gson/JsonElement; + public fun toString ()Ljava/lang/String; +} + +public final class com/datadog/android/rum/model/VitalOperationStepEvent$Tab$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$Tab; +} + public final class com/datadog/android/rum/model/VitalOperationStepEvent$Usr { public static final field Companion Lcom/datadog/android/rum/model/VitalOperationStepEvent$Usr$Companion; public fun ()V @@ -8107,6 +9977,7 @@ public final class com/datadog/android/rum/model/VitalOperationStepEvent$VitalOp public final class com/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource : java/lang/Enum { public static final field ANDROID Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; public static final field BROWSER Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; + public static final field CPP Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; public static final field Companion Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource$Companion; public static final field ELECTRON Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; public static final field FLUTTER Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; @@ -8115,7 +9986,6 @@ public final class com/datadog/android/rum/model/VitalOperationStepEvent$VitalOp public static final field MAUI Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; public static final field REACT_NATIVE Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; public static final field ROKU Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; - public static final field RUM_CPP Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; public static final field UNITY Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/rum/model/VitalOperationStepEvent$VitalOperationStepEventSource; public final fun toJson ()Lcom/google/gson/JsonElement; @@ -8231,6 +10101,27 @@ public abstract interface class com/datadog/android/rum/startup/AppStartupActivi public abstract fun shouldTrackStartup (Landroid/app/Activity;)Z } +public final class com/datadog/android/rum/timeseries/TimeseriesConfiguration { + public static final field Companion Lcom/datadog/android/rum/timeseries/TimeseriesConfiguration$Companion; +} + +public final class com/datadog/android/rum/timeseries/TimeseriesConfiguration$Builder { + public fun ()V + public final fun build ()Lcom/datadog/android/rum/timeseries/TimeseriesConfiguration; + public final fun collectOnly ([Lcom/datadog/android/rum/timeseries/TimeseriesType;)Lcom/datadog/android/rum/timeseries/TimeseriesConfiguration$Builder; +} + +public final class com/datadog/android/rum/timeseries/TimeseriesConfiguration$Companion { + public final fun getDEFAULT ()Lcom/datadog/android/rum/timeseries/TimeseriesConfiguration; +} + +public final class com/datadog/android/rum/timeseries/TimeseriesType : java/lang/Enum { + public static final field CPU Lcom/datadog/android/rum/timeseries/TimeseriesType; + public static final field MEMORY Lcom/datadog/android/rum/timeseries/TimeseriesType; + public static fun valueOf (Ljava/lang/String;)Lcom/datadog/android/rum/timeseries/TimeseriesType; + public static fun values ()[Lcom/datadog/android/rum/timeseries/TimeseriesType; +} + public class com/datadog/android/rum/tracking/AcceptAllActivities : com/datadog/android/rum/tracking/ComponentPredicate { public fun ()V public fun accept (Landroid/app/Activity;)Z @@ -10393,6 +12284,20 @@ public final class com/datadog/android/telemetry/model/TelemetryUsageEvent$Usage public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$StopSession; } +public final class com/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$Timeseries : com/datadog/android/telemetry/model/TelemetryUsageEvent$Usage { + public static final field Companion Lcom/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$Timeseries$Companion; + public fun ()V + public static final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$Timeseries; + public static final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$Timeseries; + public final fun getFeature ()Ljava/lang/String; + public fun toJson ()Lcom/google/gson/JsonElement; +} + +public final class com/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$Timeseries$Companion { + public final fun fromJson (Ljava/lang/String;)Lcom/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$Timeseries; + public final fun fromJsonObject (Lcom/google/gson/JsonObject;)Lcom/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$Timeseries; +} + public final class com/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$TrackWebView : com/datadog/android/telemetry/model/TelemetryUsageEvent$Usage { public static final field Companion Lcom/datadog/android/telemetry/model/TelemetryUsageEvent$Usage$TrackWebView$Companion; public fun ()V diff --git a/features/dd-sdk-android-rum/build.gradle.kts b/features/dd-sdk-android-rum/build.gradle.kts index b5f21c4a2e..f75e49932f 100644 --- a/features/dd-sdk-android-rum/build.gradle.kts +++ b/features/dd-sdk-android-rum/build.gradle.kts @@ -166,7 +166,9 @@ createJsonModelsGenerationTask("generateRumModelsFromJson") { "view-schema.json" to "ViewEvent", "long_task-schema.json" to "LongTaskEvent", "vital-app-launch-schema.json" to "VitalAppLaunchEvent", - "vital-operation-step-schema.json" to "VitalOperationStepEvent" + "vital-operation-step-schema.json" to "VitalOperationStepEvent", + "timeseries-memory-schema.json" to "TimeseriesMemoryEvent", + "timeseries-cpu-schema.json" to "TimeseriesCpuEvent" ) } diff --git a/features/dd-sdk-android-rum/src/main/json/rum/_common-schema.json b/features/dd-sdk-android-rum/src/main/json/rum/_common-schema.json index 991e883116..014d762542 100644 --- a/features/dd-sdk-android-rum/src/main/json/rum/_common-schema.json +++ b/features/dd-sdk-android-rum/src/main/json/rum/_common-schema.json @@ -4,7 +4,7 @@ "title": "CommonProperties", "type": "object", "description": "Schema of common properties of RUM events", - "required": ["date", "application", "session", "view", "_dd"], + "required": ["date", "application", "session", "_dd"], "properties": { "date": { "type": "integer", @@ -92,7 +92,7 @@ "unity", "kotlin-multiplatform", "electron", - "rum-cpp", + "cpp", "maui" ], "readOnly": true @@ -173,6 +173,20 @@ }, "readOnly": true }, + "tab": { + "type": "object", + "description": "Tab properties", + "required": ["id"], + "properties": { + "id": { + "type": "string", + "description": "UUID of the browser tab", + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", + "readOnly": true + } + }, + "readOnly": true + }, "connectivity": { "type": "object", "description": "Device connectivity properties", @@ -455,6 +469,14 @@ "minimum": 0, "maximum": 100, "readOnly": true + }, + "session_replay_experimental_features": { + "type": "array", + "description": "Session Replay experimental features enabled in the SDK configuration", + "items": { + "type": "string" + }, + "readOnly": true } } }, @@ -475,6 +497,19 @@ "type": "object", "description": "User provided context", "additionalProperties": true + }, + "stream": { + "type": "object", + "description": "Stream properties", + "required": ["id"], + "properties": { + "id": { + "type": "string", + "description": "UUID of the stream", + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", + "readOnly": true + } + } } } } diff --git a/features/dd-sdk-android-rum/src/main/json/rum/_view-container-schema.json b/features/dd-sdk-android-rum/src/main/json/rum/_view-container-schema.json index e22b81dcca..62942aa429 100644 --- a/features/dd-sdk-android-rum/src/main/json/rum/_view-container-schema.json +++ b/features/dd-sdk-android-rum/src/main/json/rum/_view-container-schema.json @@ -37,7 +37,7 @@ "unity", "kotlin-multiplatform", "electron", - "rum-cpp", + "cpp", "maui" ], "readOnly": true diff --git a/features/dd-sdk-android-rum/src/main/json/rum/timeseries-cpu-schema.json b/features/dd-sdk-android-rum/src/main/json/rum/timeseries-cpu-schema.json new file mode 100644 index 0000000000..9e77f8885c --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/json/rum/timeseries-cpu-schema.json @@ -0,0 +1,93 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "rum/timeseries-cpu-schema.json", + "title": "RumTimeseriesCpuEvent", + "type": "object", + "description": "Schema for a CPU timeseries event.", + "allOf": [ + { + "$ref": "_common-schema.json" + }, + { + "required": ["type", "timeseries"], + "properties": { + "type": { + "type": "string", + "description": "RUM event type", + "const": "timeseries", + "readOnly": true + }, + "timeseries": { + "type": "object", + "description": "CPU timeseries properties", + "required": ["id", "name", "schema", "start", "end", "data"], + "properties": { + "id": { + "type": "string", + "description": "UUID of the timeseries batch", + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", + "readOnly": true + }, + "name": { + "type": "string", + "description": "Name identifying the timeseries metric", + "const": "cpu", + "readOnly": true + }, + "schema": { + "type": "string", + "description": "Wire-shape discriminator for the data field", + "const": "object-v2", + "readOnly": true + }, + "start": { + "type": "integer", + "description": "Timestamp of the first sample in nanoseconds from epoch", + "readOnly": true + }, + "end": { + "type": "integer", + "description": "Timestamp of the last sample in nanoseconds from epoch", + "readOnly": true + }, + "data": { + "type": "object", + "description": "Flattened CPU data points", + "required": ["timestamps", "values"], + "properties": { + "timestamps": { + "type": "array", + "description": "Sample timestamps in nanoseconds from epoch", + "items": { + "type": "integer", + "readOnly": true + }, + "readOnly": true + }, + "values": { + "type": "object", + "description": "CPU measurements, aligned index-for-index with timestamps", + "required": ["cpu_usage"], + "properties": { + "cpu_usage": { + "type": "array", + "description": "CPU usage as a percentage (0.0 to 100.0)", + "items": { + "type": "number", + "readOnly": true + }, + "readOnly": true + } + }, + "readOnly": true + } + }, + "readOnly": true + } + }, + "readOnly": true + } + } + } + ] +} diff --git a/features/dd-sdk-android-rum/src/main/json/rum/timeseries-memory-schema.json b/features/dd-sdk-android-rum/src/main/json/rum/timeseries-memory-schema.json new file mode 100644 index 0000000000..122f58d670 --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/json/rum/timeseries-memory-schema.json @@ -0,0 +1,102 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "rum/timeseries-memory-schema.json", + "title": "RumTimeseriesMemoryEvent", + "type": "object", + "description": "Schema for a memory timeseries event.", + "allOf": [ + { + "$ref": "_common-schema.json" + }, + { + "required": ["type", "timeseries"], + "properties": { + "type": { + "type": "string", + "description": "RUM event type", + "const": "timeseries", + "readOnly": true + }, + "timeseries": { + "type": "object", + "description": "Memory timeseries properties", + "required": ["id", "name", "schema", "start", "end", "data"], + "properties": { + "id": { + "type": "string", + "description": "UUID of the timeseries batch", + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", + "readOnly": true + }, + "name": { + "type": "string", + "description": "Name identifying the timeseries metric", + "const": "memory", + "readOnly": true + }, + "schema": { + "type": "string", + "description": "Wire-shape discriminator for the data field", + "const": "object-v2", + "readOnly": true + }, + "start": { + "type": "integer", + "description": "Timestamp of the first sample in nanoseconds from epoch", + "readOnly": true + }, + "end": { + "type": "integer", + "description": "Timestamp of the last sample in nanoseconds from epoch", + "readOnly": true + }, + "data": { + "type": "object", + "description": "Flattened memory data points", + "required": ["timestamps", "values"], + "properties": { + "timestamps": { + "type": "array", + "description": "Sample timestamps in nanoseconds from epoch", + "items": { + "type": "integer", + "readOnly": true + }, + "readOnly": true + }, + "values": { + "type": "object", + "description": "Memory measurements, aligned index-for-index with timestamps", + "required": ["memory_footprint", "memory_percent"], + "properties": { + "memory_footprint": { + "type": "array", + "description": "Physical memory footprint of the process in kilobytes", + "items": { + "type": "number", + "readOnly": true + }, + "readOnly": true + }, + "memory_percent": { + "type": "array", + "description": "Memory footprint as a percentage of total device RAM", + "items": { + "type": "number", + "readOnly": true + }, + "readOnly": true + } + }, + "readOnly": true + } + }, + "readOnly": true + } + }, + "readOnly": true + } + } + } + ] +} diff --git a/features/dd-sdk-android-rum/src/main/json/telemetry/usage/mobile-features-schema.json b/features/dd-sdk-android-rum/src/main/json/telemetry/usage/mobile-features-schema.json index 815f714977..b2ffd57832 100644 --- a/features/dd-sdk-android-rum/src/main/json/telemetry/usage/mobile-features-schema.json +++ b/features/dd-sdk-android-rum/src/main/json/telemetry/usage/mobile-features-schema.json @@ -39,6 +39,17 @@ } } }, + { + "required": ["feature"], + "title": "Timeseries", + "properties": { + "feature": { + "type": "string", + "description": "Timeseries tracking enabled", + "const": "timeseries" + } + } + }, { "required": ["feature", "type"], "title": "AndroidNetworkInstrumentation", diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/Rum.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/Rum.kt index b155c5aec5..7fcf71aea6 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/Rum.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/Rum.kt @@ -18,8 +18,10 @@ import com.datadog.android.core.InternalSdkCore import com.datadog.android.core.sampling.DeterministicSampler import com.datadog.android.core.sampling.RateBasedSampler import com.datadog.android.internal.sampling.SessionSamplingIdProvider +import com.datadog.android.internal.telemetry.InternalTelemetryEvent import com.datadog.android.rum.internal.RumAnonymousIdentifierManager import com.datadog.android.rum.internal.RumFeature +import com.datadog.android.rum.internal.RumFeature.Configuration import com.datadog.android.rum.internal.domain.scope.RumVitalAppLaunchEventHelper import com.datadog.android.rum.internal.metric.SessionEndedMetricDispatcher import com.datadog.android.rum.internal.monitor.DatadogRumMonitor @@ -106,6 +108,12 @@ object Rum { // and before it is registered, but with current code (internal RUM scopes using the // `GlobalRumMonitor`) it is impossible to break cycle dependency. rumMonitor.start() + + // Reported here and not in RumFeature.onInitialize: telemetry events are dropped while the + // global RUM monitor is not registered yet (see RumFeature.handleTelemetryEvent). + if (rumConfiguration.featureConfiguration.isTimeseriesConfigured()) { + sdkCore.internalLogger.logApiUsage { InternalTelemetryEvent.ApiUsage.Timeseries() } + } } // region private @@ -142,14 +150,7 @@ object Rum { sessionSampler = sessionSampler, writer = rumFeature.dataWriter, handler = Handler(Looper.getMainLooper()), - telemetryEventHandler = TelemetryEventHandler( - sdkCore = sdkCore, - eventSampler = RateBasedSampler(rumFeature.telemetrySampleRate), - sessionEndedMetricDispatcher = sessionEndedMetricDispatcher, - configurationExtraSampler = RateBasedSampler( - rumFeature.telemetryConfigurationSampleRate - ) - ), + telemetryEventHandler = createTelemetryEventHandler(sdkCore, rumFeature, sessionEndedMetricDispatcher), firstPartyHostHeaderTypeResolver = sdkCore.firstPartyHostResolver, cpuVitalMonitor = rumFeature.cpuVitalMonitor, memoryVitalMonitor = rumFeature.memoryVitalMonitor, @@ -173,10 +174,24 @@ object Rum { ) }, insightsCollector = rumFeature.insightsCollector, - heatmapIdentifierRegistry = rumFeature.heatmapIdentifierRegistry + heatmapIdentifierRegistry = rumFeature.heatmapIdentifierRegistry, + timeseriesCollectorFactory = rumFeature.timeseriesCollectorFactory ) } + private fun createTelemetryEventHandler( + sdkCore: InternalSdkCore, + rumFeature: RumFeature, + sessionEndedMetricDispatcher: SessionEndedMetricDispatcher + ) = TelemetryEventHandler( + sdkCore = sdkCore, + eventSampler = RateBasedSampler(rumFeature.telemetrySampleRate), + sessionEndedMetricDispatcher = sessionEndedMetricDispatcher, + configurationExtraSampler = RateBasedSampler( + rumFeature.telemetryConfigurationSampleRate + ) + ) + // endregion // region Constants @@ -191,5 +206,9 @@ object Rum { internal const val RUM_FEATURE_ALREADY_ENABLED = "RUM Feature is already enabled in this SDK core, ignoring the call to enable it." + private fun Configuration.isTimeseriesConfigured(): Boolean { + return timeseriesConfiguration?.enabledTypes?.isNotEmpty() == true + } + // endregion } diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/RumConfiguration.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/RumConfiguration.kt index 7677258b68..6049fcaff7 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/RumConfiguration.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/RumConfiguration.kt @@ -28,6 +28,7 @@ import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent import com.datadog.android.rum.startup.AppStartupActivityPredicate +import com.datadog.android.rum.timeseries.TimeseriesConfiguration import com.datadog.android.rum.tracking.ActionTrackingStrategy import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy import com.datadog.android.rum.tracking.InteractionPredicate @@ -410,6 +411,22 @@ data class RumConfiguration internal constructor( return this } + /** + * Enables device timeseries collection. + * + * By default, all supported timeseries types are collected. Use + * [TimeseriesConfiguration.Builder.collectOnly] to restrict collection to specific types. + * + * @param configuration configuration for timeseries collection. + */ + @ExperimentalRumApi + fun setTimeseriesConfiguration( + configuration: TimeseriesConfiguration + ): Builder { + rumConfig = rumConfig.copy(timeseriesConfiguration = configuration) + return this + } + /** * Builds a [RumConfiguration] based on the current state of this Builder. */ diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt index 35f39977e2..28edfb59b3 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt @@ -91,12 +91,16 @@ import com.datadog.android.rum.internal.startup.RumAppStartupDetector import com.datadog.android.rum.internal.startup.RumStartupScenario import com.datadog.android.rum.internal.startup.RumTTIDInfo import com.datadog.android.rum.internal.thread.NoOpScheduledExecutorService +import com.datadog.android.rum.internal.timeseries.DefaultTimeseriesCollectorFactory +import com.datadog.android.rum.internal.timeseries.NoOpTimeseriesCollectorFactory +import com.datadog.android.rum.internal.timeseries.TimeseriesCollector import com.datadog.android.rum.internal.tracking.JetpackViewAttributesProvider import com.datadog.android.rum.internal.tracking.NoOpInteractionPredicate import com.datadog.android.rum.internal.tracking.NoOpUserActionTrackingStrategy import com.datadog.android.rum.internal.tracking.UserActionTrackingStrategy import com.datadog.android.rum.internal.vitals.AggregatingVitalMonitor import com.datadog.android.rum.internal.vitals.CPUVitalReader +import com.datadog.android.rum.internal.vitals.CpuStatReader import com.datadog.android.rum.internal.vitals.FPSVitalListener import com.datadog.android.rum.internal.vitals.FrameStateListener import com.datadog.android.rum.internal.vitals.FrameStatesAggregator @@ -120,6 +124,7 @@ import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent import com.datadog.android.rum.startup.AppStartupActivityPredicate +import com.datadog.android.rum.timeseries.TimeseriesConfiguration import com.datadog.android.rum.tracking.ActionTrackingStrategy import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy import com.datadog.android.rum.tracking.InteractionPredicate @@ -189,6 +194,7 @@ internal class RumFeature( internal val rumContextUpdateReceivers = mutableSetOf() internal var insightsCollector: InsightsCollector = NoOpInsightsCollector() override val heatmapIdentifierRegistry: HeatmapIdentifierRegistry = HeatmapIdentifierRegistry.create() + internal var timeseriesCollectorFactory: TimeseriesCollector.Factory = NoOpTimeseriesCollectorFactory() private val lateCrashEventHandler by lazy { lateCrashReporterFactory(sdkCore as InternalSdkCore) } internal var rumAppStartupDetector: RumAppStartupDetector? = null @@ -259,20 +265,27 @@ internal class RumFeature( configuration.longTaskTrackingStrategy?.let { longTaskTrackingStrategy = it } val frequency = configuration.vitalsMonitorUpdateFrequency - val slowFrameListenerConfiguration = configuration.slowFramesConfiguration - if (frequency != VitalsUpdateFrequency.NEVER || slowFrameListenerConfiguration != null) { - initializeVitalExecutorService(frequency) + val vitalsUpdatesRequired = frequency != VitalsUpdateFrequency.NEVER + + // The vital executor backs both the CPU/memory vital monitors and timeseries sampling. + if (vitalsUpdatesRequired || configuration.timeseriesConfiguration != null) initializeVitalExecutorService() + + if (vitalsUpdatesRequired) { + // CPU/memory monitors schedule on the vital executor, so they are only set up when vitals + // are enabled - the same condition that creates the executor above. initializeCpuVitalMonitor(frequency) initializeMemoryVitalMonitor(frequency) - if (!configuration.disableJankStats) { - initializeFrameStatesAggregator( - application = appContext as? Application, - listeners = listOfNotNull( - initializeSlowFrameListener(slowFrameListenerConfiguration), - initializeFPSVitalMonitor(frequency) - ) - ) - } + } + + val fpsVitalMonitor = initializeFPSVitalMonitor(frequency) + val slowFrameListener = initializeSlowFrameListener(configuration.slowFramesConfiguration) + if (fpsVitalMonitor != null || slowFrameListener != null) { + // The aggregator feeds two Choreographer-based listeners (no executor needed): the + // FPS frame-rate vital - gated on the vitals frequency, hence vitalsUpdatesRequired - and + // the slow-frames listener, gated on its own config. + (appContext as? Application)?.initializeFrameStatesAggregator( + listOfNotNull(slowFrameListener, fpsVitalMonitor) + ) } if (configuration.trackNonFatalAnrs) { @@ -283,6 +296,19 @@ internal class RumFeature( sessionListener = configuration.sessionListener + configuration.timeseriesConfiguration?.let { timeseriesConfiguration -> + timeseriesCollectorFactory = DefaultTimeseriesCollectorFactory( + sdkCore = sdkCore, + dataWriter = dataWriter, + insightsCollector = insightsCollector, + configuration = timeseriesConfiguration, + scheduledExecutorService = vitalExecutorService, + totalRamBytes = appContext.readTotalRamBytes(sdkCore.internalLogger) ?: 0L, + batteryInfoProvider = batteryInfoProvider, + displayInfoProvider = displayInfoProvider + ) + } + initRumAppStartupDetector() sdkCore.setEventReceiver(name, this) @@ -290,13 +316,13 @@ internal class RumFeature( initialized.set(true) } - private fun initializeFrameStatesAggregator(application: Application?, listeners: List) { + private fun Application.initializeFrameStatesAggregator(listeners: List) { frameStatesAggregator = FrameStatesAggregator(listeners, sdkCore.internalLogger) - application?.registerActivityLifecycleCallbacks(frameStatesAggregator) + registerActivityLifecycleCallbacks(frameStatesAggregator) } private fun initializeSlowFrameListener(slowFramesConfiguration: SlowFramesConfiguration?): FrameStateListener? { - slowFramesListener = if (slowFramesConfiguration != null) { + slowFramesListener = if (slowFramesConfiguration != null && !configuration.disableJankStats) { sdkCore.internalLogger.log( InternalLogger.Level.INFO, InternalLogger.Target.USER, @@ -348,6 +374,9 @@ internal class RumFeature( unregisterTrackingStrategies(appContext) + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() + (GlobalRumMonitor.get(sdkCore) as? DatadogRumMonitor)?.stopTimeseries() + dataWriter = NoOpDataWriter() viewTrackingStrategy = NoOpViewTrackingStrategy() @@ -604,10 +633,7 @@ internal class RumFeature( longTaskTrackingStrategy.unregister(appContext) } - private fun initializeVitalExecutorService(frequency: VitalsUpdateFrequency) { - if (frequency == VitalsUpdateFrequency.NEVER) { - return - } + private fun initializeVitalExecutorService() { @Suppress("UnsafeThirdPartyFunctionCall") // pool size can't be <= 0 vitalExecutorService = sdkCore.createScheduledExecutorService("rum-vital") } @@ -617,7 +643,7 @@ internal class RumFeature( cpuVitalMonitor = AggregatingVitalMonitor() initializeVitalMonitor( - CPUVitalReader(internalLogger = sdkCore.internalLogger), + CPUVitalReader(CpuStatReader(internalLogger = sdkCore.internalLogger)), cpuVitalMonitor, frequency.periodInMs ) @@ -635,7 +661,7 @@ internal class RumFeature( } private fun initializeFPSVitalMonitor(frequency: VitalsUpdateFrequency): FPSVitalListener? { - if (frequency == VitalsUpdateFrequency.NEVER) return null + if (frequency == VitalsUpdateFrequency.NEVER || configuration.disableJankStats) return null frameRateVitalMonitor = AggregatingVitalMonitor() return FPSVitalListener(frameRateVitalMonitor) @@ -802,7 +828,8 @@ internal class RumFeature( val collectAccessibility: Boolean, val disableJankStats: Boolean, val insightsCollector: InsightsCollector, - val appStartupActivityPredicate: AppStartupActivityPredicate + val appStartupActivityPredicate: AppStartupActivityPredicate, + val timeseriesConfiguration: TimeseriesConfiguration? ) internal companion object { @@ -856,7 +883,8 @@ internal class RumFeature( collectAccessibility = false, disableJankStats = false, insightsCollector = NoOpInsightsCollector(), - appStartupActivityPredicate = DefaultAppStartupActivityPredicate + appStartupActivityPredicate = DefaultAppStartupActivityPredicate, + timeseriesConfiguration = null ) internal const val EVENT_MESSAGE_PROPERTY = "message" @@ -890,6 +918,24 @@ internal class RumFeature( internal const val FAILED_TO_ENABLE_JANK_STATS_TRACKING_MANUALLY = "Manually enabling JankStats tracking threw an exception." + internal fun Context.readTotalRamBytes(internalLogger: InternalLogger): Long? = try { + getSystemServiceAs(Context.ACTIVITY_SERVICE) + ?.run { + // UnsafeThirdPartyFunctionCall: MemoryInfo() and getMemoryInfo() can throw + // RuntimeException on broken Android implementations; fall back to 0. + @Suppress("UnsafeThirdPartyFunctionCall") + ActivityManager.MemoryInfo().also { getMemoryInfo(it) }.totalMem + } + } catch (@Suppress("TooGenericExceptionCaught") e: RuntimeException) { + internalLogger.log( + InternalLogger.Level.WARN, + InternalLogger.Target.MAINTAINER, + { "Failed to read total RAM via ActivityManager" }, + e + ) + null + } + private fun provideUserTrackingStrategy( touchTargetExtraAttributesProviders: Array, interactionPredicate: InteractionPredicate, diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumSessionTypeExt.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumSessionTypeExt.kt index e2b12f316d..ff9ee46572 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumSessionTypeExt.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumSessionTypeExt.kt @@ -11,6 +11,8 @@ import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent.TimeseriesCpuEventSessionType +import com.datadog.android.rum.model.TimeseriesMemoryEvent.TimeseriesMemoryEventSessionType import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent @@ -49,6 +51,7 @@ internal fun RumSessionType.toLongTask(): LongTaskEvent.LongTaskEventSessionType RumSessionType.USER -> LongTaskEvent.LongTaskEventSessionType.USER } } + internal fun RumSessionType.toVital(): VitalOperationStepEvent.VitalOperationStepEventSessionType { return when (this) { RumSessionType.SYNTHETICS -> VitalOperationStepEvent.VitalOperationStepEventSessionType.SYNTHETICS @@ -62,3 +65,13 @@ internal fun RumSessionType.toVitalAppLaunch(): VitalAppLaunchEvent.VitalAppLaun RumSessionType.USER -> VitalAppLaunchEvent.VitalAppLaunchEventSessionType.USER } } + +internal fun RumSessionType.toTimeseriesMemorySessionType(): TimeseriesMemoryEventSessionType = when (this) { + RumSessionType.SYNTHETICS -> TimeseriesMemoryEventSessionType.SYNTHETICS + RumSessionType.USER -> TimeseriesMemoryEventSessionType.USER +} + +internal fun RumSessionType.toTimeseriesCpuSessionType(): TimeseriesCpuEventSessionType = when (this) { + RumSessionType.SYNTHETICS -> TimeseriesCpuEventSessionType.SYNTHETICS + RumSessionType.USER -> TimeseriesCpuEventSessionType.USER +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/RumDataWriter.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/RumDataWriter.kt index b70f0dddd3..4e1a75c247 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/RumDataWriter.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/RumDataWriter.kt @@ -22,6 +22,8 @@ import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent @@ -130,6 +132,8 @@ internal class RumDataWriter( is TelemetryDebugEvent -> event.type is TelemetryErrorEvent -> event.type is TelemetryUsageEvent -> event.type + is TimeseriesCpuEvent -> event.type + is TimeseriesMemoryEvent -> event.type else -> UNKNOWN_EVENT_TYPE } } diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapper.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapper.kt index e932bea14a..c11ccfcb3d 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapper.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapper.kt @@ -13,6 +13,8 @@ import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent @@ -67,6 +69,8 @@ internal data class RumEventMapper( is VitalOperationStepEvent -> vitalOperationStepEventMapper.map(event) is VitalAppLaunchEvent -> vitalAppLaunchEventMapper.map(event) is TelemetryConfigurationEvent -> telemetryConfigurationMapper.map(event) + is TimeseriesCpuEvent, + is TimeseriesMemoryEvent, is TelemetryDebugEvent, is TelemetryUsageEvent, is TelemetryErrorEvent -> event diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventSerializer.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventSerializer.kt index ea867f6cc9..96915488be 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventSerializer.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventSerializer.kt @@ -16,6 +16,8 @@ import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent @@ -68,6 +70,12 @@ internal class RumEventSerializer( is TelemetryUsageEvent -> { model.toJson().toString() } + is TimeseriesCpuEvent -> { + model.toJson().toString() + } + is TimeseriesMemoryEvent -> { + model.toJson().toString() + } is JsonObject -> { model.toString() } diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScope.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScope.kt index 768515481b..07aba22a7d 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScope.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScope.kt @@ -30,6 +30,7 @@ import com.datadog.android.rum.internal.instrumentation.insights.InsightsCollect import com.datadog.android.rum.internal.metric.SessionMetricDispatcher import com.datadog.android.rum.internal.metric.slowframes.SlowFramesListener import com.datadog.android.rum.internal.startup.RumSessionScopeStartupManager +import com.datadog.android.rum.internal.timeseries.TimeseriesCollector import com.datadog.android.rum.internal.vitals.VitalMonitor import com.datadog.android.rum.metric.interactiontonextview.LastInteractionIdentifier import com.datadog.android.rum.metric.networksettled.InitialResourceIdentifier @@ -57,7 +58,8 @@ internal class RumApplicationScope( private val displayInfoProvider: InfoProvider, private val rumSessionScopeStartupManagerFactory: () -> RumSessionScopeStartupManager, private val insightsCollector: InsightsCollector, - private val heatmapIdentifierRegistry: HeatmapIdentifierRegistry? + private val heatmapIdentifierRegistry: HeatmapIdentifierRegistry?, + private val timeseriesCollectorFactory: TimeseriesCollector.Factory ) : RumScope, RumViewChangedListener { override val parentScope: RumScope? = null @@ -88,7 +90,8 @@ internal class RumApplicationScope( displayInfoProvider = displayInfoProvider, rumSessionScopeStartupManagerFactory = rumSessionScopeStartupManagerFactory, insightsCollector = insightsCollector, - heatmapIdentifierRegistry = heatmapIdentifierRegistry + heatmapIdentifierRegistry = heatmapIdentifierRegistry, + timeseriesCollectorFactory = timeseriesCollectorFactory ) ) @@ -211,7 +214,8 @@ internal class RumApplicationScope( displayInfoProvider = displayInfoProvider, rumSessionScopeStartupManagerFactory = rumSessionScopeStartupManagerFactory, insightsCollector = insightsCollector, - heatmapIdentifierRegistry = heatmapIdentifierRegistry + heatmapIdentifierRegistry = heatmapIdentifierRegistry, + timeseriesCollectorFactory = timeseriesCollectorFactory ) childScopes.add(newSession) if (event !is RumRawEvent.StartView) { diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExt.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExt.kt index d92742407e..25f3bea919 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExt.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExt.kt @@ -8,19 +8,26 @@ package com.datadog.android.rum.internal.domain.scope import com.datadog.android.api.InternalLogger +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.api.context.DeviceInfo import com.datadog.android.api.context.DeviceType import com.datadog.android.api.context.NetworkInfo +import com.datadog.android.api.feature.Feature import com.datadog.android.rum.RumActionType import com.datadog.android.rum.RumErrorSource import com.datadog.android.rum.RumResourceKind import com.datadog.android.rum.RumResourceMethod import com.datadog.android.rum.internal.RumErrorSourceType +import com.datadog.android.rum.internal.domain.battery.BatteryInfo +import com.datadog.android.rum.internal.domain.display.DisplayInfo import com.datadog.android.rum.internal.domain.event.ResourceTiming import com.datadog.android.rum.internal.startup.RumStartupScenario import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent @@ -518,6 +525,94 @@ internal fun DeviceType.toVitalAppLaunchSchemaType(): VitalAppLaunchEvent.Device } } +internal fun DeviceType.toTimeseriesCpuSchemaType(): TimeseriesCpuEvent.DeviceType { + return when (this) { + DeviceType.MOBILE -> TimeseriesCpuEvent.DeviceType.MOBILE + DeviceType.TABLET -> TimeseriesCpuEvent.DeviceType.TABLET + DeviceType.TV -> TimeseriesCpuEvent.DeviceType.TV + DeviceType.DESKTOP -> TimeseriesCpuEvent.DeviceType.DESKTOP + DeviceType.GAMING_CONSOLE -> TimeseriesCpuEvent.DeviceType.GAMING_CONSOLE + DeviceType.BOT -> TimeseriesCpuEvent.DeviceType.BOT + DeviceType.OTHER -> TimeseriesCpuEvent.DeviceType.OTHER + } +} + +internal fun DeviceType.toTimeseriesMemorySchemaType(): TimeseriesMemoryEvent.DeviceType { + return when (this) { + DeviceType.MOBILE -> TimeseriesMemoryEvent.DeviceType.MOBILE + DeviceType.TABLET -> TimeseriesMemoryEvent.DeviceType.TABLET + DeviceType.TV -> TimeseriesMemoryEvent.DeviceType.TV + DeviceType.DESKTOP -> TimeseriesMemoryEvent.DeviceType.DESKTOP + DeviceType.GAMING_CONSOLE -> TimeseriesMemoryEvent.DeviceType.GAMING_CONSOLE + DeviceType.BOT -> TimeseriesMemoryEvent.DeviceType.BOT + DeviceType.OTHER -> TimeseriesMemoryEvent.DeviceType.OTHER + } +} + +internal fun DeviceInfo.toTimeseriesCpuDevice( + batteryInfo: BatteryInfo, + displayInfo: DisplayInfo +) = TimeseriesCpuEvent.Device( + type = deviceType.toTimeseriesCpuSchemaType(), + name = deviceName, + model = deviceModel, + brand = deviceBrand, + architecture = architecture, + locales = localeInfo.locales, + timeZone = localeInfo.timeZone, + batteryLevel = batteryInfo.batteryLevel, + powerSavingMode = batteryInfo.lowPowerMode, + brightnessLevel = displayInfo.screenBrightness, + logicalCpuCount = logicalCpuCount, + totalRam = totalRam, + isLowRam = isLowRam +) + +internal fun DeviceInfo.toTimeseriesMemoryDevice( + batteryInfo: BatteryInfo, + displayInfo: DisplayInfo +) = TimeseriesMemoryEvent.Device( + type = deviceType.toTimeseriesMemorySchemaType(), + name = deviceName, + model = deviceModel, + brand = deviceBrand, + architecture = architecture, + locales = localeInfo.locales, + timeZone = localeInfo.timeZone, + batteryLevel = batteryInfo.batteryLevel, + powerSavingMode = batteryInfo.lowPowerMode, + brightnessLevel = displayInfo.screenBrightness, + logicalCpuCount = logicalCpuCount, + totalRam = totalRam, + isLowRam = isLowRam +) + +internal fun DeviceInfo.toTimeseriesCpuOs() = TimeseriesCpuEvent.Os( + name = osName, + version = osVersion, + versionMajor = osMajorVersion +) + +internal fun DeviceInfo.toTimeseriesMemoryOs() = TimeseriesMemoryEvent.Os( + name = osName, + version = osVersion, + versionMajor = osMajorVersion +) + +// endregion + +// region Feature context sample rates + +internal fun DatadogContext.resolveSessionReplaySampleRate(): Long? { + val srContext = featuresContext[Feature.SESSION_REPLAY_FEATURE_NAME] + return srContext?.get(RumViewScope.SESSION_REPLAY_SAMPLE_RATE_KEY) as? Long +} + +internal fun DatadogContext.resolveTraceSampleRate(): Float? { + val tracingContext = featuresContext[Feature.TRACING_FEATURE_NAME] + return tracingContext?.get(RumViewScope.TRACE_SAMPLE_RATE) as? Float +} + // endregion // region Source @@ -641,6 +736,40 @@ internal fun VitalAppLaunchEvent.VitalAppLaunchEventSource.Companion.tryFromSour } } +internal fun TimeseriesCpuEvent.Source.Companion.tryFromSource( + source: String, + internalLogger: InternalLogger +): TimeseriesCpuEvent.Source? { + return try { + fromJson(source) + } catch (e: NoSuchElementException) { + internalLogger.log( + InternalLogger.Level.ERROR, + InternalLogger.Target.USER, + { UNKNOWN_SOURCE_WARNING_MESSAGE_FORMAT.format(Locale.US, source) }, + e + ) + null + } +} + +internal fun TimeseriesMemoryEvent.Source.Companion.tryFromSource( + source: String, + internalLogger: InternalLogger +): TimeseriesMemoryEvent.Source? { + return try { + fromJson(source) + } catch (e: NoSuchElementException) { + internalLogger.log( + InternalLogger.Level.ERROR, + InternalLogger.Target.USER, + { UNKNOWN_SOURCE_WARNING_MESSAGE_FORMAT.format(Locale.US, source) }, + e + ) + null + } +} + internal const val UNKNOWN_SOURCE_WARNING_MESSAGE_FORMAT = "You are using an unknown " + "source %s for your events" @@ -713,6 +842,33 @@ internal fun RumSessionScope.StartReason.toLongTaskSessionPrecondition(): LongTa } } +internal fun RumSessionScope.StartReason.toTimeseriesCpuSessionPrecondition(): TimeseriesCpuEvent.SessionPrecondition { + return when (this) { + RumSessionScope.StartReason.USER_APP_LAUNCH -> TimeseriesCpuEvent.SessionPrecondition.USER_APP_LAUNCH + RumSessionScope.StartReason.INACTIVITY_TIMEOUT -> TimeseriesCpuEvent.SessionPrecondition.INACTIVITY_TIMEOUT + RumSessionScope.StartReason.MAX_DURATION -> TimeseriesCpuEvent.SessionPrecondition.MAX_DURATION + RumSessionScope.StartReason.EXPLICIT_STOP -> TimeseriesCpuEvent.SessionPrecondition.EXPLICIT_STOP + RumSessionScope.StartReason.BACKGROUND_LAUNCH -> TimeseriesCpuEvent.SessionPrecondition.BACKGROUND_LAUNCH + RumSessionScope.StartReason.PREWARM -> TimeseriesCpuEvent.SessionPrecondition.PREWARM + RumSessionScope.StartReason.FROM_NON_INTERACTIVE_SESSION -> + TimeseriesCpuEvent.SessionPrecondition.FROM_NON_INTERACTIVE_SESSION + } +} + +internal fun RumSessionScope.StartReason.toTimeseriesMemorySessionPrecondition(): + TimeseriesMemoryEvent.SessionPrecondition { + return when (this) { + RumSessionScope.StartReason.USER_APP_LAUNCH -> TimeseriesMemoryEvent.SessionPrecondition.USER_APP_LAUNCH + RumSessionScope.StartReason.INACTIVITY_TIMEOUT -> TimeseriesMemoryEvent.SessionPrecondition.INACTIVITY_TIMEOUT + RumSessionScope.StartReason.MAX_DURATION -> TimeseriesMemoryEvent.SessionPrecondition.MAX_DURATION + RumSessionScope.StartReason.EXPLICIT_STOP -> TimeseriesMemoryEvent.SessionPrecondition.EXPLICIT_STOP + RumSessionScope.StartReason.BACKGROUND_LAUNCH -> TimeseriesMemoryEvent.SessionPrecondition.BACKGROUND_LAUNCH + RumSessionScope.StartReason.PREWARM -> TimeseriesMemoryEvent.SessionPrecondition.PREWARM + RumSessionScope.StartReason.FROM_NON_INTERACTIVE_SESSION -> + TimeseriesMemoryEvent.SessionPrecondition.FROM_NON_INTERACTIVE_SESSION + } +} + // endregion // region Operation diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScope.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScope.kt index 33f3984529..611dc3a859 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScope.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScope.kt @@ -28,6 +28,9 @@ import com.datadog.android.rum.internal.instrumentation.insights.InsightsCollect import com.datadog.android.rum.internal.metric.SessionMetricDispatcher import com.datadog.android.rum.internal.metric.slowframes.SlowFramesListener import com.datadog.android.rum.internal.startup.RumSessionScopeStartupManager +import com.datadog.android.rum.internal.timeseries.NoOpTimeseriesCollector +import com.datadog.android.rum.internal.timeseries.NoOpTimeseriesCollectorFactory +import com.datadog.android.rum.internal.timeseries.TimeseriesCollector import com.datadog.android.rum.internal.vitals.VitalMonitor import com.datadog.android.rum.metric.interactiontonextview.LastInteractionIdentifier import com.datadog.android.rum.metric.networksettled.InitialResourceIdentifier @@ -58,12 +61,15 @@ internal class RumSessionScope( displayInfoProvider: InfoProvider, private val sessionInactivityNanos: Long = DEFAULT_SESSION_INACTIVITY_NS, private val sessionMaxDurationNanos: Long = DEFAULT_SESSION_MAX_DURATION_NS, - rumSessionTypeOverride: RumSessionType?, + private val rumSessionTypeOverride: RumSessionType?, private val rumSessionScopeStartupManagerFactory: () -> RumSessionScopeStartupManager, insightsCollector: InsightsCollector, - heatmapIdentifierRegistry: HeatmapIdentifierRegistry? + heatmapIdentifierRegistry: HeatmapIdentifierRegistry?, + private val timeseriesCollectorFactory: TimeseriesCollector.Factory = NoOpTimeseriesCollectorFactory() ) : RumScope { + private var timeseriesCollector: TimeseriesCollector = NoOpTimeseriesCollector() + internal var sessionId = RumContext.NULL_UUID internal var sessionState: State = State.NOT_TRACKED internal val sessionSampleRate: Float = sessionSampler.getSampleRate() ?: RumContext.SAMPLE_ALL_RATE @@ -157,7 +163,7 @@ internal class RumSessionScope( val actualWriter = if (sessionState == State.TRACKED) writer else noOpWriter - val rumContext = activeView?.getRumContext() ?: getRumContext() + val rumContext = getActiveRumContext() when (event) { is RumRawEvent.AppStartTTIDEvent -> { @@ -195,6 +201,12 @@ internal class RumSessionScope( } } + // getActiveRumContext() copies the whole context chain, so it is only built when there is a + // collector to feed: timeseries collection is opt-in and this runs on every RUM event. + if (timeseriesCollector !is NoOpTimeseriesCollector) { + timeseriesCollector.onRumContextUpdate(getActiveRumContext()) + } + return if (isSessionComplete()) { null } else { @@ -221,8 +233,27 @@ internal class RumSessionScope( // region Internal + private fun getActiveRumContext(): RumContext { + return activeView?.getRumContext() ?: getRumContext() + } + + private fun startTimeseries() { + val rumContext = getActiveRumContext() + timeseriesCollector = timeseriesCollectorFactory.create( + rumContext = rumContext, + sessionType = rumContext.resolveSessionType(rumSessionTypeOverride) + ) + timeseriesCollector.onSessionStart() + } + + internal fun stopTimeseries() { + timeseriesCollector.onSessionStop() + timeseriesCollector = NoOpTimeseriesCollector() + } + private fun stopSession() { isActive = false + stopTimeseries() sessionEndedMetricDispatcher.onSessionStopped(sessionId) } @@ -270,6 +301,7 @@ internal class RumSessionScope( renewSession(event.eventTime, StartReason.BACKGROUND_LAUNCH) lastUserInteractionNs.set(nanoTime) } else { + stopTimeseries() sessionState = State.EXPIRED } } else if (isTimedOut) { @@ -280,6 +312,7 @@ internal class RumSessionScope( } private fun renewSession(time: Time, reason: StartReason) { + stopTimeseries() val newSessionId = UUID.randomUUID().toString() val keepSession = sessionSampler.sample(newSessionId) startReason = reason @@ -295,6 +328,7 @@ internal class RumSessionScope( ntpOffsetAtStartMs = sdkCore.time.serverTimeOffsetMs, backgroundEventTracking = backgroundTrackingEnabled ) + startTimeseries() } sessionListener?.onSessionStarted(sessionId, !keepSession) } @@ -326,5 +360,13 @@ internal class RumSessionScope( internal const val RUM_SESSION_SAMPLE_RATE_BUS_MESSAGE_KEY = "sessionSampleRate" internal val DEFAULT_SESSION_INACTIVITY_NS = TimeUnit.MINUTES.toNanos(15) internal val DEFAULT_SESSION_MAX_DURATION_NS = TimeUnit.HOURS.toNanos(4) + + internal fun RumContext.resolveSessionType(rumSessionTypeOverride: RumSessionType?): RumSessionType { + return when { + rumSessionTypeOverride != null -> rumSessionTypeOverride + !syntheticsTestId.isNullOrBlank() && !syntheticsResultId.isNullOrBlank() -> RumSessionType.SYNTHETICS + else -> RumSessionType.USER + } + } } } diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt index 39540ba7ef..ab07c34939 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt @@ -1448,8 +1448,8 @@ internal open class RumViewScope( replayStats = replayStats, configuration = ViewEvent.Configuration( sessionSampleRate = sampleRate, - sessionReplaySampleRate = resolveSessionReplaySampleRate(datadogContext), - traceSampleRate = resolveTraceSampleRate(datadogContext) + sessionReplaySampleRate = datadogContext.resolveSessionReplaySampleRate(), + traceSampleRate = datadogContext.resolveTraceSampleRate() ), profiling = resolveViewProfilingStatus(datadogContext) ), @@ -1735,16 +1735,6 @@ internal open class RumViewScope( } } - private fun resolveSessionReplaySampleRate(datadogContext: DatadogContext): Long? { - val srContext = datadogContext.featuresContext[Feature.SESSION_REPLAY_FEATURE_NAME] - return srContext?.get(SESSION_REPLAY_SAMPLE_RATE_KEY) as? Long - } - - private fun resolveTraceSampleRate(datadogContext: DatadogContext): Float? { - val tracingContext = datadogContext.featuresContext[Feature.TRACING_FEATURE_NAME] - return tracingContext?.get(TRACE_SAMPLE_RATE) as? Float - } - private fun resolveErrorProfilingStatus(datadogContext: DatadogContext): ErrorEvent.Profiling? { val isRunning = datadogContext.isProfilerRunning() val quotaReason = datadogContext.resolveProfilingQuotaReason(sessionId) diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/instrumentation/insights/InsightsCollector.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/instrumentation/insights/InsightsCollector.kt index fc798e008a..cbca43fb03 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/instrumentation/insights/InsightsCollector.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/instrumentation/insights/InsightsCollector.kt @@ -97,6 +97,11 @@ interface InsightsCollector { */ fun onSlowFrameRate(rate: Double?) + /** + * Notifies the collector that a timeseries batch has been sent. + */ + fun onTimeseries(name: String) + /** * Binds this collector to the given [sdkCore] so it can subscribe to feature context updates. * Called once by the RUM feature during initialization. diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt index 28a9f1b0c1..0406ce5173 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt @@ -66,6 +66,7 @@ import com.datadog.android.rum.internal.metric.slowframes.SlowFramesListener import com.datadog.android.rum.internal.startup.RumSessionScopeStartupManager import com.datadog.android.rum.internal.startup.RumStartupScenario import com.datadog.android.rum.internal.startup.RumTTIDInfo +import com.datadog.android.rum.internal.timeseries.TimeseriesCollector import com.datadog.android.rum.internal.vitals.VitalMonitor import com.datadog.android.rum.metric.interactiontonextview.LastInteractionIdentifier import com.datadog.android.rum.metric.networksettled.InitialResourceIdentifier @@ -109,7 +110,8 @@ internal class DatadogRumMonitor( displayInfoProvider: InfoProvider, private val rumSessionScopeStartupManagerFactory: () -> RumSessionScopeStartupManager, insightsCollector: InsightsCollector, - heatmapIdentifierRegistry: HeatmapIdentifierRegistry? + heatmapIdentifierRegistry: HeatmapIdentifierRegistry?, + timeseriesCollectorFactory: TimeseriesCollector.Factory ) : RumMonitor, AdvancedRumMonitor { @Volatile private var cachedViewUrl: String? = null @@ -135,7 +137,8 @@ internal class DatadogRumMonitor( displayInfoProvider = displayInfoProvider, rumSessionScopeStartupManagerFactory = rumSessionScopeStartupManagerFactory, insightsCollector = insightsCollector, - heatmapIdentifierRegistry = heatmapIdentifierRegistry + heatmapIdentifierRegistry = heatmapIdentifierRegistry, + timeseriesCollectorFactory = timeseriesCollectorFactory ) internal var debugListener: RumDebugListener? = null @@ -917,6 +920,27 @@ internal class DatadogRumMonitor( } } + /** + * Stops the timeseries collector on the currently active session, if any. + * + * Must be called from [RumFeature.onStop] **before** [GlobalRumMonitor.unregister], so that + * the active session can stop sampling and flush buffered timeseries data while the monitor is + * still reachable. The shared RUM vitals executor is owned and shut down separately by + * [RumFeature.onStop]. + * + * Must be called **before** [RumFeature.dataWriter] is replaced with a + * [com.datadog.android.rum.internal.storage.NoOpDataWriter]. [EventWriter.write] captures the + * writer eagerly at call time, so the final flush issued inside [stop] will reach the real + * writer only if this ordering is maintained. Note: the flush is best-effort — if the core SDK + * de-initializes and shuts down its context executor before the async write task fires, the + * write is silently skipped regardless. + */ + internal fun stopTimeseries() { + synchronized(rootScope) { + rootScope.activeSession?.stopTimeseries() + } + } + internal fun handleEvent(event: RumRawEvent) { if (event is RumRawEvent.AddError && event.isFatal) { val handled = sdkCore.getFeature(Feature.RUM_FEATURE_NAME) diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/Buffer.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/Buffer.kt new file mode 100644 index 0000000000..5b7243d47a --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/Buffer.kt @@ -0,0 +1,16 @@ +/* + * 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.rum.internal.timeseries + +internal class Buffer(private val size: Int) { + private val items = ArrayList>(size) + + fun add(dataPoint: DataPoint) = items.add(dataPoint) + + fun isFull(): Boolean = items.size >= size + + fun drain() = items.toList().also { items.clear() } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/DataPoint.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/DataPoint.kt new file mode 100644 index 0000000000..1ef50c7836 --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/DataPoint.kt @@ -0,0 +1,9 @@ +/* + * 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.rum.internal.timeseries + +internal data class DataPoint(val timestampNs: Long, val value: T) diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollector.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollector.kt new file mode 100644 index 0000000000..03d342c99f --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollector.kt @@ -0,0 +1,194 @@ +/* + * 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.rum.internal.timeseries + +import androidx.annotation.WorkerThread +import com.datadog.android.api.InternalLogger +import com.datadog.android.core.internal.utils.scheduleSafe +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.domain.scope.RumViewType +import java.util.concurrent.ScheduledExecutorService +import java.util.concurrent.TimeUnit + +internal class DefaultTimeseriesCollector( + private val internalLogger: InternalLogger, + internal val pipelines: List>, + internal val scheduledExecutorService: ScheduledExecutorService, + @Volatile private var rumContext: RumContext +) : TimeseriesCollector { + private val state = State() + + // Batches are attributed to the view they are sent from, but a flush can happen once the app + // already left the foreground, where there is no view to attribute to. Keep the last foreground + // context so those batches stay attached to the view they were sent from. + @Volatile + private var lastForegroundRumContext: RumContext = rumContext + + // region PUBLIC API + @WorkerThread + override fun onSessionStart() { + state.setActive(isActive = rumContext.viewType.isForeground)?.let { generation -> scheduleSampling(generation) } + } + + @WorkerThread + override fun onSessionStop() { + if (state.setActive(false) != null) { + flushPipelines(lastForegroundRumContext) + } + } + + @WorkerThread + override fun onRumContextUpdate(newRumContext: RumContext) { + val oldViewType = rumContext.viewType + val newViewType = newRumContext.viewType + + val isEnterForeground = !oldViewType.isForeground && newViewType.isForeground + val isLeaveForeground = oldViewType.isForeground && !newViewType.isForeground + + rumContext = newRumContext + if (newViewType.isForeground) lastForegroundRumContext = newRumContext + + if (isLeaveForeground) { + scheduleStop(state.currentGeneration, lastForegroundRumContext) + } else if (isEnterForeground) { + scheduleSampling(generation = state.startGeneration()) + } + } + + // endregion + + //region SAMPLING + + private fun scheduleSampling(generation: Int) { + pipelines.forEach { pipeline -> scheduledExecutorService.schedulePipeline(pipeline, generation) } + } + + private fun ScheduledExecutorService.schedulePipeline( + pipeline: Pipeline<*>, + generation: Int + ) { + scheduleSafe( + TIMESERIES_OPERATION_NAME, + pipeline.intervalMs, + TimeUnit.MILLISECONDS, + internalLogger + ) { + if (!state.isGenerationActive(generation)) return@scheduleSafe + try { + val currentRumContext = rumContext + if (currentRumContext.viewType.isForeground) { + pipeline.execute(currentRumContext) + } + } catch (@Suppress("TooGenericExceptionCaught") t: Throwable) { + internalLogger.log( + level = InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + messageBuilder = { ERROR_SAMPLING_FAILED }, + throwable = t + ) + } finally { + if (state.isGenerationActive(generation)) schedulePipeline(pipeline, generation) + } + } + } + + @WorkerThread + private fun flushPipelines(rumContext: RumContext) { + pipelines.forEach { pipeline -> + try { + pipeline.flush(rumContext) + } catch (@Suppress("TooGenericExceptionCaught") t: Throwable) { + internalLogger.log( + level = InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + messageBuilder = { ERROR_FLUSH_FAILED }, + throwable = t + ) + } + } + } + + // endregion + + // region SUSPENSION + + private fun scheduleStop(stopRequestGeneration: Int, rumContextSnapshot: RumContext) { + scheduledExecutorService.scheduleSafe( + SUSPEND_OPERATION_NAME, + SUSPEND_DELAY_MS, + TimeUnit.MILLISECONDS, + internalLogger + ) { + if (!rumContext.viewType.isForeground && state.stopGeneration(stopRequestGeneration)) { + flushPipelines(rumContextSnapshot) + } + } + } + + // endregion + + internal companion object { + const val TIMESERIES_OPERATION_NAME = "Timeseries sampling" + const val SUSPEND_OPERATION_NAME = "Timeseries suspend" + const val ERROR_SAMPLING_FAILED = "Timeseries sampling iteration failed; rescheduling next sample." + const val ERROR_FLUSH_FAILED = "Timeseries flush failed." + + // Matches ActivityViewTrackingStrategy.STOP_VIEW_DELAY_MS, which guards the same race: + // an Activity-to-Activity transition leaves no active view for a moment when the tracking + // strategy stops the view on pause rather than on stop. + const val SUSPEND_DELAY_MS = 200L + + val RumViewType?.isForeground: Boolean + get() = when (this) { + RumViewType.FOREGROUND, RumViewType.APPLICATION_LAUNCH -> true + RumViewType.BACKGROUND -> false + RumViewType.NONE -> false + null -> false + } + + private class State { + // Written under the monitor only, but read outside of it, hence @Volatile: a stale + // generation would make the guards below reject a live sampling chain or flush. + @Volatile + var currentGeneration: Int = 0 + private set + + private var active: Boolean = false + + fun isGenerationActive(generation: Int): Boolean = synchronized(this) { + currentGeneration == generation && active + } + + /** + * Always starts a fresh generation, so that a suspension pending on the previous one + * can no longer stop the sampling chain. Returns the new generation. + */ + fun startGeneration(): Int = synchronized(this) { + active = true + ++currentGeneration + } + + /** + * Deactivates [generation] if it is still the current one. + * Returns true when this call is the one that deactivated it. + */ + fun stopGeneration(generation: Int): Boolean = synchronized(this) { + currentGeneration == generation && setActive(false) != null + } + + /** Returns the new generation if this call changed the state, null otherwise. */ + fun setActive(isActive: Boolean): Int? = synchronized(this) { + if (isActive == active) { + null + } else { + active = isActive + ++currentGeneration + } + } + } + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollectorFactory.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollectorFactory.kt new file mode 100644 index 0000000000..f474627d2c --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollectorFactory.kt @@ -0,0 +1,114 @@ +/* + * 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.rum.internal.timeseries + +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.feature.FeatureSdkCore +import com.datadog.android.api.storage.DataWriter +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.internal.domain.InfoProvider +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.domain.battery.BatteryInfo +import com.datadog.android.rum.internal.domain.display.DisplayInfo +import com.datadog.android.rum.internal.instrumentation.insights.InsightsCollector +import com.datadog.android.rum.internal.timeseries.factory.CpuEventFactory +import com.datadog.android.rum.internal.timeseries.factory.MemoryEventFactory +import com.datadog.android.rum.internal.timeseries.provider.CpuDatapointReader +import com.datadog.android.rum.internal.timeseries.provider.VitalReaderWrapper +import com.datadog.android.rum.internal.vitals.CpuStatReader +import com.datadog.android.rum.internal.vitals.MemoryVitalReader +import com.datadog.android.rum.timeseries.TimeseriesConfiguration +import com.datadog.android.rum.timeseries.TimeseriesType +import java.util.concurrent.ScheduledExecutorService + +@Suppress("LongParameterList") +internal class DefaultTimeseriesCollectorFactory( + private val sdkCore: FeatureSdkCore, + private val configuration: TimeseriesConfiguration, + private val scheduledExecutorService: ScheduledExecutorService, + private val insightsCollector: InsightsCollector, + private val totalRamBytes: Long, + private val dataWriter: DataWriter, + private val batteryInfoProvider: InfoProvider, + private val displayInfoProvider: InfoProvider +) : TimeseriesCollector.Factory { + + override fun create( + sessionType: RumSessionType, + rumContext: RumContext + ): TimeseriesCollector { + val pipelines = mutableListOf>() + + if (TimeseriesType.CPU in configuration.enabledTypes) { + pipelines += createCpuPipeline(sessionType) + } + + if (TimeseriesType.MEMORY in configuration.enabledTypes) { + if (totalRamBytes > 0L) { + pipelines += createMemoryPipeline(sessionType) + } else { + sdkCore.internalLogger.log( + InternalLogger.Level.WARN, + InternalLogger.Target.USER, + { MEMORY_TIMESERIES_DISABLED_MESSAGE }, + onlyOnce = true + ) + } + } + + return DefaultTimeseriesCollector( + internalLogger = sdkCore.internalLogger, + scheduledExecutorService = scheduledExecutorService, + rumContext = rumContext, + pipelines = pipelines + ) + } + + private fun createMemoryPipeline(sessionType: RumSessionType) = Pipeline( + sdkCore = sdkCore, + reader = VitalReaderWrapper( + vitalReader = MemoryVitalReader(internalLogger = sdkCore.internalLogger), + timeProvider = sdkCore.timeProvider, + intervalMs = TimeseriesConfiguration.DEFAULT_INTERVAL_MS + ), + buffer = Buffer(TimeseriesConfiguration.DEFAULT_BUFFER_SIZE), + eventFactory = MemoryEventFactory( + sessionType = sessionType, + totalRamBytes = totalRamBytes, + timeProvider = sdkCore.timeProvider, + batteryInfoProvider = batteryInfoProvider, + displayInfoProvider = displayInfoProvider, + internalLogger = sdkCore.internalLogger + ), + dataWriter = dataWriter, + insightsCollector = insightsCollector + ) + + private fun createCpuPipeline(sessionType: RumSessionType) = Pipeline( + sdkCore = sdkCore, + reader = CpuDatapointReader( + cpuStatReader = CpuStatReader(internalLogger = sdkCore.internalLogger), + timeProvider = sdkCore.timeProvider, + intervalMs = TimeseriesConfiguration.DEFAULT_INTERVAL_MS + ), + buffer = Buffer(TimeseriesConfiguration.DEFAULT_BUFFER_SIZE), + eventFactory = CpuEventFactory( + sessionType = sessionType, + timeProvider = sdkCore.timeProvider, + batteryInfoProvider = batteryInfoProvider, + displayInfoProvider = displayInfoProvider, + internalLogger = sdkCore.internalLogger + ), + dataWriter = dataWriter, + insightsCollector = insightsCollector + ) + + internal companion object { + const val MEMORY_TIMESERIES_DISABLED_MESSAGE = + "Unable to read total device memory; memory timeseries collection is disabled." + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/Pipeline.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/Pipeline.kt new file mode 100644 index 0000000000..129455a8c3 --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/Pipeline.kt @@ -0,0 +1,87 @@ +/* + * 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.rum.internal.timeseries + +import androidx.annotation.WorkerThread +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.api.feature.EventWriteScope +import com.datadog.android.api.feature.Feature +import com.datadog.android.api.feature.FeatureSdkCore +import com.datadog.android.api.storage.DataWriter +import com.datadog.android.api.storage.EventType +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.instrumentation.insights.InsightsCollector +import com.datadog.android.rum.internal.instrumentation.insights.NoOpInsightsCollector +import com.datadog.android.rum.internal.timeseries.factory.EventFactory +import com.datadog.android.rum.internal.timeseries.provider.DataPointsReader + +@Suppress("LongParameterList") +internal class Pipeline( + private val sdkCore: FeatureSdkCore, + private val reader: DataPointsReader, + private val buffer: Buffer, + private val eventFactory: EventFactory, + private val dataWriter: DataWriter, + private val insightsCollector: InsightsCollector = NoOpInsightsCollector() +) { + val intervalMs: Long get() = reader.intervalMs + + @WorkerThread + fun execute(rumContext: RumContext) { + // reader.read() may hit the filesystem (/proc); kept outside the lock so a concurrent + // flush() waits only for the buffer and never for I/O. + val dataPoint = reader.read() + synchronized(this) { + dataPoint?.let(buffer::add) + if (buffer.isFull()) drainAndWrite(rumContext) + } + } + + @WorkerThread + fun flush(rumContext: RumContext) = synchronized(this) { drainAndWrite(rumContext) } + + private fun drainAndWrite(rumContext: RumContext) { + val dataPoints = buffer.drain().ifEmpty { return } + sdkCore.getFeature(Feature.RUM_FEATURE_NAME) + ?.withWriteContext( + withFeatureContexts = setOf( + Feature.SESSION_REPLAY_FEATURE_NAME, + Feature.TRACING_FEATURE_NAME + ) + ) { datadogContext: DatadogContext, writeScope: EventWriteScope -> + val event = safeCall(ERROR_EVENT_CREATION_FAILED) { + eventFactory.create(datadogContext, rumContext, dataPoints) + } ?: return@withWriteContext + + writeScope { batchWriter -> + safeCall(ERROR_FLUSH_FAILED) { + if (dataWriter.write(batchWriter, event, EventType.DEFAULT)) { + insightsCollector.onTimeseries(eventFactory.eventName) + } + } + } + } + } + + private inline fun safeCall(message: String, block: () -> R): R? = try { + block() + } catch (@Suppress("TooGenericExceptionCaught") t: Throwable) { + sdkCore.internalLogger.log( + level = InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + messageBuilder = { message }, + throwable = t + ) + null + } + + private companion object { + private const val ERROR_FLUSH_FAILED = "Timeseries flush failed" + private const val ERROR_EVENT_CREATION_FAILED = "Timeseries event creation failed" + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/TimeseriesCollector.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/TimeseriesCollector.kt new file mode 100644 index 0000000000..ccd56677ec --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/TimeseriesCollector.kt @@ -0,0 +1,26 @@ +/* + * 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.rum.internal.timeseries + +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.tools.annotation.NoOpImplementation + +@NoOpImplementation +internal interface TimeseriesCollector { + fun onSessionStart() + fun onSessionStop() + fun onRumContextUpdate(newRumContext: RumContext) + + @NoOpImplementation + interface Factory { + fun create( + sessionType: RumSessionType, + rumContext: RumContext + ): TimeseriesCollector + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/factory/CpuEventFactory.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/factory/CpuEventFactory.kt new file mode 100644 index 0000000000..739adf8c96 --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/factory/CpuEventFactory.kt @@ -0,0 +1,110 @@ +/* + * 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.rum.internal.timeseries.factory + +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.core.internal.utils.DdTagsUtils +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.internal.FeaturesContextResolver +import com.datadog.android.rum.internal.domain.InfoProvider +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.domain.battery.BatteryInfo +import com.datadog.android.rum.internal.domain.display.DisplayInfo +import com.datadog.android.rum.internal.domain.scope.resolveSessionReplaySampleRate +import com.datadog.android.rum.internal.domain.scope.resolveTraceSampleRate +import com.datadog.android.rum.internal.domain.scope.toTimeseriesCpuDevice +import com.datadog.android.rum.internal.domain.scope.toTimeseriesCpuOs +import com.datadog.android.rum.internal.domain.scope.toTimeseriesCpuSessionPrecondition +import com.datadog.android.rum.internal.domain.scope.tryFromSource +import com.datadog.android.rum.internal.timeseries.DataPoint +import com.datadog.android.rum.internal.toTimeseriesCpuSessionType +import com.datadog.android.rum.model.TimeseriesCpuEvent +import java.util.UUID + +@Suppress("LongParameterList") +internal class CpuEventFactory( + private val sessionType: RumSessionType, + private val timeProvider: TimeProvider, + private val batteryInfoProvider: InfoProvider, + private val displayInfoProvider: InfoProvider, + private val internalLogger: InternalLogger, + private val featuresContextResolver: FeaturesContextResolver = FeaturesContextResolver() +) : EventFactory { + + override val eventName: String = "cpu" + + @Suppress("LongMethod") + override fun create( + datadogContext: DatadogContext, + rumContext: RumContext, + dataPoints: List> + ): TimeseriesCpuEvent? { + if (dataPoints.isEmpty()) return null + + val deviceInfo = datadogContext.deviceInfo + val syntheticsAttribute = if ( + rumContext.syntheticsTestId.isNullOrBlank() || + rumContext.syntheticsResultId.isNullOrBlank() + ) { + null + } else { + TimeseriesCpuEvent.Synthetics( + testId = rumContext.syntheticsTestId, + resultId = rumContext.syntheticsResultId + ) + } + + return TimeseriesCpuEvent( + dd = TimeseriesCpuEvent.Dd( + session = TimeseriesCpuEvent.DdSession( + sessionPrecondition = rumContext.sessionStartReason.toTimeseriesCpuSessionPrecondition() + ), + configuration = TimeseriesCpuEvent.Configuration( + sessionSampleRate = rumContext.sessionSampleRate, + sessionReplaySampleRate = datadogContext.resolveSessionReplaySampleRate(), + traceSampleRate = datadogContext.resolveTraceSampleRate() + ) + ), + application = TimeseriesCpuEvent.Application( + id = rumContext.applicationId, + currentLocale = deviceInfo.localeInfo.currentLocale + ), + session = TimeseriesCpuEvent.TimeseriesCpuEventSession( + id = rumContext.sessionId, + type = sessionType.toTimeseriesCpuSessionType(), + hasReplay = featuresContextResolver.resolveViewHasReplay( + datadogContext, + rumContext.viewId.orEmpty() + ) + ), + synthetics = syntheticsAttribute, + source = TimeseriesCpuEvent.Source.tryFromSource(datadogContext.source, internalLogger), + date = timeProvider.getServerTimestampMillis(), + version = datadogContext.version, + service = datadogContext.service, + buildVersion = datadogContext.versionCode.toString(), + buildId = datadogContext.appBuildId, + ddtags = DdTagsUtils.toDdTagsString(datadogContext), + os = deviceInfo.toTimeseriesCpuOs(), + device = deviceInfo.toTimeseriesCpuDevice( + batteryInfo = batteryInfoProvider.getState(), + displayInfo = displayInfoProvider.getState() + ), + timeseries = TimeseriesCpuEvent.Timeseries( + id = UUID.randomUUID().toString(), + start = dataPoints.firstOrNull()?.timestampNs ?: 0L, + end = dataPoints.lastOrNull()?.timestampNs ?: 0L, + data = TimeseriesCpuEvent.Data( + timestamps = dataPoints.map { it.timestampNs }, + values = TimeseriesCpuEvent.Values(dataPoints.map { it.value }) + ) + ) + ) + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/factory/EventFactory.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/factory/EventFactory.kt new file mode 100644 index 0000000000..b6008fa194 --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/factory/EventFactory.kt @@ -0,0 +1,21 @@ +/* + * 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.rum.internal.timeseries.factory + +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.timeseries.DataPoint + +internal interface EventFactory { + val eventName: String + + fun create( + datadogContext: DatadogContext, + rumContext: RumContext, + dataPoints: List> + ): E? +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/factory/MemoryEventFactory.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/factory/MemoryEventFactory.kt new file mode 100644 index 0000000000..c597ab7121 --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/factory/MemoryEventFactory.kt @@ -0,0 +1,123 @@ +/* + * 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.rum.internal.timeseries.factory + +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.core.internal.utils.DdTagsUtils +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.internal.FeaturesContextResolver +import com.datadog.android.rum.internal.domain.InfoProvider +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.domain.battery.BatteryInfo +import com.datadog.android.rum.internal.domain.display.DisplayInfo +import com.datadog.android.rum.internal.domain.scope.resolveSessionReplaySampleRate +import com.datadog.android.rum.internal.domain.scope.resolveTraceSampleRate +import com.datadog.android.rum.internal.domain.scope.toTimeseriesMemoryDevice +import com.datadog.android.rum.internal.domain.scope.toTimeseriesMemoryOs +import com.datadog.android.rum.internal.domain.scope.toTimeseriesMemorySessionPrecondition +import com.datadog.android.rum.internal.domain.scope.tryFromSource +import com.datadog.android.rum.internal.timeseries.DataPoint +import com.datadog.android.rum.internal.toTimeseriesMemorySessionType +import com.datadog.android.rum.model.TimeseriesMemoryEvent +import java.util.UUID + +@Suppress("LongParameterList") +internal class MemoryEventFactory( + private val sessionType: RumSessionType, + private val totalRamBytes: Long, + private val timeProvider: TimeProvider, + private val batteryInfoProvider: InfoProvider, + private val displayInfoProvider: InfoProvider, + private val internalLogger: InternalLogger, + private val featuresContextResolver: FeaturesContextResolver = FeaturesContextResolver() +) : EventFactory { + + override val eventName: String = "memory" + + @Suppress("LongMethod") + override fun create( + datadogContext: DatadogContext, + rumContext: RumContext, + dataPoints: List> + ): TimeseriesMemoryEvent? { + if (totalRamBytes <= 0L || dataPoints.isEmpty()) return null + + val deviceInfo = datadogContext.deviceInfo + val syntheticsAttribute = if ( + rumContext.syntheticsTestId.isNullOrBlank() || + rumContext.syntheticsResultId.isNullOrBlank() + ) { + null + } else { + TimeseriesMemoryEvent.Synthetics( + testId = rumContext.syntheticsTestId, + resultId = rumContext.syntheticsResultId + ) + } + + return TimeseriesMemoryEvent( + dd = TimeseriesMemoryEvent.Dd( + session = TimeseriesMemoryEvent.DdSession( + sessionPrecondition = rumContext.sessionStartReason.toTimeseriesMemorySessionPrecondition() + ), + configuration = TimeseriesMemoryEvent.Configuration( + sessionSampleRate = rumContext.sessionSampleRate, + sessionReplaySampleRate = datadogContext.resolveSessionReplaySampleRate(), + traceSampleRate = datadogContext.resolveTraceSampleRate() + ) + ), + application = TimeseriesMemoryEvent.Application( + id = rumContext.applicationId, + currentLocale = deviceInfo.localeInfo.currentLocale + ), + session = TimeseriesMemoryEvent.TimeseriesMemoryEventSession( + id = rumContext.sessionId, + type = sessionType.toTimeseriesMemorySessionType(), + hasReplay = featuresContextResolver.resolveViewHasReplay( + datadogContext, + rumContext.viewId.orEmpty() + ) + ), + synthetics = syntheticsAttribute, + source = TimeseriesMemoryEvent.Source.tryFromSource(datadogContext.source, internalLogger), + date = timeProvider.getServerTimestampMillis(), + version = datadogContext.version, + service = datadogContext.service, + buildVersion = datadogContext.versionCode.toString(), + buildId = datadogContext.appBuildId, + ddtags = DdTagsUtils.toDdTagsString(datadogContext), + os = deviceInfo.toTimeseriesMemoryOs(), + device = deviceInfo.toTimeseriesMemoryDevice( + batteryInfo = batteryInfoProvider.getState(), + displayInfo = displayInfoProvider.getState() + ), + timeseries = TimeseriesMemoryEvent.Timeseries( + id = UUID.randomUUID().toString(), + start = dataPoints.firstOrNull()?.timestampNs ?: 0L, + end = dataPoints.lastOrNull()?.timestampNs ?: 0L, + data = TimeseriesMemoryEvent.Data( + timestamps = dataPoints.map { it.timestampNs }, + values = TimeseriesMemoryEvent.Values( + memoryPercent = dataPoints.map { it.value / totalRamBytes * PERCENT_FACTOR }, + memoryFootprint = dataPoints.map { it.value / BYTES_IN_KB } + ) + ) + ) + ) + } + + private companion object { + const val PERCENT_FACTOR = 100.0 + + // Must match the factor used in MemoryVitalReader when converting VmRSS kB to bytes. + // Datadog memory vitals use decimal (SI) units, so 1000 (not 1024) keeps the emitted + // memory_footprint consistent with the collected value and with memory_percent. + const val BYTES_IN_KB = 1000 + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/provider/CpuDatapointReader.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/provider/CpuDatapointReader.kt new file mode 100644 index 0000000000..efcf4a1dde --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/provider/CpuDatapointReader.kt @@ -0,0 +1,66 @@ +/* + * 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.rum.internal.timeseries.provider + +import androidx.annotation.WorkerThread +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.internal.vitals.CpuStatReader + +/** + * Reads CPU usage as a percentage of total device capacity by computing successive + * deltas of the utime+stime CPU time provided by [CpuStatReader], divided by the number of + * available processors. + * + * CLK_TCK = 100 Hz on Android bionic: 100 ticks/s per core. Dividing by the core + * count normalizes the result to [0, 100] relative to total device CPU capacity, + * so multi-threaded work is represented correctly without artificial clamping. + * The first call always returns null. + */ +internal class CpuDatapointReader( + private val cpuStatReader: CpuStatReader, + private val timeProvider: TimeProvider, + override val intervalMs: Long, + private val availableProcessors: Int = Runtime.getRuntime().availableProcessors() +) : DataPointsReader(timeProvider) { + + private var lastUtime: Double? = null + private var lastNs: Long? = null + + @WorkerThread + override fun readValue() = cpuStatReader.readActiveTime()?.let { currentCpuTicks -> + val nowNs = timeProvider.getDeviceElapsedTimeNanos() + val (prevCpuTicks, prevNs) = updateValues(currentCpuTicks, nowNs) + if (prevCpuTicks == null || prevNs == null) return null + val elapsedMs = ((nowNs - prevNs) / NS_PER_MS).coerceAtLeast(1L) + // Sampling is suspended while the app is not in the foreground, so a gap much longer than + // the sampling interval means this delta spans that pause and would smear background CPU + // time over the first foreground sample. Drop it; the read above already re-baselined. + if (elapsedMs > intervalMs * MAX_GAP_FACTOR) return null + val corePercent = (currentCpuTicks - prevCpuTicks) * MS_PER_SECOND / elapsedMs + (corePercent / availableProcessors.coerceAtLeast(1)).coerceIn(0.0, MAX_CPU_PERCENT) + } + + private fun updateValues( + cpuTicks: Double, + nowNs: Long + ): Pair { + val prevCpuTicks = lastUtime + val prevNs = lastNs + lastUtime = cpuTicks + lastNs = nowNs + return prevCpuTicks to prevNs + } + + companion object { + private const val MS_PER_SECOND = 1000.0 + private const val NS_PER_MS = 1_000_000L + private const val MAX_CPU_PERCENT = 100.0 + + // How many sampling intervals a delta may span before it is treated as a gap. + internal const val MAX_GAP_FACTOR = 2 + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/provider/DataPointsReader.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/provider/DataPointsReader.kt new file mode 100644 index 0000000000..d00bb7bbce --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/provider/DataPointsReader.kt @@ -0,0 +1,28 @@ +/* + * 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.rum.internal.timeseries.provider + +import androidx.annotation.WorkerThread +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.internal.timeseries.DataPoint +import java.util.concurrent.TimeUnit + +internal abstract class DataPointsReader(private val timeProvider: TimeProvider) { + + abstract val intervalMs: Long + + @WorkerThread + protected abstract fun readValue(): T? + + @WorkerThread + open fun read(): DataPoint? = readValue()?.let { value -> + DataPoint( + value = value, + timestampNs = TimeUnit.MILLISECONDS.toNanos(timeProvider.getServerTimestampMillis()) + ) + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/provider/VitalReaderWrapper.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/provider/VitalReaderWrapper.kt new file mode 100644 index 0000000000..3afd3ccf1b --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/timeseries/provider/VitalReaderWrapper.kt @@ -0,0 +1,19 @@ +/* + * 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.rum.internal.timeseries.provider + +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.internal.vitals.VitalReader + +internal class VitalReaderWrapper( + private val vitalReader: VitalReader, + timeProvider: TimeProvider, + override val intervalMs: Long +) : DataPointsReader(timeProvider) { + + override fun readValue(): Double? = vitalReader.readVitalData() +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/CPUVitalReader.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/CPUVitalReader.kt index a7f570e230..aedaed9eb7 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/CPUVitalReader.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/CPUVitalReader.kt @@ -6,41 +6,16 @@ package com.datadog.android.rum.internal.vitals -import com.datadog.android.api.InternalLogger -import com.datadog.android.core.internal.persistence.file.canReadSafe -import com.datadog.android.core.internal.persistence.file.existsSafe -import com.datadog.android.core.internal.persistence.file.readTextSafe -import java.io.File +import androidx.annotation.WorkerThread /** - * Reads the CPU `utime` based on the `/proc/self/stat` file. - * cf. documentation https://man7.org/linux/man-pages/man5/procfs.5.html + * Reads the CPU `utime` based on the `/proc/self/stat` file, delegating the file access and + * parsing to [CpuStatReader]. */ internal class CPUVitalReader( - internal val statFile: File = STAT_FILE, - internal val internalLogger: InternalLogger + private val cpuStatReader: CpuStatReader ) : VitalReader { - @Suppress("ReturnCount") - override fun readVitalData(): Double? { - if (!(statFile.existsSafe(internalLogger) && statFile.canReadSafe(internalLogger))) { - return null - } - - val stat = statFile.readTextSafe(internalLogger = internalLogger) ?: return null - val tokens = stat.split(' ') - return if (tokens.size > UTIME_IDX) { - tokens[UTIME_IDX].toDoubleOrNull() - } else { - null - } - } - - companion object { - - private const val STAT_PATH = "/proc/self/stat" - internal val STAT_FILE = File(STAT_PATH) - - private const val UTIME_IDX = 13 - } + @WorkerThread + override fun readVitalData(): Double? = cpuStatReader.readUserTime() } diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/CpuStatReader.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/CpuStatReader.kt new file mode 100644 index 0000000000..673cb41848 --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/vitals/CpuStatReader.kt @@ -0,0 +1,64 @@ +/* + * 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.rum.internal.vitals + +import androidx.annotation.WorkerThread +import com.datadog.android.api.InternalLogger +import com.datadog.android.core.internal.persistence.file.canReadSafe +import com.datadog.android.core.internal.persistence.file.existsSafe +import com.datadog.android.core.internal.persistence.file.readTextSafe +import java.io.File + +/** + * Reads the process' CPU time counters from the `/proc/self/stat` file. + * cf. documentation https://man7.org/linux/man-pages/man5/procfs.5.html + */ +internal class CpuStatReader( + internal val statFile: File = STAT_FILE, + private val internalLogger: InternalLogger +) { + + /** + * Cumulative user-mode CPU time (`utime`, field 14 of `/proc/self/stat`) in clock ticks, + * or `null` when the file is unavailable or the field can't be parsed. + */ + @WorkerThread + fun readUserTime(): Double? = readTokens()?.getOrNull(UTIME_IDX)?.toDoubleOrNull() + + /** + * Cumulative active CPU time (`utime` + `stime`, fields 14 & 15) in clock ticks. Falls back + * to `utime` alone when `stime` is absent; returns `null` when the file is unavailable, + * `utime` is missing/unparseable, or `stime` is present but unparseable. + */ + @WorkerThread + @Suppress("ReturnCount") + fun readActiveTime(): Double? { + val tokens = readTokens() ?: return null + return when { + tokens.size <= UTIME_IDX -> null + tokens.size <= STIME_IDX -> tokens[UTIME_IDX].toDoubleOrNull() + else -> { + val utime = tokens[UTIME_IDX].toDoubleOrNull() ?: return null + val stime = tokens[STIME_IDX].toDoubleOrNull() ?: return null + utime + stime + } + } + } + + @WorkerThread + private fun readTokens(): List? { + if (!(statFile.existsSafe(internalLogger) && statFile.canReadSafe(internalLogger))) return null + return statFile.readTextSafe(internalLogger = internalLogger)?.split(' ') + } + + companion object { + private const val STAT_PATH = "/proc/self/stat" + internal val STAT_FILE = File(STAT_PATH) + private const val UTIME_IDX = 13 + private const val STIME_IDX = 14 + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/timeseries/TimeseriesConfiguration.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/timeseries/TimeseriesConfiguration.kt new file mode 100644 index 0000000000..26380cedd8 --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/timeseries/TimeseriesConfiguration.kt @@ -0,0 +1,57 @@ +/* + * 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.rum.timeseries + +import com.datadog.android.rum.ExperimentalRumApi + +/** + * Configuration for memory and CPU timeseries collection. + * + * Use [Builder] to create an instance. + */ +class TimeseriesConfiguration internal constructor( + internal val enabledTypes: Set +) { + + /** + * A Builder for [TimeseriesConfiguration]. + */ + @ExperimentalRumApi + class Builder { + + private var enabledTypes: Set = TimeseriesType.values().toSet() + + /** + * Restricts collection to the provided timeseries types. + * + * By default, all supported timeseries types are collected. + * Passing an empty array disables collection of every timeseries type. + * + * @param types the timeseries types to collect. + */ + fun collectOnly(vararg types: TimeseriesType): Builder = apply { + enabledTypes = types.toSet() + } + + /** Builds a [TimeseriesConfiguration] from the current builder state. */ + fun build(): TimeseriesConfiguration = TimeseriesConfiguration( + enabledTypes = enabledTypes + ) + } + + companion object { + + /** Default [TimeseriesConfiguration] built with all default settings. */ + @ExperimentalRumApi + val DEFAULT: TimeseriesConfiguration = Builder().build() + + /** Default number of samples to accumulate before emitting a timeseries event. */ + internal const val DEFAULT_BUFFER_SIZE: Int = 120 + + /** Default sampling interval in milliseconds. */ + internal const val DEFAULT_INTERVAL_MS: Long = 1000L + } +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/timeseries/TimeseriesType.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/timeseries/TimeseriesType.kt new file mode 100644 index 0000000000..56e41ee01a --- /dev/null +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/timeseries/TimeseriesType.kt @@ -0,0 +1,19 @@ +/* + * 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.rum.timeseries + +/** + * Type of device timeseries that can be collected by RUM. + */ +enum class TimeseriesType { + + /** CPU usage timeseries. */ + CPU, + + /** Memory usage timeseries. */ + MEMORY +} diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/telemetry/internal/TelemetryEventHandler.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/telemetry/internal/TelemetryEventHandler.kt index f60919cfdb..b351b4810c 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/telemetry/internal/TelemetryEventHandler.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/telemetry/internal/TelemetryEventHandler.kt @@ -446,6 +446,9 @@ internal class TelemetryEventHandler( is InternalTelemetryEvent.ApiUsage.TrackWebView -> { TelemetryUsageEvent.Usage.TrackWebView() } + is InternalTelemetryEvent.ApiUsage.Timeseries -> { + TelemetryUsageEvent.Usage.Timeseries() + } is InternalTelemetryEvent.ApiUsage.NetworkInstrumentation -> { TelemetryUsageEvent.Usage.AndroidNetworkInstrumentation( type = when (event.type) { diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/RumConfigurationBuilderTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/RumConfigurationBuilderTest.kt index 246b12466c..b9be98d4a3 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/RumConfigurationBuilderTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/RumConfigurationBuilderTest.kt @@ -30,6 +30,8 @@ import com.datadog.android.rum.model.ResourceEvent import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent +import com.datadog.android.rum.timeseries.TimeseriesConfiguration +import com.datadog.android.rum.timeseries.TimeseriesType import com.datadog.android.rum.tracking.ActionTrackingStrategy import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy import com.datadog.android.rum.tracking.InteractionPredicate @@ -65,6 +67,7 @@ import java.util.UUID ) @MockitoSettings(strictness = Strictness.LENIENT) @ForgeConfiguration(Configurator::class) +@OptIn(ExperimentalRumApi::class) internal class RumConfigurationBuilderTest { private lateinit var testedBuilder: RumConfiguration.Builder @@ -739,4 +742,19 @@ internal class RumConfigurationBuilderTest { assertThat(rumConfiguration.featureConfiguration.insightsCollector) .isInstanceOf(NoOpInsightsCollector::class.java) } + + @Test + fun `M store provided configuration W setTimeseriesConfiguration(config)`(forge: Forge) { + // Given + val fakeConfig = TimeseriesConfiguration.Builder() + .collectOnly(forge.aValueFrom(TimeseriesType::class.java)) + .build() + + // When + val rumConfiguration = testedBuilder.setTimeseriesConfiguration(fakeConfig).build() + + // Then + assertThat(rumConfiguration.featureConfiguration.timeseriesConfiguration) + .isSameAs(fakeConfig) + } } diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/RumTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/RumTest.kt index 1232c02422..8d4afa0a0f 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/RumTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/RumTest.kt @@ -14,18 +14,23 @@ import com.datadog.android.api.feature.FeatureSdkCore import com.datadog.android.core.InternalSdkCore import com.datadog.android.core.sampling.DeterministicSampler import com.datadog.android.core.sampling.RateBasedSampler +import com.datadog.android.internal.telemetry.InternalTelemetryEvent import com.datadog.android.rum.internal.RumFeature import com.datadog.android.rum.internal.monitor.DatadogRumMonitor import com.datadog.android.rum.internal.monitor.NoOpAdvancedRumMonitor import com.datadog.android.rum.internal.net.RumRequestFactory +import com.datadog.android.rum.timeseries.TimeseriesConfiguration +import com.datadog.android.rum.timeseries.TimeseriesType import com.datadog.android.rum.tracking.NoOpTrackingStrategy import com.datadog.android.rum.tracking.NoOpViewTrackingStrategy import com.datadog.android.rum.utils.config.MainLooperTestConfiguration import com.datadog.android.rum.utils.forge.Configurator +import com.datadog.android.utils.verifyApiUsage import com.datadog.android.utils.verifyLog import com.datadog.tools.unit.annotations.TestConfigurationsProvider import com.datadog.tools.unit.extensions.TestConfigurationExtension import com.datadog.tools.unit.extensions.config.TestConfiguration +import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.annotation.Forgery import fr.xgouchet.elmyr.annotation.StringForgery import fr.xgouchet.elmyr.junit5.ForgeConfiguration @@ -55,14 +60,18 @@ import org.mockito.quality.Strictness ) @MockitoSettings(strictness = Strictness.LENIENT) @ForgeConfiguration(Configurator::class) +@OptIn(ExperimentalRumApi::class) internal class RumTest { @Mock lateinit var mockSdkCore: InternalSdkCore + @Mock + lateinit var mockInternalLogger: InternalLogger + @BeforeEach fun `set up`() { - whenever(mockSdkCore.internalLogger) doReturn mock() + whenever(mockSdkCore.internalLogger) doReturn mockInternalLogger whenever(mockSdkCore.timeProvider) doReturn mock() whenever(mockSdkCore.firstPartyHostResolver) doReturn mock() whenever(mockSdkCore.createSingleThreadExecutorService(any())) doReturn mock() @@ -183,12 +192,81 @@ internal class RumTest { assertThat(monitor.appPackageName).isEqualTo(fakePackageName) } + @Test + fun `M send timeseries api usage W enable() { timeseries collection enabled }`( + @StringForgery fakePackageName: String, + @Forgery fakeRumConfiguration: RumConfiguration + ) { + // Given + stubFeatureInitialization(fakePackageName) + + // When + Rum.enable(fakeRumConfiguration.withTimeseries(TimeseriesConfiguration.DEFAULT), mockSdkCore) + + // Then + mockInternalLogger.verifyApiUsage( + apiUsage = InternalTelemetryEvent.ApiUsage.Timeseries(), + samplingRate = API_USAGE_SAMPLING_RATE + ) + } + + @Test + fun `M send timeseries api usage W enable() { timeseries collection subset }`( + @StringForgery fakePackageName: String, + @Forgery fakeRumConfiguration: RumConfiguration, + forge: Forge + ) { + // Given + stubFeatureInitialization(fakePackageName) + val fakeType = forge.aValueFrom(TimeseriesType::class.java) + val timeseriesConfiguration = TimeseriesConfiguration.Builder().collectOnly(fakeType).build() + + // When + Rum.enable(fakeRumConfiguration.withTimeseries(timeseriesConfiguration), mockSdkCore) + + // Then + mockInternalLogger.verifyApiUsage( + apiUsage = InternalTelemetryEvent.ApiUsage.Timeseries(), + samplingRate = API_USAGE_SAMPLING_RATE + ) + } + + @Test + fun `M not send timeseries api usage W enable() { timeseries collection disabled }`( + @StringForgery fakePackageName: String, + @Forgery fakeRumConfiguration: RumConfiguration + ) { + // Given + stubFeatureInitialization(fakePackageName) + val fakeTimeseriesConfiguration = TimeseriesConfiguration.Builder().collectOnly().build() + + // When + Rum.enable(fakeRumConfiguration.withTimeseries(fakeTimeseriesConfiguration), mockSdkCore) + + // Then + verify(mockInternalLogger, never()).logApiUsage(any(), any()) + } + + @Test + fun `M not send timeseries api usage W enable() { no timeseries configuration }`( + @StringForgery fakePackageName: String, + @Forgery fakeRumConfiguration: RumConfiguration + ) { + // Given + stubFeatureInitialization(fakePackageName) + + // When + Rum.enable(fakeRumConfiguration.withTimeseries(null), mockSdkCore) + + // Then + verify(mockInternalLogger, never()).logApiUsage(any(), any()) + } + @Test fun `M register nothing W enable() { SDK instance doesn't implement InternalSdkCore }`( @Forgery fakeRumConfiguration: RumConfiguration ) { // Given - val mockInternalLogger = mock() val wrongSdkCore = mock() whenever(wrongSdkCore.internalLogger) doReturn mockInternalLogger @@ -210,10 +288,6 @@ internal class RumTest { @Forgery fakeRumConfiguration: RumConfiguration, @StringForgery(regex = "\\s*") fakeApplicationId: String ) { - // Given - val mockInternalLogger = mock() - whenever(mockSdkCore.internalLogger) doReturn mockInternalLogger - // When Rum.enable( rumConfiguration = fakeRumConfiguration.copy(applicationId = fakeApplicationId), @@ -235,8 +309,6 @@ internal class RumTest { @Forgery fakeRumConfiguration: RumConfiguration ) { // Given - val mockInternalLogger = mock() - whenever(mockSdkCore.internalLogger) doReturn mockInternalLogger whenever(mockSdkCore.getFeature(Feature.RUM_FEATURE_NAME)) doReturn mock() // When @@ -251,7 +323,27 @@ internal class RumTest { verify(mockSdkCore, never()).registerFeature(any()) } + private fun stubFeatureInitialization(packageName: String) { + whenever(mockSdkCore.registerFeature(any())) doAnswer { + val mockApplication = mock { application -> + whenever(application.packageName) doReturn packageName + whenever(application.resources) doReturn mock() + whenever(application.contentResolver) doReturn mock() + whenever(application.resources.configuration) doReturn mock() + } + whenever(mockApplication.applicationContext) doReturn mockApplication + + it.getArgument(0).onInitialize(appContext = mockApplication) + } + } + + private fun RumConfiguration.withTimeseries(configuration: TimeseriesConfiguration?) = copy( + featureConfiguration = featureConfiguration.copy(timeseriesConfiguration = configuration) + ) + companion object { + private const val API_USAGE_SAMPLING_RATE = 15f + private val mainLooper = MainLooperTestConfiguration() @TestConfigurationsProvider diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ActionEventAssert.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ActionEventAssert.kt index 93ab7dc5b9..1c186aa40b 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ActionEventAssert.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ActionEventAssert.kt @@ -157,19 +157,19 @@ internal class ActionEventAssert(actual: ActionEvent) : expectedName: String?, expectedUrl: String? ): ActionEventAssert { - assertThat(actual.view.id) + assertThat(actual.view?.id) .overridingErrorMessage( - "Expected event data to have view.id $expectedId but was ${actual.view.id}" + "Expected event data to have view.id $expectedId but was ${actual.view?.id}" ) .isEqualTo(expectedId.orEmpty()) - assertThat(actual.view.name) + assertThat(actual.view?.name) .overridingErrorMessage( - "Expected event data to have view.name $expectedName but was ${actual.view.name}" + "Expected event data to have view.name $expectedName but was ${actual.view?.name}" ) .isEqualTo(expectedName) - assertThat(actual.view.url) + assertThat(actual.view?.url) .overridingErrorMessage( - "Expected event data to have view.url $expectedUrl but was ${actual.view.url}" + "Expected event data to have view.url $expectedUrl but was ${actual.view?.url}" ) .isEqualTo(expectedUrl.orEmpty()) return this @@ -178,21 +178,21 @@ internal class ActionEventAssert(actual: ActionEvent) : fun hasView( expected: RumContext ): ActionEventAssert { - assertThat(actual.view.id) + assertThat(actual.view?.id) .overridingErrorMessage( - "Expected event data to have view.id ${expected.viewId} but was ${actual.view.id}" + "Expected event data to have view.id ${expected.viewId} but was ${actual.view?.id}" ) .isEqualTo(expected.viewId.orEmpty()) - assertThat(actual.view.name) + assertThat(actual.view?.name) .overridingErrorMessage( "Expected event data to have view.name ${expected.viewName} " + - "but was ${actual.view.name}" + "but was ${actual.view?.name}" ) .isEqualTo(expected.viewName) - assertThat(actual.view.url) + assertThat(actual.view?.url) .overridingErrorMessage( "Expected event data to have view.url ${expected.viewUrl} " + - "but was ${actual.view.url}" + "but was ${actual.view?.url}" ) .isEqualTo(expected.viewUrl.orEmpty()) return this diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ErrorEventAssert.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ErrorEventAssert.kt index 2625234924..c7d08d0fe0 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ErrorEventAssert.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ErrorEventAssert.kt @@ -252,41 +252,41 @@ internal class ErrorEventAssert(actual: ErrorEvent) : expectedName: String?, expectedUrl: String? ): ErrorEventAssert { - assertThat(actual.view.id) + assertThat(actual.view?.id) .overridingErrorMessage( - "Expected event data to have view.id $expectedId but was ${actual.view.id}" + "Expected event data to have view.id $expectedId but was ${actual.view?.id}" ) .isEqualTo(expectedId.orEmpty()) - assertThat(actual.view.name) + assertThat(actual.view?.name) .overridingErrorMessage( - "Expected event data to have view.name $expectedName but was ${actual.view.name}" + "Expected event data to have view.name $expectedName but was ${actual.view?.name}" ) .isEqualTo(expectedName) - assertThat(actual.view.url) + assertThat(actual.view?.url) .overridingErrorMessage( - "Expected event data to have view.url $expectedUrl but was ${actual.view.url}" + "Expected event data to have view.url $expectedUrl but was ${actual.view?.url}" ) .isEqualTo(expectedUrl.orEmpty()) return this } fun hasView(expected: RumContext): ErrorEventAssert { - assertThat(actual.view.id) + assertThat(actual.view?.id) .overridingErrorMessage( "Expected event data to have view.id ${expected.viewId} " + - "but was ${actual.view.id}" + "but was ${actual.view?.id}" ) .isEqualTo(expected.viewId.orEmpty()) - assertThat(actual.view.name) + assertThat(actual.view?.name) .overridingErrorMessage( "Expected event data to have view.name ${expected.viewName} " + - "but was ${actual.view.name}" + "but was ${actual.view?.name}" ) .isEqualTo(expected.viewName) - assertThat(actual.view.url) + assertThat(actual.view?.url) .overridingErrorMessage( "Expected event data to have view.url ${expected.viewUrl} " + - "but was ${actual.view.url}" + "but was ${actual.view?.url}" ) .isEqualTo(expected.viewUrl.orEmpty()) return this diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/LongTaskEventAssert.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/LongTaskEventAssert.kt index c65cd2807f..143d5f586d 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/LongTaskEventAssert.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/LongTaskEventAssert.kt @@ -180,14 +180,14 @@ internal class LongTaskEventAssert(actual: LongTaskEvent) : } fun hasView(expectedId: String?, expectedUrl: String?): LongTaskEventAssert { - assertThat(actual.view.id) + assertThat(actual.view?.id) .overridingErrorMessage( - "Expected event data to have view.id $expectedId but was ${actual.view.id}" + "Expected event data to have view.id $expectedId but was ${actual.view?.id}" ) .isEqualTo(expectedId.orEmpty()) - assertThat(actual.view.url) + assertThat(actual.view?.url) .overridingErrorMessage( - "Expected event data to have view.id $expectedUrl but was ${actual.view.url}" + "Expected event data to have view.id $expectedUrl but was ${actual.view?.url}" ) .isEqualTo(expectedUrl.orEmpty()) return this diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ResourceEventAssert.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ResourceEventAssert.kt index 382c050302..74bfc26d79 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ResourceEventAssert.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/ResourceEventAssert.kt @@ -377,22 +377,22 @@ internal class ResourceEventAssert(actual: ResourceEvent) : } fun hasView(expected: RumContext): ResourceEventAssert { - assertThat(actual.view.id) + assertThat(actual.view?.id) .overridingErrorMessage( "Expected event data to have view.id ${expected.viewId} " + - "but was ${actual.view.id}" + "but was ${actual.view?.id}" ) .isEqualTo(expected.viewId.orEmpty()) - assertThat(actual.view.name) + assertThat(actual.view?.name) .overridingErrorMessage( "Expected event data to have view.name ${expected.viewName} " + - "but was ${actual.view.name}" + "but was ${actual.view?.name}" ) .isEqualTo(expected.viewName) - assertThat(actual.view.url) + assertThat(actual.view?.url) .overridingErrorMessage( "Expected event data to have view.url ${expected.viewUrl} " + - "but was ${actual.view.url}" + "but was ${actual.view?.url}" ) .isEqualTo(expected.viewUrl.orEmpty()) return this diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/VitalAppLaunchEventAssert.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/VitalAppLaunchEventAssert.kt index e084faddca..f6191dde13 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/VitalAppLaunchEventAssert.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/VitalAppLaunchEventAssert.kt @@ -98,25 +98,25 @@ internal class VitalAppLaunchEventAssert( } fun hasViewId(expectedId: String) = apply { - assertThat(actual.view.id) + assertThat(actual.view?.id) .overridingErrorMessage( - "Expected event data to have view.id $expectedId but was ${actual.view.id}" + "Expected event data to have view.id $expectedId but was ${actual.view?.id}" ) .isEqualTo(expectedId) } fun hasName(expected: String?) = apply { - assertThat(actual.view.name) + assertThat(actual.view?.name) .overridingErrorMessage( - "Expected event data to have view.name $expected but was ${actual.view.name}" + "Expected event data to have view.name $expected but was ${actual.view?.name}" ) .isEqualTo(expected) } fun hasUrl(expected: String) = apply { - assertThat(actual.view.url) + assertThat(actual.view?.url) .overridingErrorMessage( - "Expected event data to have view.url $expected but was ${actual.view.url}" + "Expected event data to have view.url $expected but was ${actual.view?.url}" ) .isEqualTo(expected) } diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/VitalEventAssert.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/VitalEventAssert.kt index 7805c55fb3..6342a6f385 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/VitalEventAssert.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/assertj/VitalEventAssert.kt @@ -107,25 +107,25 @@ internal class VitalEventAssert( } fun hasViewId(expectedId: String) = apply { - assertThat(actual.view.id) + assertThat(actual.view?.id) .overridingErrorMessage( - "Expected event data to have view.id $expectedId but was ${actual.view.id}" + "Expected event data to have view.id $expectedId but was ${actual.view?.id}" ) .isEqualTo(expectedId) } fun hasName(expected: String) = apply { - assertThat(actual.view.name) + assertThat(actual.view?.name) .overridingErrorMessage( - "Expected event data to have view.name $expected but was ${actual.view.name}" + "Expected event data to have view.name $expected but was ${actual.view?.name}" ) .isEqualTo(expected) } fun hasUrl(expected: String) = apply { - assertThat(actual.view.url) + assertThat(actual.view?.url) .overridingErrorMessage( - "Expected event data to have view.url $expected but was ${actual.view.url}" + "Expected event data to have view.url $expected but was ${actual.view?.url}" ) .isEqualTo(expected) } diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/RumFeatureTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/RumFeatureTest.kt index efd52d69bc..a01e91dfa7 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/RumFeatureTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/RumFeatureTest.kt @@ -16,6 +16,7 @@ import android.content.res.Resources import android.os.Handler import com.datadog.android.api.InternalLogger import com.datadog.android.api.feature.FeatureContextUpdateReceiver +import com.datadog.android.api.storage.DataWriter import com.datadog.android.api.storage.NoOpDataWriter import com.datadog.android.core.InternalSdkCore import com.datadog.android.core.feature.event.JvmCrash @@ -28,6 +29,7 @@ import com.datadog.android.internal.system.BuildSdkVersionProvider import com.datadog.android.internal.telemetry.InternalTelemetryEvent import com.datadog.android.internal.utils.asString import com.datadog.android.internal.utils.loggableStackTrace +import com.datadog.android.rum.ExperimentalRumApi import com.datadog.android.rum.GlobalRumMonitor import com.datadog.android.rum.RumAttributes import com.datadog.android.rum.RumErrorSource @@ -46,11 +48,14 @@ import com.datadog.android.rum.internal.domain.accessibility.NoOpAccessibilitySn import com.datadog.android.rum.internal.domain.battery.DefaultBatteryInfoProvider import com.datadog.android.rum.internal.domain.display.DefaultDisplayInfoProvider import com.datadog.android.rum.internal.domain.event.RumEventMapper +import com.datadog.android.rum.internal.instrumentation.insights.InsightsCollector import com.datadog.android.rum.internal.metric.slowframes.SlowFramesListener import com.datadog.android.rum.internal.monitor.AdvancedRumMonitor +import com.datadog.android.rum.internal.monitor.DatadogRumMonitor import com.datadog.android.rum.internal.monitor.NoOpAdvancedRumMonitor import com.datadog.android.rum.internal.startup.RumAppStartupDetector import com.datadog.android.rum.internal.thread.NoOpScheduledExecutorService +import com.datadog.android.rum.internal.timeseries.DefaultTimeseriesCollectorFactory import com.datadog.android.rum.internal.tracking.NoOpInteractionPredicate import com.datadog.android.rum.internal.tracking.NoOpUserActionTrackingStrategy import com.datadog.android.rum.internal.tracking.UserActionTrackingStrategy @@ -60,6 +65,7 @@ import com.datadog.android.rum.internal.vitals.FrameStateListener import com.datadog.android.rum.internal.vitals.FrameStatesAggregator import com.datadog.android.rum.internal.vitals.NoOpVitalMonitor import com.datadog.android.rum.internal.vitals.VitalReaderRunnable +import com.datadog.android.rum.timeseries.TimeseriesConfiguration import com.datadog.android.rum.tracking.InteractionPredicate import com.datadog.android.rum.tracking.NoOpTrackingStrategy import com.datadog.android.rum.tracking.NoOpViewTrackingStrategy @@ -732,7 +738,8 @@ internal class RumFeatureTest { fun `M not initialize the vital monitors W initialize { frequency = NEVER }`() { // Given fakeConfiguration = fakeConfiguration.copy( - vitalsMonitorUpdateFrequency = VitalsUpdateFrequency.NEVER + vitalsMonitorUpdateFrequency = VitalsUpdateFrequency.NEVER, + timeseriesConfiguration = null ) testedFeature = RumFeature( mockSdkCore, @@ -849,6 +856,104 @@ internal class RumFeatureTest { assertThat(testedFeature.dataWriter).isInstanceOf(NoOpDataWriter::class.java) } + @Test + fun `M stop active timeseries before resetting writer W onStop()`() { + // Given + testedFeature.onInitialize(appContext.mockInstance) + val stubDatadogMonitor = mock() + GlobalRumMonitor.clear() + GlobalRumMonitor.registerIfAbsent(stubDatadogMonitor, mockSdkCore) + + var writerAtStopTime: DataWriter? = null + doAnswer { + writerAtStopTime = testedFeature.dataWriter + }.whenever(stubDatadogMonitor).stopTimeseries() + + // When + testedFeature.onStop() + + // Then — the last timeseries batch must still reach the real writer + assertThat(writerAtStopTime).isNotNull + assertThat(writerAtStopTime).isNotInstanceOf(NoOpDataWriter::class.java) + assertThat(testedFeature.dataWriter).isInstanceOf(NoOpDataWriter::class.java) + } + + @Test + @OptIn(ExperimentalRumApi::class) + fun `M wire timeseries factory W initialize { timeseries enabled }`( + @LongForgery(min = 1L) fakeTotalRamBytes: Long + ) { + // Given + fakeConfiguration = fakeConfiguration.copy( + timeseriesConfiguration = TimeseriesConfiguration.Builder().build() + ) + testedFeature = RumFeature( + mockSdkCore, + fakeApplicationId.toString(), + fakeConfiguration, + lateCrashReporterFactory = { mockLateCrashReporter } + ) + val stubActivityManager = mock() + doAnswer { invocation -> + invocation.getArgument(0).totalMem = fakeTotalRamBytes + null + }.whenever(stubActivityManager).getMemoryInfo(any()) + whenever( + appContext.mockInstance.getSystemService(Context.ACTIVITY_SERVICE) + ) doReturn stubActivityManager + + // When + testedFeature.onInitialize(appContext.mockInstance) + + // Then + val timeseriesFactory = testedFeature.timeseriesCollectorFactory + check(timeseriesFactory is DefaultTimeseriesCollectorFactory) + assertThat(timeseriesFactory.getFieldValue, DefaultTimeseriesCollectorFactory>("dataWriter")) + .isSameAs(testedFeature.dataWriter) + assertThat( + timeseriesFactory.getFieldValue("insightsCollector") + ) + .isSameAs(testedFeature.insightsCollector) + assertThat( + timeseriesFactory + .getFieldValue("scheduledExecutorService") + ).isSameAs(testedFeature.vitalExecutorService) + assertThat(timeseriesFactory.getFieldValue("totalRamBytes")) + .isEqualTo(fakeTotalRamBytes) + assertThat( + timeseriesFactory.getFieldValue, DefaultTimeseriesCollectorFactory>("batteryInfoProvider") + ) + .isSameAs(testedFeature.batteryInfoProvider) + assertThat( + timeseriesFactory.getFieldValue, DefaultTimeseriesCollectorFactory>("displayInfoProvider") + ) + .isSameAs(testedFeature.displayInfoProvider) + } + + @Test + @OptIn(ExperimentalRumApi::class) + fun `M initialize vital executor W initialize { frequency = NEVER and timeseries enabled }`() { + // Given + fakeConfiguration = fakeConfiguration.copy( + vitalsMonitorUpdateFrequency = VitalsUpdateFrequency.NEVER, + slowFramesConfiguration = null, + timeseriesConfiguration = TimeseriesConfiguration.Builder().build() + ) + testedFeature = RumFeature( + mockSdkCore, + fakeApplicationId.toString(), + fakeConfiguration, + lateCrashReporterFactory = { mockLateCrashReporter } + ) + + // When + testedFeature.onInitialize(appContext.mockInstance) + + // Then: timeseries sampling needs a real executor even when vitals are disabled. + assertThat(testedFeature.vitalExecutorService) + .isNotInstanceOf(NoOpScheduledExecutorService::class.java) + } + @Test fun `M remove associated monitor W onStop()`() { // Given @@ -933,7 +1038,8 @@ internal class RumFeatureTest { fun `M not initialize vital executor W initialize { frequency = NEVER }()`() { // Given fakeConfiguration = fakeConfiguration.copy( - vitalsMonitorUpdateFrequency = VitalsUpdateFrequency.NEVER + vitalsMonitorUpdateFrequency = VitalsUpdateFrequency.NEVER, + timeseriesConfiguration = null ) testedFeature = RumFeature( mockSdkCore, diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/RumSessionTypeExtTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/RumSessionTypeExtTest.kt new file mode 100644 index 0000000000..ac9174b1ac --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/RumSessionTypeExtTest.kt @@ -0,0 +1,160 @@ +/* + * 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.rum.internal + +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.model.ActionEvent +import com.datadog.android.rum.model.ErrorEvent +import com.datadog.android.rum.model.LongTaskEvent +import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent.TimeseriesCpuEventSessionType +import com.datadog.android.rum.model.TimeseriesMemoryEvent.TimeseriesMemoryEventSessionType +import com.datadog.android.rum.model.ViewEvent +import com.datadog.android.rum.model.VitalAppLaunchEvent +import com.datadog.android.rum.model.VitalOperationStepEvent +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource + +internal class RumSessionTypeExtTest { + + @ParameterizedTest + @MethodSource("toActionMappings") + fun `M map session type W toAction()`(input: RumSessionType, expected: ActionEvent.ActionEventSessionType) { + assertThat(input.toAction()).isEqualTo(expected) + } + + @ParameterizedTest + @MethodSource("toResourceMappings") + fun `M map session type W toResource()`(input: RumSessionType, expected: ResourceEvent.ResourceEventSessionType) { + assertThat(input.toResource()).isEqualTo(expected) + } + + @ParameterizedTest + @MethodSource("toErrorMappings") + fun `M map session type W toError()`(input: RumSessionType, expected: ErrorEvent.ErrorEventSessionType) { + assertThat(input.toError()).isEqualTo(expected) + } + + @ParameterizedTest + @MethodSource("toViewMappings") + fun `M map session type W toView()`(input: RumSessionType, expected: ViewEvent.ViewEventSessionType) { + assertThat(input.toView()).isEqualTo(expected) + } + + @ParameterizedTest + @MethodSource("toLongTaskMappings") + fun `M map session type W toLongTask()`(input: RumSessionType, expected: LongTaskEvent.LongTaskEventSessionType) { + assertThat(input.toLongTask()).isEqualTo(expected) + } + + @ParameterizedTest + @MethodSource("toVitalMappings") + fun `M map session type W toVital()`( + input: RumSessionType, + expected: VitalOperationStepEvent.VitalOperationStepEventSessionType + ) { + assertThat(input.toVital()).isEqualTo(expected) + } + + @ParameterizedTest + @MethodSource("toVitalAppLaunchMappings") + fun `M map session type W toVitalAppLaunch()`( + input: RumSessionType, + expected: VitalAppLaunchEvent.VitalAppLaunchEventSessionType + ) { + assertThat(input.toVitalAppLaunch()).isEqualTo(expected) + } + + @ParameterizedTest + @MethodSource("toTimeseriesMemorySessionTypeMappings") + fun `M map session type W toTimeseriesMemorySessionType()`( + input: RumSessionType, + expected: TimeseriesMemoryEventSessionType + ) { + assertThat(input.toTimeseriesMemorySessionType()).isEqualTo(expected) + } + + @ParameterizedTest + @MethodSource("toTimeseriesCpuSessionTypeMappings") + fun `M map session type W toTimeseriesCpuSessionType()`( + input: RumSessionType, + expected: TimeseriesCpuEventSessionType + ) { + assertThat(input.toTimeseriesCpuSessionType()).isEqualTo(expected) + } + + companion object { + + @JvmStatic + fun toActionMappings(): List = listOf( + Arguments.of(RumSessionType.USER, ActionEvent.ActionEventSessionType.USER), + Arguments.of(RumSessionType.SYNTHETICS, ActionEvent.ActionEventSessionType.SYNTHETICS) + ) + + @JvmStatic + fun toResourceMappings(): List = listOf( + Arguments.of(RumSessionType.USER, ResourceEvent.ResourceEventSessionType.USER), + Arguments.of(RumSessionType.SYNTHETICS, ResourceEvent.ResourceEventSessionType.SYNTHETICS) + ) + + @JvmStatic + fun toErrorMappings(): List = listOf( + Arguments.of(RumSessionType.USER, ErrorEvent.ErrorEventSessionType.USER), + Arguments.of(RumSessionType.SYNTHETICS, ErrorEvent.ErrorEventSessionType.SYNTHETICS) + ) + + @JvmStatic + fun toViewMappings(): List = listOf( + Arguments.of(RumSessionType.USER, ViewEvent.ViewEventSessionType.USER), + Arguments.of(RumSessionType.SYNTHETICS, ViewEvent.ViewEventSessionType.SYNTHETICS) + ) + + @JvmStatic + fun toLongTaskMappings(): List = listOf( + Arguments.of(RumSessionType.USER, LongTaskEvent.LongTaskEventSessionType.USER), + Arguments.of(RumSessionType.SYNTHETICS, LongTaskEvent.LongTaskEventSessionType.SYNTHETICS) + ) + + @JvmStatic + fun toVitalMappings(): List = listOf( + Arguments.of( + RumSessionType.USER, + VitalOperationStepEvent.VitalOperationStepEventSessionType.USER + ), + Arguments.of( + RumSessionType.SYNTHETICS, + VitalOperationStepEvent.VitalOperationStepEventSessionType.SYNTHETICS + ) + ) + + @JvmStatic + fun toVitalAppLaunchMappings(): List = listOf( + Arguments.of( + RumSessionType.USER, + VitalAppLaunchEvent.VitalAppLaunchEventSessionType.USER + ), + Arguments.of( + RumSessionType.SYNTHETICS, + VitalAppLaunchEvent.VitalAppLaunchEventSessionType.SYNTHETICS + ) + ) + + @JvmStatic + fun toTimeseriesMemorySessionTypeMappings(): List = listOf( + Arguments.of(RumSessionType.USER, TimeseriesMemoryEventSessionType.USER), + Arguments.of(RumSessionType.SYNTHETICS, TimeseriesMemoryEventSessionType.SYNTHETICS) + ) + + @JvmStatic + fun toTimeseriesCpuSessionTypeMappings(): List = listOf( + Arguments.of(RumSessionType.USER, TimeseriesCpuEventSessionType.USER), + Arguments.of(RumSessionType.SYNTHETICS, TimeseriesCpuEventSessionType.SYNTHETICS) + ) + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/RumDataWriterTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/RumDataWriterTest.kt index 811e15987a..554ad66a39 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/RumDataWriterTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/RumDataWriterTest.kt @@ -17,6 +17,8 @@ import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.utils.config.GlobalRumMonitorTestConfiguration import com.datadog.android.rum.utils.forge.Configurator @@ -47,6 +49,7 @@ import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doReturn import org.mockito.kotlin.doThrow +import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.times import org.mockito.kotlin.verify @@ -206,6 +209,29 @@ internal class RumDataWriterTest { assertThat(captor.firstValue.eventType).isEqualTo("unknown") } + @Test + fun `M resolve timeseries event type W write() { generated timeseries events }`() { + // Given + val fakeEvents = listOf( + mock { on { type } doReturn "timeseries" }, + mock { on { type } doReturn "timeseries" } + ) + fakeEvents.forEach { whenever(mockSerializer.serialize(it)) doReturn fakeSerializedEvent } + + // When + fakeEvents.forEach { testedWriter.write(mockEventBatchWriter, it, fakeEventType) } + + // Then + val captor = argumentCaptor() + verify(mockEventBatchWriter, times(fakeEvents.size)).write( + any(), + anyOrNull(), + any(), + captor.capture() + ) + assertThat(captor.allValues.map { it.eventType }).containsOnly("timeseries") + } + @Test fun `M write data with event meta W write() {View Event}`( @Forgery fakeViewEvent: ViewEvent, diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapperTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapperTest.kt index 04e838179d..d98586c7a8 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapperTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapperTest.kt @@ -12,6 +12,8 @@ import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent @@ -35,6 +37,7 @@ import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoSettings import org.mockito.kotlin.any +import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.verifyNoInteractions import org.mockito.kotlin.whenever @@ -283,6 +286,22 @@ internal class RumEventMapperTest { assertThat(mappedRumEvent).isSameAs(telemetryErrorEvent) } + @Test + fun `M return the original event W map() { timeseries events }`() { + // Given + val fakeEvents = listOf( + mock(), + mock() + ) + + // When + val mappedEvents = fakeEvents.map(testedRumEventMapper::map) + + // Then + verifyNoInteractions(mockInternalLogger) + assertThat(mappedEvents).containsExactlyElementsOf(fakeEvents) + } + @Test fun `M return the bundled event W map { TelemetryConfigurationEvent }`( @Forgery telemetryConfigurationEvent: TelemetryConfigurationEvent diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventSerializerTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventSerializerTest.kt index 5f645700a4..acca076c63 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventSerializerTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventSerializerTest.kt @@ -14,6 +14,8 @@ import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent import com.datadog.android.rum.model.ViewEvent import com.datadog.android.rum.model.VitalAppLaunchEvent import com.datadog.android.rum.model.VitalOperationStepEvent @@ -92,8 +94,8 @@ internal class RumEventSerializerTest { hasField("type", event.session.type.name.lowercase(Locale.US)) } .hasField("view") { - hasField("id", event.view.id) - hasField("url", event.view.url) + hasNullableField("id", event.view?.id) + hasNullableField("url", event.view?.url) } .hasField("_dd") { hasField("format_version", 2L) @@ -209,8 +211,8 @@ internal class RumEventSerializerTest { hasField("type", event.session.type.name.lowercase(Locale.US)) } .hasField("view") { - hasField("id", event.view.id) - hasField("url", event.view.url) + hasNullableField("id", event.view?.id) + hasNullableField("url", event.view?.url) } .hasField("_dd") { hasField("format_version", 2L) @@ -401,8 +403,8 @@ internal class RumEventSerializerTest { hasField("type", event.session.type.name.lowercase(Locale.US)) } .hasField("view") { - hasField("id", event.view.id) - hasField("url", event.view.url) + hasNullableField("id", event.view?.id) + hasNullableField("url", event.view?.url) } .hasField("_dd") { hasField("format_version", 2L) @@ -488,8 +490,8 @@ internal class RumEventSerializerTest { hasField("type", event.session.type.name.lowercase(Locale.US)) } .hasField("view") { - hasField("id", event.view.id) - hasField("url", event.view.url) + hasNullableField("id", event.view?.id) + hasNullableField("url", event.view?.url) } .hasField("_dd") { hasField("format_version", 2L) @@ -667,7 +669,7 @@ internal class RumEventSerializerTest { } .hasNullableField("service", event.service) - event.view.let { + event.view?.let { assertThat(jsonObject).hasField("view") { val view = checkNotNull(event.view) hasField("id", view.id) @@ -1198,6 +1200,19 @@ internal class RumEventSerializerTest { assertThat(serialized).isEqualTo(fakeJsonObject.toString()) } + @Test + fun `M serialize generated event W serialize() { timeseries events }`() { + // Given + val fakeEvents = createTimeseriesEvents() + + // When + val serializedEvents = fakeEvents.map(testedSerializer::serialize) + + // Then + assertThat(serializedEvents.map { JsonParser.parseString(it).asJsonObject.get("type").asString }) + .containsOnly("timeseries") + } + @Test fun `M keep known custom attributes as is W serialize()`(forge: Forge) { val key = forge.anElementFrom(RumEventSerializer.knownAttributes) @@ -2176,6 +2191,50 @@ internal class RumEventSerializerTest { // region Internal + private fun createTimeseriesEvents(): List { + return listOf( + TimeseriesCpuEvent( + date = 0L, + application = TimeseriesCpuEvent.Application(id = "application-id"), + session = TimeseriesCpuEvent.TimeseriesCpuEventSession( + id = "session-id", + type = TimeseriesCpuEvent.TimeseriesCpuEventSessionType.USER + ), + dd = TimeseriesCpuEvent.Dd(), + timeseries = TimeseriesCpuEvent.Timeseries( + id = "timeseries-id", + start = 0L, + end = 0L, + data = TimeseriesCpuEvent.Data( + timestamps = emptyList(), + values = TimeseriesCpuEvent.Values(cpuUsage = emptyList()) + ) + ) + ), + TimeseriesMemoryEvent( + date = 0L, + application = TimeseriesMemoryEvent.Application(id = "application-id"), + session = TimeseriesMemoryEvent.TimeseriesMemoryEventSession( + id = "session-id", + type = TimeseriesMemoryEvent.TimeseriesMemoryEventSessionType.USER + ), + dd = TimeseriesMemoryEvent.Dd(), + timeseries = TimeseriesMemoryEvent.Timeseries( + id = "timeseries-id", + start = 0L, + end = 0L, + data = TimeseriesMemoryEvent.Data( + timestamps = emptyList(), + values = TimeseriesMemoryEvent.Values( + memoryFootprint = emptyList(), + memoryPercent = emptyList() + ) + ) + ) + ) + ) + } + private fun Forge.forgeRumEvent( attributes: MutableMap = mutableMapOf(), userAttributes: MutableMap = mutableMapOf() diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeAttributePropagationTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeAttributePropagationTest.kt index 8988099d12..a89a7692f0 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeAttributePropagationTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeAttributePropagationTest.kt @@ -27,6 +27,7 @@ import com.datadog.android.rum.internal.instrumentation.insights.InsightsCollect import com.datadog.android.rum.internal.metric.SessionMetricDispatcher import com.datadog.android.rum.internal.metric.slowframes.SlowFramesListener import com.datadog.android.rum.internal.startup.RumAppStartupTelemetryReporter +import com.datadog.android.rum.internal.timeseries.NoOpTimeseriesCollectorFactory import com.datadog.android.rum.internal.vitals.VitalMonitor import com.datadog.android.rum.metric.interactiontonextview.LastInteractionIdentifier import com.datadog.android.rum.metric.networksettled.InitialResourceIdentifier @@ -215,7 +216,8 @@ internal class RumApplicationScopeAttributePropagationTest { displayInfoProvider = mockDisplayInfoProvider, rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() ) } diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeTest.kt index 966eed2fe3..b5a0faae3d 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumApplicationScopeTest.kt @@ -22,6 +22,7 @@ import com.datadog.android.rum.RumActionType import com.datadog.android.rum.RumSessionListener import com.datadog.android.rum.RumSessionType import com.datadog.android.rum.internal.domain.InfoProvider +import com.datadog.android.rum.internal.domain.RumContext import com.datadog.android.rum.internal.domain.Time import com.datadog.android.rum.internal.domain.accessibility.AccessibilitySnapshotManager import com.datadog.android.rum.internal.domain.battery.BatteryInfo @@ -30,6 +31,7 @@ import com.datadog.android.rum.internal.domain.state.ViewUIPerformanceReport import com.datadog.android.rum.internal.instrumentation.insights.InsightsCollector import com.datadog.android.rum.internal.metric.SessionMetricDispatcher import com.datadog.android.rum.internal.metric.slowframes.SlowFramesListener +import com.datadog.android.rum.internal.timeseries.TimeseriesCollector import com.datadog.android.rum.internal.vitals.VitalMonitor import com.datadog.android.rum.metric.interactiontonextview.LastInteractionIdentifier import com.datadog.android.rum.metric.networksettled.InitialResourceIdentifier @@ -57,6 +59,7 @@ import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.mock +import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.verifyNoInteractions import org.mockito.kotlin.whenever @@ -136,6 +139,12 @@ internal class RumApplicationScopeTest { @Mock lateinit var mockSessionSampler: Sampler + @Mock + lateinit var mockTimeseriesCollectorFactory: TimeseriesCollector.Factory + + @Mock + lateinit var mockTimeseriesCollector: TimeseriesCollector + @StringForgery(regex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") lateinit var fakeApplicationId: String @@ -177,6 +186,7 @@ internal class RumApplicationScopeTest { whenever(mockSessionSampler.getSampleRate()).thenReturn(fakeSampleRate) whenever(mockSessionSampler.sample(any())).thenReturn(true) + whenever(mockTimeseriesCollectorFactory.create(any(), any())) doReturn mockTimeseriesCollector testedScope = RumApplicationScope( applicationId = fakeApplicationId, @@ -199,7 +209,8 @@ internal class RumApplicationScopeTest { displayInfoProvider = mockDisplayInfoProvider, rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = mockTimeseriesCollectorFactory ) } @@ -215,6 +226,37 @@ internal class RumApplicationScopeTest { assertThat(childScope.firstPartyHostHeaderTypeResolver).isSameAs(mockResolver) } + @Test + fun `M propagate timeseriesFactory to every child session W handleEvent { startView, stop, startView }`( + @StringForgery viewKey: String, + @StringForgery viewName: String + ) { + // Given - the initial child session, renewed by an interactive event + val fakeStartViewEvent = RumRawEvent.StartView( + key = RumScopeKey.from(viewKey, viewName), + attributes = emptyMap(), + eventTime = fakeEventTime + ) + testedScope.handleEvent(fakeStartViewEvent, fakeDatadogContext, mockEventWriteScope, mockWriter) + testedScope.handleEvent( + RumRawEvent.StopSession(fakeEventTime), + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) + + // When - a brand new child session scope is created by the application scope + testedScope.handleEvent(fakeStartViewEvent, fakeDatadogContext, mockEventWriteScope, mockWriter) + + // Then - both the initial and the new child session use the factory we gave the application scope + val rumContextCaptor = argumentCaptor() + verify(mockTimeseriesCollectorFactory, times(2)).create(any(), rumContextCaptor.capture()) + assertThat(rumContextCaptor.allValues.map { it.applicationId }) + .containsOnly(fakeApplicationId) + assertThat(rumContextCaptor.firstValue.sessionId) + .isNotEqualTo(rumContextCaptor.secondValue.sessionId) + } + @Test fun `M always return the same applicationId W getRumContext()`() { val context = testedScope.getRumContext() diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExtTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExtTest.kt index 48026d185a..9128bd0b38 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExtTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumEventExtTest.kt @@ -1103,5 +1103,29 @@ internal class RumEventExtTest { assertThat(schemaDeviceType.name).isEqualTo(deviceType.name) } + @ParameterizedTest + @EnumSource(DeviceType::class) + fun `M return schema device type W toTimeseriesCpuSchemaType()`( + deviceType: DeviceType + ) { + // When + val schemaDeviceType = deviceType.toTimeseriesCpuSchemaType() + + // Then + assertThat(schemaDeviceType.name).isEqualTo(deviceType.name) + } + + @ParameterizedTest + @EnumSource(DeviceType::class) + fun `M return schema device type W toTimeseriesMemorySchemaType()`( + deviceType: DeviceType + ) { + // When + val schemaDeviceType = deviceType.toTimeseriesMemorySchemaType() + + // Then + assertThat(schemaDeviceType.name).isEqualTo(deviceType.name) + } + // endregion } diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScopeTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScopeTest.kt index b856bf4d82..f376b60801 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScopeTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumSessionScopeTest.kt @@ -37,6 +37,8 @@ import com.datadog.android.rum.internal.startup.RumSessionScopeStartupManager import com.datadog.android.rum.internal.startup.RumStartupScenario import com.datadog.android.rum.internal.startup.RumTTIDInfo import com.datadog.android.rum.internal.startup.testRumStartupScenarios +import com.datadog.android.rum.internal.timeseries.NoOpTimeseriesCollectorFactory +import com.datadog.android.rum.internal.timeseries.TimeseriesCollector import com.datadog.android.rum.internal.vitals.VitalMonitor import com.datadog.android.rum.metric.interactiontonextview.LastInteractionIdentifier import com.datadog.android.rum.metric.networksettled.InitialResourceIdentifier @@ -57,6 +59,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.Extensions import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource import org.mockito.Mock import org.mockito.Mockito @@ -191,12 +194,19 @@ internal class RumSessionScopeTest { @Mock private lateinit var mockRumSessionScopeStartupManager: RumSessionScopeStartupManager + @Mock + private lateinit var mockTimeseriesCollectorFactory: TimeseriesCollector.Factory + + @Mock + private lateinit var mockTimeseriesCollector: TimeseriesCollector + private lateinit var stubTimeProvider: StubTimeProvider @BeforeEach fun `set up`(forge: Forge) { stubTimeProvider = StubTimeProvider(elapsedTimeNs = TEST_INACTIVITY_NS + 1) fakeInitialViewEvent = forge.startViewEvent() + fakeParentContext = fakeParentContext.copy(viewType = RumViewType.NONE) whenever(mockParentScope.getRumContext()).doAnswer { fakeParentContext } whenever(mockChildScope.handleEvent(any(), any(), any(), any())) doReturn mockChildScope @@ -218,6 +228,7 @@ internal class RumSessionScopeTest { whenever(mockDisplayInfoProvider.getState()) doReturn fakeDisplayInfo whenever(mockSessionSampler.sample(any())).thenReturn(true) whenever(mockSessionSampler.getSampleRate()).thenReturn(100f) + whenever(mockTimeseriesCollectorFactory.create(any(), any())) doReturn mockTimeseriesCollector fakeParentAttributes = forge.exhaustiveAttributes() whenever(mockParentScope.getCustomAttributes()) doReturn fakeParentAttributes @@ -369,25 +380,25 @@ internal class RumSessionScopeTest { assertThat(context.isSessionActive).isFalse } - fun `M return scope from handleEvent W stopped { with active child scopes }`() { + @Test + fun `M return session scope from handleEvent W stopped { with active child scopes }`() { // Given whenever( mockChildScope.handleEvent( any(), - fakeDatadogContext, - mockEventWriteScope, - mockWriter + eq(fakeDatadogContext), + eq(mockEventWriteScope), + eq(mockWriter) ) ) doReturn mockChildScope // When - val result = - testedScope.handleEvent( - RumRawEvent.StopSession(eventTime = currentFakeTime()), - fakeDatadogContext, - mockEventWriteScope, - mockWriter - ) + val result = testedScope.handleEvent( + RumRawEvent.StopSession(eventTime = currentFakeTime()), + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) // Then assertThat(result).isSameAs(testedScope) @@ -1839,6 +1850,248 @@ internal class RumSessionScopeTest { // endregion + // region Timeseries + + @Test + fun `M start timeseries with session context W renewSession { keepSession = true, no active view }`( + forge: Forge + ) { + // Given + initializeTestedScope(timeseriesCollectorFactory = mockTimeseriesCollectorFactory) + + // When + testedScope.handleEvent( + forge.startViewEvent(), + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) + + // Then + val rumContextCaptor = argumentCaptor() + verify(mockTimeseriesCollectorFactory).create(any(), rumContextCaptor.capture()) + assertThat(rumContextCaptor.firstValue).isEqualTo(testedScope.getRumContext()) + verify(mockTimeseriesCollector).onSessionStart() + } + + @Test + fun `M pass active view context to factory W renewSession { foreground view active }`(forge: Forge) { + // Given + val mockViewScope = mock() + val fakeViewContext = forge.getForgery().copy(viewType = RumViewType.FOREGROUND) + whenever(mockChildScope.activeView) doReturn mockViewScope + whenever(mockViewScope.getRumContext()) doReturn fakeViewContext + initializeTestedScope(timeseriesCollectorFactory = mockTimeseriesCollectorFactory) + + // When + testedScope.handleEvent(forge.startViewEvent(), fakeDatadogContext, mockEventWriteScope, mockWriter) + + // Then — the view context, not the session scope one (which has viewType NONE) + val rumContextCaptor = argumentCaptor() + verify(mockTimeseriesCollectorFactory).create(any(), rumContextCaptor.capture()) + assertThat(rumContextCaptor.firstValue).isEqualTo(fakeViewContext) + assertThat(rumContextCaptor.firstValue).isNotEqualTo(testedScope.getRumContext()) + } + + @ParameterizedTest + @MethodSource("sessionTypeResolutions") + fun `M pass resolved session type to factory W renewSession`( + fakeSyntheticsTestId: String?, + fakeSyntheticsResultId: String?, + fakeSessionTypeOverride: RumSessionType?, + expectedSessionType: RumSessionType, + forge: Forge + ) { + // Given + fakeParentContext = fakeParentContext.copy( + syntheticsTestId = fakeSyntheticsTestId, + syntheticsResultId = fakeSyntheticsResultId + ) + initializeTestedScope( + timeseriesCollectorFactory = mockTimeseriesCollectorFactory, + rumSessionTypeOverride = fakeSessionTypeOverride + ) + + // When + testedScope.handleEvent(forge.startViewEvent(), fakeDatadogContext, mockEventWriteScope, mockWriter) + + // Then + verify(mockTimeseriesCollectorFactory).create(eq(expectedSessionType), any()) + } + + @Test + fun `M not start timeseries W renewSession { keepSession = false }`(forge: Forge) { + // Given + whenever(mockSessionSampler.sample(any())).thenReturn(false) + initializeTestedScope(timeseriesCollectorFactory = mockTimeseriesCollectorFactory) + + // When + testedScope.handleEvent( + forge.startViewEvent(), + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) + + // Then + verify(mockTimeseriesCollectorFactory, never()).create(any(), any()) + verify(mockTimeseriesCollector, never()).onSessionStart() + } + + @Test + fun `M stop previous and feed fresh timeseries W renewSession { another tracked session }`(forge: Forge) { + // Given + val mockViewScope = mock() + val fakeViewContext = forge.getForgery().copy(viewType = RumViewType.FOREGROUND) + whenever(mockChildScope.activeView) doReturn mockViewScope + whenever(mockViewScope.getRumContext()) doReturn fakeViewContext + initializeTestedScope(timeseriesCollectorFactory = mockTimeseriesCollectorFactory) + testedScope.handleEvent(forge.startViewEvent(), fakeDatadogContext, mockEventWriteScope, mockWriter) + val firstTimeseriesCollector = mockTimeseriesCollector + val secondTimeseriesCollector: TimeseriesCollector = mock() + whenever(mockTimeseriesCollectorFactory.create(any(), any())) doReturn secondTimeseriesCollector + + // When — second session via inactivity expiration + advanceTimeByMs(TEST_INACTIVITY_MS) + testedScope.handleEvent(forge.startViewEvent(), fakeDatadogContext, mockEventWriteScope, mockWriter) + + // Then — one timeseries per tracked session, updates go to the live one only + verify(mockTimeseriesCollectorFactory, times(2)).create(any(), any()) + verify(firstTimeseriesCollector).onSessionStop() + verify(firstTimeseriesCollector, times(1)).onRumContextUpdate(fakeViewContext) + verify(secondTimeseriesCollector).onSessionStart() + verify(secondTimeseriesCollector).onRumContextUpdate(fakeViewContext) + } + + @Test + fun `M stop timeseries W handleEvent { session expires without renewal }`(forge: Forge) { + // Given + initializeTestedScope( + backgroundTrackingEnabled = false, + timeseriesCollectorFactory = mockTimeseriesCollectorFactory + ) + testedScope.handleEvent( + forge.startViewEvent(), + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) + + // When + advanceTimeByMs(TEST_INACTIVITY_MS) + testedScope.handleEvent(mock(), fakeDatadogContext, mockEventWriteScope, mockWriter) + + // Then + assertThat(testedScope.sessionState).isEqualTo(RumSessionScope.State.EXPIRED) + verify(mockTimeseriesCollector).onSessionStop() + } + + @Test + fun `M stop timeseries W handleEvent { StopSession }`(forge: Forge) { + // Given + initializeTestedScope(timeseriesCollectorFactory = mockTimeseriesCollectorFactory) + testedScope.handleEvent( + forge.startViewEvent(), + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) + + // When + testedScope.handleEvent( + RumRawEvent.StopSession(eventTime = currentFakeTime()), + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) + + // Then + verify(mockTimeseriesCollector).onSessionStop() + } + + @Test + fun `M pass session context W onRumContextUpdate() { no active view }`(forge: Forge) { + // Given — activeView is null by default (mockChildScope.activeView not stubbed) + initializeTestedScope(timeseriesCollectorFactory = mockTimeseriesCollectorFactory) + testedScope.handleEvent(forge.startViewEvent(), fakeDatadogContext, mockEventWriteScope, mockWriter) + + // When + testedScope.handleEvent(forge.addErrorEvent(), fakeDatadogContext, mockEventWriteScope, mockWriter) + + // Then — the session scope context, once per handled event + val rumContextCaptor = argumentCaptor() + verify(mockTimeseriesCollector, times(2)).onRumContextUpdate(rumContextCaptor.capture()) + assertThat(rumContextCaptor.allValues).containsOnly(testedScope.getRumContext()) + } + + @Test + fun `M pass active view context W onRumContextUpdate() { StartView creates a foreground view }`(forge: Forge) { + // Given — a real view manager child scope, so the context comes from an actual RumViewScope + initializeTestedScope( + withMockChildScope = false, + timeseriesCollectorFactory = mockTimeseriesCollectorFactory + ) + val fakeStartViewEvent = forge.startViewEvent() + + // When + testedScope.handleEvent( + fakeStartViewEvent, + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) + + // Then + val rumContextCaptor = argumentCaptor() + verify(mockTimeseriesCollector).onRumContextUpdate(rumContextCaptor.capture()) + assertThat(rumContextCaptor.firstValue.viewType).isEqualTo(RumViewType.FOREGROUND) + assertThat(rumContextCaptor.firstValue.viewName).isEqualTo(fakeStartViewEvent.key.name) + assertThat(rumContextCaptor.firstValue.viewId).isNotNull + assertThat(rumContextCaptor.firstValue.sessionId).isEqualTo(testedScope.sessionId) + } + + @Test + fun `M stop previous timeseries W handleEvent { ResetSession }`(forge: Forge) { + // Given + initializeTestedScope(timeseriesCollectorFactory = mockTimeseriesCollectorFactory) + testedScope.handleEvent(forge.startViewEvent(), fakeDatadogContext, mockEventWriteScope, mockWriter) + val firstTimeseriesCollector = mockTimeseriesCollector + val secondTimeseriesCollector: TimeseriesCollector = mock() + whenever(mockTimeseriesCollectorFactory.create(any(), any())) doReturn secondTimeseriesCollector + + // When + testedScope.handleEvent( + RumRawEvent.ResetSession(eventTime = currentFakeTime()), + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) + + // Then + verify(firstTimeseriesCollector).onSessionStop() + verify(secondTimeseriesCollector).onSessionStart() + } + + @Test + fun `M not create timeseries W handleEvent { StopSession, no tracked session }`() { + // Given + initializeTestedScope(timeseriesCollectorFactory = mockTimeseriesCollectorFactory) + + // When + testedScope.handleEvent( + RumRawEvent.StopSession(eventTime = currentFakeTime()), + fakeDatadogContext, + mockEventWriteScope, + mockWriter + ) + + // Then + verify(mockTimeseriesCollectorFactory, never()).create(any(), any()) + verifyNoInteractions(mockTimeseriesCollector) + } + + // endregion + // region Internal private fun advanceTimeByMs(ms: Long) { @@ -1855,7 +2108,9 @@ internal class RumSessionScopeTest { private fun initializeTestedScope( sessionSampler: Sampler = mockSessionSampler, withMockChildScope: Boolean = true, - backgroundTrackingEnabled: Boolean? = null + backgroundTrackingEnabled: Boolean? = null, + timeseriesCollectorFactory: TimeseriesCollector.Factory = NoOpTimeseriesCollectorFactory(), + rumSessionTypeOverride: RumSessionType? = fakeRumSessionType ) { testedScope = RumSessionScope( parentScope = mockParentScope, @@ -1876,13 +2131,14 @@ internal class RumSessionScopeTest { slowFramesListener = mockSlowFramesListener, sessionInactivityNanos = TEST_INACTIVITY_NS, sessionMaxDurationNanos = TEST_MAX_DURATION_NS, - rumSessionTypeOverride = fakeRumSessionType, + rumSessionTypeOverride = rumSessionTypeOverride, accessibilitySnapshotManager = mockAccessibilitySnapshotManager, batteryInfoProvider = mockBatteryInfoProvider, displayInfoProvider = mockDisplayInfoProvider, rumSessionScopeStartupManagerFactory = { mockRumSessionScopeStartupManager }, insightsCollector = mockInsightsCollector, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = timeseriesCollectorFactory ) if (withMockChildScope) { @@ -1901,6 +2157,27 @@ internal class RumSessionScopeTest { private val TEST_INACTIVITY_NS = TimeUnit.MILLISECONDS.toNanos(TEST_INACTIVITY_MS) private val TEST_MAX_DURATION_NS = TimeUnit.MILLISECONDS.toNanos(TEST_MAX_DURATION_MS) + private const val FAKE_SYNTHETICS_TEST_ID = "fake-synthetics-test-id" + private const val FAKE_SYNTHETICS_RESULT_ID = "fake-synthetics-result-id" + + // syntheticsTestId, syntheticsResultId, rumSessionTypeOverride, expected session type + @JvmStatic + fun sessionTypeResolutions(): List = listOf( + Arguments.of(null, null, null, RumSessionType.USER), + Arguments.of(FAKE_SYNTHETICS_TEST_ID, FAKE_SYNTHETICS_RESULT_ID, null, RumSessionType.SYNTHETICS), + Arguments.of(null, FAKE_SYNTHETICS_RESULT_ID, null, RumSessionType.USER), + Arguments.of(FAKE_SYNTHETICS_TEST_ID, null, null, RumSessionType.USER), + Arguments.of(" ", FAKE_SYNTHETICS_RESULT_ID, null, RumSessionType.USER), + Arguments.of(FAKE_SYNTHETICS_TEST_ID, " ", null, RumSessionType.USER), + Arguments.of( + FAKE_SYNTHETICS_TEST_ID, + FAKE_SYNTHETICS_RESULT_ID, + RumSessionType.USER, + RumSessionType.USER + ), + Arguments.of(null, null, RumSessionType.SYNTHETICS, RumSessionType.SYNTHETICS) + ) + @JvmStatic fun testScenarios(): List { val forge = Forge().apply { diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt index 97008a66d4..0988755d0a 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt @@ -10604,8 +10604,8 @@ internal class RumViewScopeTest { assertThat(profilerEvent.rumContext.applicationId).isEqualTo(writtenVital.application.id) assertThat(profilerEvent.rumContext.sessionId).isEqualTo(writtenVital.session.id) - assertThat(profilerEvent.rumContext.viewId).isEqualTo(writtenVital.view.id) - assertThat(profilerEvent.rumContext.viewName).isEqualTo(writtenVital.view.name) + assertThat(profilerEvent.rumContext.viewId).isEqualTo(writtenVital.view?.id) + assertThat(profilerEvent.rumContext.viewName).isEqualTo(writtenVital.view?.name) } @Test diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt index 6a5ccacc06..7909bcda4b 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt @@ -56,6 +56,7 @@ import com.datadog.android.rum.internal.metric.slowframes.SlowFramesListener import com.datadog.android.rum.internal.monitor.DatadogRumMonitor.Companion.OPERATION_ERROR_INVALID_NAME import com.datadog.android.rum.internal.monitor.DatadogRumMonitor.Companion.OPERATION_ERROR_INVALID_NAME_CHARACTERS import com.datadog.android.rum.internal.monitor.DatadogRumMonitor.Companion.OPERATION_ERROR_INVALID_OPERATION_KEY +import com.datadog.android.rum.internal.timeseries.NoOpTimeseriesCollectorFactory import com.datadog.android.rum.internal.vitals.VitalMonitor import com.datadog.android.rum.metric.interactiontonextview.LastInteractionIdentifier import com.datadog.android.rum.metric.networksettled.InitialResourceIdentifier @@ -316,7 +317,8 @@ internal class DatadogRumMonitorTest { rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, appPackageName = fakeApplicationPackageName, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() ) testedMonitor.rootScope = mockApplicationScope } @@ -350,7 +352,8 @@ internal class DatadogRumMonitorTest { rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, appPackageName = fakeApplicationPackageName, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() ) // When @@ -427,7 +430,8 @@ internal class DatadogRumMonitorTest { rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, appPackageName = fakeApplicationPackageName, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() ) testedMonitor.start() val mockCallback = mock<(String?) -> Unit>() @@ -472,7 +476,8 @@ internal class DatadogRumMonitorTest { rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, appPackageName = fakeApplicationPackageName, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() ) testedMonitor.start() val mockCallback = mock<(String?) -> Unit>() @@ -2154,9 +2159,7 @@ internal class DatadogRumMonitorTest { } @Test - fun `M delegate event to rootScope W eventDropped {error}`( - @StringForgery viewId: String - ) { + fun `M delegate event to rootScope W eventDropped {error}`(@StringForgery viewId: String) { testedMonitor.eventDropped(viewId, StorageEvent.Error()) argumentCaptor { @@ -2291,7 +2294,8 @@ internal class DatadogRumMonitorTest { rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, appPackageName = fakeApplicationPackageName, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() ) // When @@ -2333,7 +2337,8 @@ internal class DatadogRumMonitorTest { rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, appPackageName = fakeApplicationPackageName, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() ) // When @@ -2376,7 +2381,8 @@ internal class DatadogRumMonitorTest { rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, appPackageName = fakeApplicationPackageName, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() ) whenever(mockExecutorService.isShutdown).thenReturn(true) @@ -2601,7 +2607,8 @@ internal class DatadogRumMonitorTest { rumSessionScopeStartupManagerFactory = mock(), insightsCollector = mockInsightsCollector, appPackageName = fakeApplicationPackageName, - heatmapIdentifierRegistry = null + heatmapIdentifierRegistry = null, + timeseriesCollectorFactory = NoOpTimeseriesCollectorFactory() ) testedMonitor.startView(key, name, attributes) // When @@ -3030,6 +3037,23 @@ internal class DatadogRumMonitorTest { // endregion + // region timeseries + + @Test + fun `M stop the active session timeseries W stopTimeseries()`() { + // Given + val mockSessionScope = mock() + whenever(mockApplicationScope.activeSession) doReturn mockSessionScope + + // When + testedMonitor.stopTimeseries() + + // Then + verify(mockSessionScope).stopTimeseries() + } + + // endregion + @OptIn(ExperimentalRumApi::class) @Test fun `M produce StartOperation event W startOperation`( diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/BufferTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/BufferTest.kt new file mode 100644 index 0000000000..fc390c59b1 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/BufferTest.kt @@ -0,0 +1,119 @@ +/* + * 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.rum.internal.timeseries + +import com.datadog.android.rum.utils.forge.Configurator +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.annotation.IntForgery +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions + +@Extensions( + ExtendWith(ForgeExtension::class) +) +@ForgeConfiguration(Configurator::class) +internal class BufferTest { + + @Test + fun `M return false W isFull() { buffer is empty }`(@IntForgery(min = 1, max = 256) fakeSize: Int) { + // Given + val testedBuffer = Buffer(fakeSize) + + // When / Then + assertThat(testedBuffer.isFull()).isFalse() + } + + @Test + fun `M return false W isFull() { items below capacity }`( + @IntForgery(min = 2, max = 256) fakeSize: Int, + forge: Forge + ) { + // Given + val testedBuffer = Buffer(fakeSize) + repeat(fakeSize - 1) { testedBuffer.add(forge.getForgery>()) } + + // When / Then + assertThat(testedBuffer.isFull()).isFalse() + } + + @Test + fun `M return true W isFull() { items at capacity }`(@IntForgery(min = 1, max = 256) fakeSize: Int, forge: Forge) { + // Given + val testedBuffer = Buffer(fakeSize) + repeat(fakeSize) { testedBuffer.add(forge.getForgery>()) } + + // When / Then + assertThat(testedBuffer.isFull()).isTrue() + } + + @Test + fun `M return true W isFull() { items beyond capacity }`( + @IntForgery(min = 1, max = 64) fakeSize: Int, + @IntForgery(min = 1, max = 8) fakeOverflow: Int, + forge: Forge + ) { + // Given + val testedBuffer = Buffer(fakeSize) + repeat(fakeSize + fakeOverflow) { testedBuffer.add(forge.getForgery>()) } + + // When / Then + assertThat(testedBuffer.isFull()).isTrue() + } + + @Test + fun `M return empty list W drain() { buffer is empty }`(@IntForgery(min = 1, max = 256) fakeSize: Int) { + // Given + val testedBuffer = Buffer(fakeSize) + + // When + val result = testedBuffer.drain() + + // Then + assertThat(result).isEmpty() + } + + @Test + fun `M return all items and clear W drain() { buffer not empty }`( + @IntForgery(min = 1, max = 16) fakeSize: Int, + forge: Forge + ) { + // Given + val testedBuffer = Buffer(fakeSize) + val fakePoints = (0 until fakeSize).map { forge.getForgery>() } + fakePoints.forEach { testedBuffer.add(it) } + + // When + val drained = testedBuffer.drain() + + // Then + assertThat(drained).containsExactlyElementsOf(fakePoints) + assertThat(testedBuffer.isFull()).isFalse() + assertThat(testedBuffer.drain()).isEmpty() + } + + @Test + fun `M return a detached copy W drain() { buffer is reused afterwards }`( + @IntForgery(min = 2, max = 16) fakeSize: Int, + forge: Forge + ) { + // Given + val testedBuffer = Buffer(fakeSize) + val fakePoints = (0 until fakeSize).map { forge.getForgery>() } + fakePoints.forEach { testedBuffer.add(it) } + val drained = testedBuffer.drain() + + // When + testedBuffer.add(forge.getForgery>()) + + // Then + assertThat(drained).containsExactlyElementsOf(fakePoints) + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollectorFactoryTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollectorFactoryTest.kt new file mode 100644 index 0000000000..3c1cc4e9e5 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollectorFactoryTest.kt @@ -0,0 +1,279 @@ +/* + * 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.rum.internal.timeseries + +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.feature.FeatureSdkCore +import com.datadog.android.api.storage.DataWriter +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.ExperimentalRumApi +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.internal.domain.InfoProvider +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.domain.battery.BatteryInfo +import com.datadog.android.rum.internal.domain.display.DisplayInfo +import com.datadog.android.rum.internal.instrumentation.insights.InsightsCollector +import com.datadog.android.rum.internal.timeseries.factory.CpuEventFactory +import com.datadog.android.rum.internal.timeseries.factory.MemoryEventFactory +import com.datadog.android.rum.timeseries.TimeseriesConfiguration +import com.datadog.android.rum.timeseries.TimeseriesType +import com.datadog.android.rum.utils.forge.Configurator +import com.datadog.android.utils.verifyLog +import com.datadog.tools.unit.getFieldValue +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.annotation.Forgery +import fr.xgouchet.elmyr.annotation.LongForgery +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.verifyNoInteractions +import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness +import java.util.concurrent.ScheduledExecutorService + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +@OptIn(ExperimentalRumApi::class) +internal class DefaultTimeseriesCollectorFactoryTest { + + @Mock + lateinit var mockSdkCore: FeatureSdkCore + + @Mock + lateinit var mockInternalLogger: InternalLogger + + @Mock + lateinit var mockTimeProvider: TimeProvider + + @Mock + lateinit var mockWriter: DataWriter + + @Mock + lateinit var mockExecutor: ScheduledExecutorService + + @Mock + lateinit var mockInsightsCollector: InsightsCollector + + @Mock + lateinit var mockBatteryInfoProvider: InfoProvider + + @Mock + lateinit var mockDisplayInfoProvider: InfoProvider + + @Forgery + lateinit var fakeRumContext: RumContext + + lateinit var fakeSessionType: RumSessionType + + @BeforeEach + fun `set up`(forge: Forge) { + whenever(mockSdkCore.internalLogger) doReturn mockInternalLogger + whenever(mockSdkCore.timeProvider) doReturn mockTimeProvider + + fakeSessionType = forge.aValueFrom(RumSessionType::class.java) + } + + private fun createFactory( + totalRamBytes: Long, + configuration: TimeseriesConfiguration = TimeseriesConfiguration.Builder().build() + ) = DefaultTimeseriesCollectorFactory( + sdkCore = mockSdkCore, + configuration = configuration, + scheduledExecutorService = mockExecutor, + insightsCollector = mockInsightsCollector, + totalRamBytes = totalRamBytes, + dataWriter = mockWriter, + batteryInfoProvider = mockBatteryInfoProvider, + displayInfoProvider = mockDisplayInfoProvider + ) + + @Test + fun `M build cpu and memory pipelines W create() { totalRamBytes greater than zero }`( + @LongForgery(min = 1L) fakeTotalRamBytes: Long + ) { + // Given + val testedFactory = createFactory(fakeTotalRamBytes) + + // When + val timeseries = testedFactory.create(fakeSessionType, fakeRumContext) + + // Then + check(timeseries is DefaultTimeseriesCollector) + assertThat(timeseries.pipelines).hasSize(2) + } + + @Test + fun `M use default sampling settings W create()`( + @LongForgery(min = 1L) fakeTotalRamBytes: Long + ) { + // Given + val testedFactory = createFactory(fakeTotalRamBytes) + + // When + val timeseries = testedFactory.create(fakeSessionType, fakeRumContext) + + // Then + check(timeseries is DefaultTimeseriesCollector) + assertThat(timeseries.pipelines.map { it.intervalMs }) + .containsOnly(TimeseriesConfiguration.DEFAULT_INTERVAL_MS) + assertThat( + timeseries.pipelines.map { pipeline -> + pipeline.getFieldValue, Pipeline<*>>("buffer") + .getFieldValue>("size") + } + ).containsOnly(TimeseriesConfiguration.DEFAULT_BUFFER_SIZE) + } + + @Test + fun `M build only cpu pipeline W create() { totalRamBytes is zero }`() { + // Given + val testedFactory = createFactory(0L) + + // When + val timeseries = testedFactory.create(fakeSessionType, fakeRumContext) + + // Then + check(timeseries is DefaultTimeseriesCollector) + assertThat(timeseries.pipelines).hasSize(1) + mockInternalLogger.verifyLog( + InternalLogger.Level.WARN, + InternalLogger.Target.USER, + DefaultTimeseriesCollectorFactory.MEMORY_TIMESERIES_DISABLED_MESSAGE, + onlyOnce = true + ) + } + + @Test + fun `M build only cpu pipeline W create() { configuration collects only cpu }`() { + // Given + val fakeConfiguration = TimeseriesConfiguration.Builder() + .collectOnly(TimeseriesType.CPU) + .build() + val testedFactory = createFactory(0L, fakeConfiguration) + + // When + val timeseries = testedFactory.create(fakeSessionType, fakeRumContext) + + // Then + check(timeseries is DefaultTimeseriesCollector) + assertThat(timeseries.pipelines).hasSize(1) + val eventFactory = timeseries.pipelines.single() + .getFieldValue>("eventFactory") + assertThat(eventFactory).isInstanceOf(CpuEventFactory::class.java) + verifyNoInteractions(mockInternalLogger) + } + + @Test + fun `M build only memory pipeline W create() { configuration collects only memory }`( + @LongForgery(min = 1L) fakeTotalRamBytes: Long + ) { + // Given + val fakeConfiguration = TimeseriesConfiguration.Builder() + .collectOnly(TimeseriesType.MEMORY) + .build() + val testedFactory = createFactory(fakeTotalRamBytes, fakeConfiguration) + + // When + val timeseries = testedFactory.create(fakeSessionType, fakeRumContext) + + // Then + check(timeseries is DefaultTimeseriesCollector) + assertThat(timeseries.pipelines).hasSize(1) + val eventFactory = timeseries.pipelines.single() + .getFieldValue>("eventFactory") + assertThat(eventFactory).isInstanceOf(MemoryEventFactory::class.java) + } + + @Test + fun `M build no pipelines W create() { configuration collects no types }`( + @LongForgery(min = 1L) fakeTotalRamBytes: Long + ) { + // Given + val fakeConfiguration = TimeseriesConfiguration.Builder() + .collectOnly(*emptyArray()) + .build() + val testedFactory = createFactory(fakeTotalRamBytes, fakeConfiguration) + + // When + val timeseries = testedFactory.create(fakeSessionType, fakeRumContext) + + // Then + check(timeseries is DefaultTimeseriesCollector) + assertThat(timeseries.pipelines).isEmpty() + } + + @Test + fun `M propagate executor and rum context to the collector W create()`( + @LongForgery(min = 1L) fakeTotalRamBytes: Long + ) { + // Given + val testedFactory = createFactory(fakeTotalRamBytes) + + // When + val timeseries = testedFactory.create(fakeSessionType, fakeRumContext) + + // Then + check(timeseries is DefaultTimeseriesCollector) + assertThat(timeseries.scheduledExecutorService).isSameAs(mockExecutor) + assertThat( + timeseries.getFieldValue("rumContext") + ).isSameAs(fakeRumContext) + } + + @Test + fun `M propagate session type and info providers to both factories W create()`( + @LongForgery(min = 1L) fakeTotalRamBytes: Long + ) { + // Given + val testedFactory = createFactory(fakeTotalRamBytes) + + // When + val timeseries = testedFactory.create(fakeSessionType, fakeRumContext) + + // Then + check(timeseries is DefaultTimeseriesCollector) + val cpuEventFactory = timeseries.pipelines[0] + .getFieldValue>("eventFactory") + val memoryEventFactory = timeseries.pipelines[1] + .getFieldValue>("eventFactory") + + assertThat( + cpuEventFactory.getFieldValue("sessionType") + ).isEqualTo(fakeSessionType) + assertThat( + cpuEventFactory.getFieldValue, CpuEventFactory>("batteryInfoProvider") + ).isSameAs(mockBatteryInfoProvider) + assertThat( + cpuEventFactory.getFieldValue, CpuEventFactory>("displayInfoProvider") + ).isSameAs(mockDisplayInfoProvider) + + assertThat( + memoryEventFactory.getFieldValue("sessionType") + ).isEqualTo(fakeSessionType) + assertThat( + memoryEventFactory.getFieldValue("totalRamBytes") + ).isEqualTo(fakeTotalRamBytes) + assertThat( + memoryEventFactory.getFieldValue, MemoryEventFactory>("batteryInfoProvider") + ).isSameAs(mockBatteryInfoProvider) + assertThat( + memoryEventFactory.getFieldValue, MemoryEventFactory>("displayInfoProvider") + ).isSameAs(mockDisplayInfoProvider) + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollectorTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollectorTest.kt new file mode 100644 index 0000000000..83c58d0e12 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/DefaultTimeseriesCollectorTest.kt @@ -0,0 +1,849 @@ +/* + * 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.rum.internal.timeseries + +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.api.feature.EventWriteScope +import com.datadog.android.api.feature.Feature +import com.datadog.android.api.feature.FeatureScope +import com.datadog.android.api.feature.FeatureSdkCore +import com.datadog.android.api.storage.DataWriter +import com.datadog.android.api.storage.EventBatchWriter +import com.datadog.android.api.storage.EventType +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.domain.scope.RumViewType +import com.datadog.android.rum.internal.timeseries.factory.EventFactory +import com.datadog.android.rum.internal.timeseries.provider.DataPointsReader +import com.datadog.android.rum.utils.forge.Configurator +import com.datadog.android.utils.verifyLog +import com.datadog.tools.unit.setFieldValue +import com.google.gson.JsonObject +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.annotation.Forgery +import fr.xgouchet.elmyr.annotation.IntForgery +import fr.xgouchet.elmyr.annotation.LongForgery +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.atLeastOnce +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doThrow +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoInteractions +import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness +import java.util.UUID +import java.util.concurrent.ScheduledExecutorService +import java.util.concurrent.TimeUnit + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +internal class DefaultTimeseriesCollectorTest { + + private lateinit var testedTimeseriesCollector: DefaultTimeseriesCollector + + @Mock + lateinit var mockDataWriter: DataWriter + + @Mock + lateinit var mockInternalLogger: InternalLogger + + @Mock + lateinit var mockSdkCore: FeatureSdkCore + + @Mock + lateinit var mockRumFeatureScope: FeatureScope + + @Mock + lateinit var mockEventWriteScope: EventWriteScope + + @Mock + lateinit var mockEventBatchWriter: EventBatchWriter + + @Mock + lateinit var mockDatadogContext: DatadogContext + + @Mock + lateinit var mockExecutor: ScheduledExecutorService + + @Mock + lateinit var mockReaderA: DataPointsReader + + @Mock + lateinit var mockReaderB: DataPointsReader + + @Mock + lateinit var mockEventFactoryA: EventFactory + + @Mock + lateinit var mockEventFactoryB: EventFactory + + private lateinit var bufferA: Buffer + private lateinit var bufferB: Buffer + + private lateinit var pipelineA: Pipeline + private lateinit var pipelineB: Pipeline + + @LongForgery(min = 1_000L, max = 60_000L) + var fakeIntervalAMs: Long = 0L + + @LongForgery(min = 60_001L, max = 120_000L) + var fakeIntervalBMs: Long = 0L + + @IntForgery(min = 2, max = 16) + var fakeBufferSize: Int = 0 + + @Forgery + lateinit var fakeRumContext: RumContext + + private fun fakeRumContextOf(viewType: RumViewType) = fakeRumContext.copy(viewType = viewType) + + private fun createTimeseries( + initialViewType: RumViewType, + pipelines: List> = listOf(pipelineA, pipelineB) + ) = createTimeseries(fakeRumContextOf(initialViewType), pipelines) + + private fun createTimeseries( + initialRumContext: RumContext, + pipelines: List> = listOf(pipelineA, pipelineB) + ) = DefaultTimeseriesCollector( + pipelines = pipelines, + internalLogger = mockInternalLogger, + scheduledExecutorService = mockExecutor, + rumContext = initialRumContext + ) + + // Single foreground pipeline wired to reader/event factory A, with a buffer the test controls. + private fun createTimeseriesWithBuffer(buffer: Buffer) = createTimeseries( + RumViewType.FOREGROUND, + listOf(Pipeline(mockSdkCore, mockReaderA, buffer, mockEventFactoryA, mockDataWriter)) + ) + + @BeforeEach + fun `set up`() { + whenever(mockReaderA.intervalMs) doReturn fakeIntervalAMs + whenever(mockReaderB.intervalMs) doReturn fakeIntervalBMs + whenever(mockSdkCore.internalLogger) doReturn mockInternalLogger + whenever(mockSdkCore.getFeature(Feature.RUM_FEATURE_NAME)) doReturn mockRumFeatureScope + whenever(mockRumFeatureScope.withWriteContext(any(), any())) doAnswer { inv -> + inv.getArgument<(DatadogContext, EventWriteScope) -> Unit>(inv.arguments.lastIndex) + .invoke(mockDatadogContext, mockEventWriteScope) + } + whenever(mockEventWriteScope.invoke(any())) doAnswer { inv -> + inv.getArgument<(EventBatchWriter) -> Unit>(0).invoke(mockEventBatchWriter) + } + whenever(mockEventFactoryA.eventName) doReturn "" + whenever(mockEventFactoryB.eventName) doReturn "" + + bufferA = Buffer(fakeBufferSize) + bufferB = Buffer(fakeBufferSize) + pipelineA = Pipeline(mockSdkCore, mockReaderA, bufferA, mockEventFactoryA, mockDataWriter) + pipelineB = Pipeline(mockSdkCore, mockReaderB, bufferB, mockEventFactoryB, mockDataWriter) + + testedTimeseriesCollector = createTimeseries(RumViewType.FOREGROUND) + } + + @ParameterizedTest + @EnumSource( + value = RumViewType::class, + names = ["FOREGROUND", "APPLICATION_LAUNCH"] + ) + fun `M schedule one runnable per pipeline W onSessionStart() { initial view is foreground }`( + initialViewType: RumViewType + ) { + // Given + testedTimeseriesCollector = createTimeseries(initialViewType) + + // When + testedTimeseriesCollector.onSessionStart() + + // Then + verify(mockExecutor).schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + verify(mockExecutor).schedule(any(), eq(fakeIntervalBMs), eq(TimeUnit.MILLISECONDS)) + } + + @ParameterizedTest + @EnumSource( + value = RumViewType::class, + names = ["NONE", "BACKGROUND"] + ) + fun `M not schedule W onSessionStart() { initial view is not foreground }`( + initialViewType: RumViewType + ) { + // Given + testedTimeseriesCollector = createTimeseries(initialViewType) + + // When + testedTimeseriesCollector.onSessionStart() + + // Then + verify(mockExecutor, never()).schedule(any(), any(), any()) + } + + @Test + fun `M not schedule W onRumContextUpdate() { none to background }`() { + // Given + testedTimeseriesCollector = createTimeseries(RumViewType.NONE) + testedTimeseriesCollector.onSessionStart() + + // When + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.BACKGROUND)) + + // Then — neither a sampling chain nor a suspend: the app never left the foreground + verify(mockExecutor, never()).schedule(any(), any(), any()) + } + + @ParameterizedTest + @EnumSource( + value = RumViewType::class, + names = ["FOREGROUND", "APPLICATION_LAUNCH"] + ) + fun `M resume scheduling W onRumContextUpdate() { none to foreground }`( + foregroundViewType: RumViewType + ) { + // Given + testedTimeseriesCollector = createTimeseries(RumViewType.NONE) + testedTimeseriesCollector.onSessionStart() + + // When + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(foregroundViewType)) + + // Then + verify(mockExecutor).schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + verify(mockExecutor).schedule(any(), eq(fakeIntervalBMs), eq(TimeUnit.MILLISECONDS)) + } + + @Test + fun `M not shut down shared executor W onSessionStop()`() { + // Given + testedTimeseriesCollector.onSessionStart() + + // When + testedTimeseriesCollector.onSessionStop() + + // Then — executor is owned by the SDK core and reused across components + verify(mockExecutor, never()).shutdown() + verify(mockExecutor, never()).shutdownNow() + } + + @Test + fun `M not write events W onSessionStop() { nothing sampled }`() { + // Given + testedTimeseriesCollector.onSessionStart() + + // When + testedTimeseriesCollector.onSessionStop() + + // Then + verify(mockDataWriter, never()).write(any(), any(), any()) + } + + @Test + fun `M log error and flush remaining pipelines W onSessionStop() { pipeline flush throws }`(forge: Forge) { + // Given — drain() throws outside Pipeline's own try/catch, so the failure surfaces in + // DefaultTimeseriesCollector.flushPipelines() and must not skip the remaining pipelines. + val fakeError = RuntimeException("drain failure") + val fakeJson = JsonObject().apply { addProperty("k", "v") } + val mockBuffer = mock>() + whenever(mockBuffer.drain()) doThrow fakeError + whenever(mockReaderB.read()) doReturn forge.getForgery>() + whenever(mockEventFactoryB.create(any(), any(), any())) doReturn fakeJson + val failingPipeline = + Pipeline(mockSdkCore, mockReaderA, mockBuffer, mockEventFactoryA, mockDataWriter) + testedTimeseriesCollector = createTimeseries(RumViewType.FOREGROUND, listOf(failingPipeline, pipelineB)) + testedTimeseriesCollector.onSessionStart() + captureScheduledRunnableForInterval(fakeIntervalBMs).run() // buffers one sample for pipeline B + + // When + testedTimeseriesCollector.onSessionStop() + + // Then + mockInternalLogger.verifyLog( + InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + DefaultTimeseriesCollector.ERROR_FLUSH_FAILED, + fakeError + ) + verify(mockDataWriter).write(any(), eq(fakeJson), eq(EventType.DEFAULT)) + } + + @Test + fun `M flush partial buffer W onSessionStop() { buffer below capacity }`(forge: Forge) { + // Given + val fakeJson = JsonObject().apply { addProperty("k", "v") } + whenever(mockReaderA.read()) doReturn forge.getForgery>() + whenever(mockEventFactoryA.create(any(), any(), any())) doReturn fakeJson + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + runnableA.run() + + // When + testedTimeseriesCollector.onSessionStop() + + // Then + verify(mockEventFactoryA).create(any(), any(), any()) + verify(mockDataWriter).write(any(), eq(fakeJson), eq(EventType.DEFAULT)) + } + + @Test + fun `M write batch W sample tick { buffer reaches capacity }`(forge: Forge) { + // Given + val fakePoint = forge.getForgery>() + val fakeDataPoints = List(fakeBufferSize) { fakePoint } + val fakeJson = JsonObject().apply { addProperty("a", "1") } + whenever(mockReaderA.read()) doReturn fakePoint + whenever(mockEventFactoryA.create(any(), any(), eq(fakeDataPoints))) doReturn fakeJson + + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + + // When + repeat(fakeBufferSize) { runnableA.run() } + + // Then + verify(mockEventFactoryA).create( + eq(mockDatadogContext), + eq(fakeRumContextOf(RumViewType.FOREGROUND)), + eq(fakeDataPoints) + ) + verify(mockDataWriter).write(any(), eq(fakeJson), eq(EventType.DEFAULT)) + } + + @Test + fun `M reschedule sample W sample tick runs`(forge: Forge) { + // Given + whenever(mockReaderA.read()) doReturn forge.getForgery>() + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + + // When + runnableA.run() + + // Then - 1 schedule from start() + 1 reschedule from sample tick + verify(mockExecutor, times(2)) + .schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + } + + @Test + fun `M not write events W sample tick { buffer not full }`(forge: Forge) { + // Given + whenever(mockReaderA.read()) doReturn forge.getForgery>() + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + + // When + repeat(fakeBufferSize - 1) { runnableA.run() } + + // Then + verify(mockEventFactoryA, never()).create(any(), any(), any()) + verify(mockDataWriter, never()).write(any(), any(), any()) + } + + @Test + fun `M not start twice W onSessionStart() { called twice }`() { + // When + testedTimeseriesCollector.onSessionStart() + testedTimeseriesCollector.onSessionStart() + + // Then — executor.schedule called exactly once per pipeline (not doubled) + verify(mockExecutor).schedule( + any(), + eq(fakeIntervalAMs), + eq(TimeUnit.MILLISECONDS) + ) + verify(mockExecutor).schedule( + any(), + eq(fakeIntervalBMs), + eq(TimeUnit.MILLISECONDS) + ) + } + + @Test + fun `M flush only once W onSessionStop() { called twice }`() { + // Given + val mockBuffer = mock>() + testedTimeseriesCollector = createTimeseriesWithBuffer(mockBuffer) + testedTimeseriesCollector.onSessionStart() + + // When + testedTimeseriesCollector.onSessionStop() + testedTimeseriesCollector.onSessionStop() + + // Then — the second call sees the state already STOPPED and never reaches the pipelines + verify(mockBuffer).drain() + } + + @Test + fun `M log error and reschedule W sample tick { reader throws }`() { + // Given + val fakeError = RuntimeException("reader failure") + whenever(mockReaderA.read()) doThrow fakeError + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + + // When + runnableA.run() + + // Then — 1 schedule from start() + 1 rescheduled via finally after the exception + mockInternalLogger.verifyLog( + InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + DefaultTimeseriesCollector.ERROR_SAMPLING_FAILED, + fakeError + ) + verify(mockExecutor, times(2)) + .schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + } + + @Test + fun `M log error and reschedule W sample tick { buffer drain throws }`(forge: Forge) { + // Given — drain() throws outside Pipeline's own try/catch, so it must be + // caught by DefaultTimeseriesCollector's sampling try/catch instead. + val fakeError = RuntimeException("drain failure") + val mockBuffer = mock>() + whenever(mockBuffer.isFull()) doReturn true + whenever(mockBuffer.drain()) doThrow fakeError + whenever(mockReaderA.read()) doReturn forge.getForgery>() + testedTimeseriesCollector = createTimeseriesWithBuffer(mockBuffer) + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + + // When + runnableA.run() + + // Then + mockInternalLogger.verifyLog( + InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + DefaultTimeseriesCollector.ERROR_SAMPLING_FAILED, + fakeError + ) + verify(mockExecutor, times(2)) + .schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + } + + @Test + fun `M log error and reschedule W sample tick { event factory throws }`(forge: Forge) { + // Given — event factory throws inside Pipeline's own try/catch: Pipeline logs it itself + // and the tick completes normally, so the sampling chain reschedules as usual. + val fakeError = RuntimeException("event factory failure") + whenever(mockReaderA.read()) doReturn forge.getForgery>() + whenever(mockEventFactoryA.create(any(), any(), any())) doThrow fakeError + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + + // When + repeat(fakeBufferSize) { runnableA.run() } + + // Then + // verifyLog matches on `same(fakeError)`, so its default times(1) also proves the + // collector's own sampling catch never logged the same throwable a second time. + mockInternalLogger.verifyLog( + InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + "Timeseries event creation failed", + fakeError + ) + verify(mockDataWriter, never()).write(any(), any(), any()) + verify(mockExecutor, times(fakeBufferSize + 1)) + .schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + } + + @Test + fun `M log error and reschedule W sample tick { write context resolution throws }`(forge: Forge) { + // Given — withWriteContext() itself throws (context/scope resolution failure), outside + // Pipeline's own try/catch, so it propagates up to the sampling try/catch. + val fakeError = RuntimeException("write context resolution failure") + whenever(mockReaderA.read()) doReturn forge.getForgery>() + whenever(mockRumFeatureScope.withWriteContext(any(), any())) doThrow fakeError + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + + // When + repeat(fakeBufferSize) { runnableA.run() } + + // Then + mockInternalLogger.verifyLog( + InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + DefaultTimeseriesCollector.ERROR_SAMPLING_FAILED, + fakeError + ) + verify(mockExecutor, times(fakeBufferSize + 1)) + .schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + } + + @Test + fun `M not sample nor reschedule W sample tick { session stopped }`(forge: Forge) { + // Given + whenever(mockReaderA.read()) doReturn forge.getForgery>() + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + testedTimeseriesCollector.onSessionStop() + + // When + runnableA.run() + + // Then — sample skipped AND no additional schedule after the one from start() + verify(mockReaderA, never()).read() + verify(mockExecutor).schedule( + any(), + eq(fakeIntervalAMs), + eq(TimeUnit.MILLISECONDS) + ) + } + + @ParameterizedTest + @EnumSource( + value = RumViewType::class, + names = ["FOREGROUND", "APPLICATION_LAUNCH"] + ) + fun `M neither flush nor schedule suspend W onRumContextUpdate() { stays foreground }`( + nextViewType: RumViewType, + forge: Forge + ) { + // Given + val fakeNextContext = fakeRumContextOf(nextViewType).copy(viewId = forge.getForgery().toString()) + whenever(mockReaderA.read()) doReturn forge.getForgery>() + testedTimeseriesCollector.onSessionStart() + captureScheduledRunnableForInterval(fakeIntervalAMs).run() // buffers one sample for pipeline A + + // When + testedTimeseriesCollector.onRumContextUpdate(fakeNextContext) + + // Then — no suspend is even scheduled, so nothing can flush later either + verify(mockExecutor, never()) + .schedule(any(), eq(DefaultTimeseriesCollector.SUSPEND_DELAY_MS), eq(TimeUnit.MILLISECONDS)) + verifyNoInteractions(mockEventFactoryA) + verifyNoInteractions(mockDataWriter) + } + + @Test + fun `M use updated context W sample tick fills buffer { foreground view changed }`(forge: Forge) { + // Given + val fakePoint = forge.getForgery>() + val fakeNextContext = fakeRumContextOf(RumViewType.FOREGROUND).copy( + viewId = forge.getForgery().toString() + ) + whenever(mockReaderA.read()) doReturn fakePoint + whenever(mockEventFactoryA.create(any(), eq(fakeNextContext), any())) doReturn JsonObject() + testedTimeseriesCollector.onSessionStart() + testedTimeseriesCollector.onRumContextUpdate(fakeNextContext) + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + + // When + repeat(fakeBufferSize) { runnableA.run() } + + // Then + verify(mockEventFactoryA).create(any(), eq(fakeNextContext), eq(List(fakeBufferSize) { fakePoint })) + } + + @Test + fun `M suspend chain W sample tick { suspend fired after background }`(forge: Forge) { + // Given + whenever(mockReaderA.read()) doReturn forge.getForgery>() + testedTimeseriesCollector.onSessionStart() + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.BACKGROUND)) + runScheduledSuspend() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + + // When + runnableA.run() + + // Then — sample skipped AND no reschedule (chain suspended) + verify(mockReaderA, never()).read() + verify(mockExecutor).schedule( + any(), + eq(fakeIntervalAMs), + eq(TimeUnit.MILLISECONDS) + ) + } + + @ParameterizedTest + @EnumSource( + value = RumViewType::class, + names = ["NONE", "BACKGROUND"] + ) + fun `M flush partial buffer with last foreground context W pending suspend fires { left foreground }`( + nextViewType: RumViewType, + forge: Forge + ) { + // Given + val fakeSample = forge.getForgery>() + val fakeJson = JsonObject().apply { addProperty("k", "v") } + whenever(mockReaderA.read()) doReturn fakeSample + whenever( + mockEventFactoryA.create( + eq(mockDatadogContext), + eq(fakeRumContextOf(RumViewType.FOREGROUND)), + eq(listOf(fakeSample)) + ) + ) doReturn fakeJson + testedTimeseriesCollector.onSessionStart() + captureScheduledRunnableForInterval(fakeIntervalAMs).run() // buffers one sample for pipeline A + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(nextViewType)) + + // When + runScheduledSuspend() + + // Then — the batch is stamped with the view the user was looking at, not the new one + verify(mockEventFactoryA).create( + eq(mockDatadogContext), + eq(fakeRumContextOf(RumViewType.FOREGROUND)), + eq(listOf(fakeSample)) + ) + verify(mockDataWriter).write(mockEventBatchWriter, fakeJson, EventType.DEFAULT) + verify(mockEventFactoryB, never()).create(any(), any(), any()) + } + + @Test + fun `M flush with the context captured on leaving foreground W suspend fires { newer view }`( + forge: Forge + ) { + // Given + val fakeForegroundContext = fakeRumContextOf(RumViewType.FOREGROUND) + val mockPipeline = mock>() + val testedCollector = createTimeseries(fakeForegroundContext, listOf(mockPipeline)) + testedCollector.onSessionStart() + + // When + testedCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.BACKGROUND)) + testedCollector.setFieldValue( + "lastForegroundRumContext", + fakeForegroundContext.copy(viewId = forge.getForgery().toString()) + ) + runScheduledSuspend() + + // Then + verify(mockPipeline).flush(fakeForegroundContext) + } + + @ParameterizedTest + @EnumSource( + value = RumViewType::class, + names = ["NONE", "BACKGROUND"] + ) + fun `M flush with last foreground context W onSessionStop() { left foreground, suspend pending }`( + nextViewType: RumViewType, + forge: Forge + ) { + // Given + val fakeSample = forge.getForgery>() + whenever(mockReaderA.read()) doReturn fakeSample + whenever(mockEventFactoryA.create(any(), any(), any())) doReturn JsonObject() + testedTimeseriesCollector.onSessionStart() + captureScheduledRunnableForInterval(fakeIntervalAMs).run() // buffers one sample for pipeline A + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(nextViewType)) + + // When — the session is stopped before the pending suspend had a chance to flush + testedTimeseriesCollector.onSessionStop() + + // Then — same attribution as the suspend path, not the background context + verify(mockEventFactoryA).create( + eq(mockDatadogContext), + eq(fakeRumContextOf(RumViewType.FOREGROUND)), + eq(listOf(fakeSample)) + ) + } + + @Test + fun `M not flush W onRumContextUpdate() { suspend not fired yet }`(forge: Forge) { + // Given + whenever(mockReaderA.read()) doReturn forge.getForgery>() + testedTimeseriesCollector.onSessionStart() + captureScheduledRunnableForInterval(fakeIntervalAMs).run() // buffers one sample for pipeline A + + // When — leaving the foreground only schedules the suspend, it does not flush inline + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.BACKGROUND)) + + // Then + verify(mockExecutor) + .schedule(any(), eq(DefaultTimeseriesCollector.SUSPEND_DELAY_MS), eq(TimeUnit.MILLISECONDS)) + verifyNoInteractions(mockEventFactoryA) + verifyNoInteractions(mockDataWriter) + } + + @ParameterizedTest + @EnumSource( + value = RumViewType::class, + names = ["NONE", "BACKGROUND"] + ) + fun `M skip sample and reschedule W sample tick { foreground exit is pending }`( + nextViewType: RumViewType + ) { + // Given + testedTimeseriesCollector.onSessionStart() + val runnableA = captureScheduledRunnableForInterval(fakeIntervalAMs) + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(nextViewType)) + + // When + runnableA.run() + + // Then + verify(mockReaderA, never()).read() + verify(mockExecutor, times(2)) + .schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + } + + @Test + fun `M keep sampling chain W stale suspend fires { foreground re-entered then left }`() { + // Given + testedTimeseriesCollector.onSessionStart() + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.NONE)) + val staleSuspend = captureScheduledSuspendRunnable() + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.FOREGROUND)) + val currentRunnableA = captureLastScheduledRunnableForInterval(fakeIntervalAMs) + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.BACKGROUND)) + + // When + staleSuspend.run() + currentRunnableA.run() + + // Then + verify(mockDataWriter, never()).write(any(), any(), any()) + verify(mockReaderA, never()).read() + verify(mockExecutor, times(3)) + .schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + } + + @Test + fun `M not flush W stale suspend fires { foreground re-entered }`() { + // Given + val mockBuffer = mock>() + testedTimeseriesCollector = createTimeseriesWithBuffer(mockBuffer) + testedTimeseriesCollector.onSessionStart() + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.NONE)) + val staleSuspend = captureScheduledSuspendRunnable() + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.FOREGROUND)) + + // When + staleSuspend.run() + + // Then + verify(mockBuffer, never()).drain() + } + + @Test + fun `M schedule suspend once W onRumContextUpdate() { repeated non-foreground updates }`() { + // Given + testedTimeseriesCollector.onSessionStart() + + // When + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.NONE)) + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.BACKGROUND)) + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.NONE)) + + // Then + verify(mockExecutor).schedule( + any(), + eq(DefaultTimeseriesCollector.SUSPEND_DELAY_MS), + eq(TimeUnit.MILLISECONDS) + ) + } + + @Test + fun `M not flush twice W pending suspend fires { session already stopped }`() { + // Given + val mockBuffer = mock>() + testedTimeseriesCollector = createTimeseriesWithBuffer(mockBuffer) + testedTimeseriesCollector.onSessionStart() + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.BACKGROUND)) + testedTimeseriesCollector.onSessionStop() // drains the buffer synchronously + + // When + runScheduledSuspend() + + // Then — the pending suspend loses the CAS against STOPPED and does nothing + verify(mockBuffer).drain() + } + + @Test + fun `M resume scheduling W onRumContextUpdate() { background to foreground }`() { + // Given — the deferred suspend fired, so the next tick dies without rescheduling + testedTimeseriesCollector.onSessionStart() + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.BACKGROUND)) + runScheduledSuspend() + captureScheduledRunnableForInterval(fakeIntervalAMs).run() + verify(mockExecutor, times(1)) + .schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + + // When — app returns to foreground + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.FOREGROUND)) + + // Then — scheduling resumed, one new schedule per pipeline + verify(mockExecutor, times(2)) + .schedule(any(), eq(fakeIntervalAMs), eq(TimeUnit.MILLISECONDS)) + verify(mockExecutor, times(2)) + .schedule(any(), eq(fakeIntervalBMs), eq(TimeUnit.MILLISECONDS)) + } + + @Test + fun `M not sample nor reschedule W stale tick fires { new generation is running }`() { + // Regression: a tick from the generation that was alive before the suspend must + // self-terminate on the generation check, even though the state is RUNNING again. + // + // Given + testedTimeseriesCollector.onSessionStart() + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.BACKGROUND)) + runScheduledSuspend() + val staleRunnableB = captureScheduledRunnableForInterval(fakeIntervalBMs) + // Resume: state = RUNNING, generation = 2; A and B each get a fresh schedule + testedTimeseriesCollector.onRumContextUpdate(fakeRumContextOf(RumViewType.FOREGROUND)) + + // When — B's stale generation-1 tick fires while state is RUNNING + staleRunnableB.run() + + // Then — stale tick neither samples nor produces an extra schedule + verify(mockReaderB, never()).read() + // B schedules: 1 from start() + 1 from the resume = 2; the stale tick adds nothing + verify(mockExecutor, times(2)) + .schedule(any(), eq(fakeIntervalBMs), eq(TimeUnit.MILLISECONDS)) + } + + private fun runScheduledSuspend() { + captureScheduledSuspendRunnable().run() + } + + private fun captureScheduledSuspendRunnable(): Runnable { + val captor = argumentCaptor() + verify(mockExecutor, atLeastOnce()) + .schedule(captor.capture(), eq(DefaultTimeseriesCollector.SUSPEND_DELAY_MS), eq(TimeUnit.MILLISECONDS)) + return captor.lastValue + } + + private fun captureScheduledRunnableForInterval(intervalMs: Long): Runnable { + val captor = argumentCaptor() + verify(mockExecutor).schedule(captor.capture(), eq(intervalMs), eq(TimeUnit.MILLISECONDS)) + return captor.firstValue + } + + private fun captureLastScheduledRunnableForInterval(intervalMs: Long): Runnable { + val captor = argumentCaptor() + verify(mockExecutor, atLeastOnce()).schedule(captor.capture(), eq(intervalMs), eq(TimeUnit.MILLISECONDS)) + return captor.lastValue + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/PipelineTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/PipelineTest.kt new file mode 100644 index 0000000000..dda9bbc05d --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/PipelineTest.kt @@ -0,0 +1,542 @@ +/* + * 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.rum.internal.timeseries + +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.api.feature.EventWriteScope +import com.datadog.android.api.feature.Feature +import com.datadog.android.api.feature.FeatureScope +import com.datadog.android.api.feature.FeatureSdkCore +import com.datadog.android.api.storage.DataWriter +import com.datadog.android.api.storage.EventBatchWriter +import com.datadog.android.api.storage.EventType +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.instrumentation.insights.InsightsCollector +import com.datadog.android.rum.internal.timeseries.factory.EventFactory +import com.datadog.android.rum.internal.timeseries.provider.DataPointsReader +import com.datadog.android.rum.utils.forge.Configurator +import com.datadog.android.utils.verifyLog +import com.datadog.tools.unit.forge.aThrowable +import com.google.gson.JsonObject +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.annotation.Forgery +import fr.xgouchet.elmyr.annotation.IntForgery +import fr.xgouchet.elmyr.annotation.LongForgery +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doThrow +import org.mockito.kotlin.eq +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoInteractions +import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness +import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.CountDownLatch +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicLong + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +internal class PipelineTest { + + @Forgery + lateinit var fakeRumContext: RumContext + + @Mock + lateinit var mockReader: DataPointsReader + + @Mock + lateinit var mockEventFactory: EventFactory + + @Mock + lateinit var mockSdkCore: FeatureSdkCore + + @Mock + lateinit var mockDataWriter: DataWriter + + @Mock + lateinit var mockRumFeatureScope: FeatureScope + + @Mock + lateinit var mockEventWriteScope: EventWriteScope + + @Mock + lateinit var mockEventBatchWriter: EventBatchWriter + + @Mock + lateinit var mockInsightsCollector: InsightsCollector + + @Mock + lateinit var mockDatadogContext: DatadogContext + + @Mock + lateinit var mockInternalLogger: InternalLogger + + @IntForgery(min = 2, max = 10) + var fakeBufferSize: Int = 0 + + private lateinit var buffer: Buffer + private lateinit var testedPipeline: Pipeline + + @BeforeEach + fun `set up`() { + whenever(mockSdkCore.internalLogger) doReturn mockInternalLogger + whenever(mockSdkCore.getFeature(Feature.RUM_FEATURE_NAME)) doReturn mockRumFeatureScope + whenever(mockRumFeatureScope.withWriteContext(any(), any())) doAnswer { + it.getArgument<(DatadogContext, EventWriteScope) -> Unit>(it.arguments.lastIndex) + .invoke(mockDatadogContext, mockEventWriteScope) + } + whenever(mockEventWriteScope.invoke(any())) doAnswer { + it.getArgument<(EventBatchWriter) -> Unit>(0).invoke(mockEventBatchWriter) + } + whenever(mockDataWriter.write(any(), any(), any())) doReturn true + whenever(mockEventFactory.eventName) doReturn "view.cpu" + + buffer = Buffer(fakeBufferSize) + testedPipeline = Pipeline( + sdkCore = mockSdkCore, + reader = mockReader, + buffer = buffer, + eventFactory = mockEventFactory, + dataWriter = mockDataWriter, + insightsCollector = mockInsightsCollector + ) + } + + @Test + fun `M expose reader intervalMs W intervalMs`(@LongForgery(min = 1L) fakeIntervalMs: Long) { + // Given + whenever(mockReader.intervalMs) doReturn fakeIntervalMs + + // When / Then + assertThat(testedPipeline.intervalMs).isEqualTo(fakeIntervalMs) + } + + // region execute() + + @Test + fun `M append sample to buffer W execute()`(forge: Forge) { + // Given + val fakePoint = forge.getForgery>() + whenever(mockReader.read()) doReturn fakePoint + + // When + testedPipeline.execute(fakeRumContext) + + // Then + assertThat(buffer.drain()).containsExactly(fakePoint) + } + + @Test + fun `M not add to buffer W execute() { reader returns null }`() { + // Given + whenever(mockReader.read()) doReturn null + + // When + testedPipeline.execute(fakeRumContext) + + // Then + assertThat(buffer.drain()).isEmpty() + } + + @Test + fun `M not hold the lock while reading W execute()`(forge: Forge) { + // Given — a concurrent flush() races the reader and must not wait for the read to finish + var flushedWhileReading = false + whenever(mockReader.read()) doAnswer { + val flushed = CountDownLatch(1) + Thread { + testedPipeline.flush(fakeRumContext) + flushed.countDown() + }.start() + flushedWhileReading = flushed.await(CONCURRENT_FLUSH_TIMEOUT_MS, TimeUnit.MILLISECONDS) + forge.getForgery>() + } + + // When + testedPipeline.execute(fakeRumContext) + + // Then + assertThat(flushedWhileReading) + .describedAs("flush() completed while reader.read() was still running") + .isTrue() + } + + // endregion + + // region flush() + + @Test + fun `M flush W execute() { buffer fills to capacity }`(forge: Forge) { + // Given + val fakePoint = forge.getForgery>() + val fakeTimeseriesName = "view.cpu" + val fakeJson = fakeTimeseriesJson(fakeTimeseriesName) + whenever(mockReader.read()) doReturn fakePoint + whenever(mockEventFactory.create(any(), any(), any())) doReturn fakeJson + whenever(mockEventFactory.eventName) doReturn fakeTimeseriesName + repeat(fakeBufferSize - 1) { testedPipeline.execute(fakeRumContext) } + + // When + testedPipeline.execute(fakeRumContext) + + // Then + verify(mockDataWriter).write(mockEventBatchWriter, fakeJson, EventType.DEFAULT) + verify(mockInsightsCollector).onTimeseries(fakeTimeseriesName) + assertThat(buffer.drain()).isEmpty() + } + + @Test + fun `M not flush W execute() { buffer not full }`(forge: Forge) { + // Given + whenever(mockReader.read()) doReturn forge.getForgery>() + + // When + repeat(fakeBufferSize - 1) { testedPipeline.execute(fakeRumContext) } + + // Then + verifyNoInteractions(mockDataWriter) + verifyNoInteractions(mockInsightsCollector) + } + + @Test + fun `M not flush W execute() { event factory returns null }`(forge: Forge) { + // Given + whenever(mockReader.read()) doReturn forge.getForgery>() + whenever(mockEventFactory.create(any(), any(), any())) doReturn null + repeat(fakeBufferSize - 1) { testedPipeline.execute(fakeRumContext) } + + // When + testedPipeline.execute(fakeRumContext) + + // Then + verifyNoInteractions(mockDataWriter) + verifyNoInteractions(mockInsightsCollector) + } + + // endregion + + // region flush() + + @Test + fun `M write partial buffer W flush() { buffer has data }`(forge: Forge) { + // Given + val fakePoint = forge.getForgery>() + val fakeTimeseriesName = "view.memory" + val fakeJson = fakeTimeseriesJson(fakeTimeseriesName) + whenever(mockReader.read()) doReturn fakePoint + whenever(mockEventFactory.create(any(), any(), any())) doReturn fakeJson + whenever(mockEventFactory.eventName) doReturn fakeTimeseriesName + val sampleCount = fakeBufferSize - 1 + repeat(sampleCount) { testedPipeline.execute(fakeRumContext) } + + // When + testedPipeline.flush(fakeRumContext) + + // Then + val captor = argumentCaptor>>() + verify(mockEventFactory).create(any(), eq(fakeRumContext), captor.capture()) + assertThat(captor.firstValue).hasSize(sampleCount).allMatch { it == fakePoint } + verify(mockDataWriter).write(mockEventBatchWriter, fakeJson, EventType.DEFAULT) + verify(mockInsightsCollector).onTimeseries(fakeTimeseriesName) + assertThat(buffer.drain()).isEmpty() + } + + @Test + fun `M drain buffer before write context callback W flush()`(forge: Forge) { + // Given + val fakePoint = forge.getForgery>() + whenever(mockRumFeatureScope.withWriteContext(any(), any())) doAnswer { Unit } + whenever(mockEventFactory.create(any(), any(), any())) doReturn fakeTimeseriesJson("view.cpu") + whenever(mockReader.read()) doReturn fakePoint + testedPipeline.execute(fakeRumContext) + + // When + testedPipeline.flush(fakeRumContext) + + // Then + assertThat(buffer.drain()).isEmpty() + verifyNoInteractions(mockEventFactory) + verifyNoInteractions(mockDataWriter) + verifyNoInteractions(mockInsightsCollector) + } + + @Test + fun `M pass pre-flush points to event factory W execute() { point added before callback }`( + forge: Forge + ) { + // Given + val fakePoint = forge.getForgery>() + val fakeNextPoint = forge.getForgery>() + val callbackCaptor = argumentCaptor<(DatadogContext, EventWriteScope) -> Unit>() + whenever(mockRumFeatureScope.withWriteContext(any(), any())) doAnswer { Unit } + whenever(mockEventFactory.create(any(), any(), any())) doReturn fakeTimeseriesJson("view.cpu") + whenever(mockReader.read()) doReturn fakePoint + testedPipeline.execute(fakeRumContext) + testedPipeline.flush(fakeRumContext) + whenever(mockReader.read()) doReturn fakeNextPoint + + // When + testedPipeline.execute(fakeRumContext) + verify(mockRumFeatureScope).withWriteContext(any(), callbackCaptor.capture()) + callbackCaptor.firstValue.invoke(mockDatadogContext, mockEventWriteScope) + + // Then + val dataPointsCaptor = argumentCaptor>>() + verify(mockEventFactory).create(eq(mockDatadogContext), eq(fakeRumContext), dataPointsCaptor.capture()) + assertThat(dataPointsCaptor.firstValue).containsExactly(fakePoint) + assertThat(buffer.drain()).containsExactly(fakeNextPoint) + } + + @Test + fun `M pass contexts to event factory W flush()`(forge: Forge) { + // Given + whenever(mockReader.read()) doReturn forge.getForgery>() + whenever(mockEventFactory.create(any(), any(), any())) doReturn fakeTimeseriesJson("view.cpu") + testedPipeline.execute(fakeRumContext) + + // When + testedPipeline.flush(fakeRumContext) + + // Then + verify(mockEventFactory).create(eq(mockDatadogContext), eq(fakeRumContext), any()) + } + + @Test + fun `M request event creation feature contexts W flush()`(forge: Forge) { + // Given + whenever(mockReader.read()) doReturn forge.getForgery>() + whenever(mockEventFactory.create(any(), any(), any())) doReturn fakeTimeseriesJson("view.cpu") + testedPipeline.execute(fakeRumContext) + + // When + testedPipeline.flush(fakeRumContext) + + // Then + verify(mockRumFeatureScope).withWriteContext( + eq(setOf(Feature.SESSION_REPLAY_FEATURE_NAME, Feature.TRACING_FEATURE_NAME)), + any() + ) + } + + @Test + fun `M not write W flush() { buffer empty }`() { + // When + testedPipeline.flush(fakeRumContext) + + // Then + verifyNoInteractions(mockDataWriter) + verifyNoInteractions(mockInsightsCollector) + } + + @Test + fun `M log error W flush() { event factory throws }`(forge: Forge) { + // Given + val fakeThrowable = forge.aThrowable() + whenever(mockReader.read()) doReturn forge.getForgery>() + whenever(mockEventFactory.create(any(), any(), any())) doThrow fakeThrowable + testedPipeline.execute(fakeRumContext) + + // When + testedPipeline.flush(fakeRumContext) + + // Then + mockInternalLogger.verifyLog( + level = InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + message = "Timeseries event creation failed", + throwable = fakeThrowable + ) + verifyNoInteractions(mockDataWriter) + verifyNoInteractions(mockInsightsCollector) + } + + @Test + fun `M log error W flush() { dataWriter throws }`(forge: Forge) { + // Given + val fakeThrowable = forge.aThrowable() + val fakeJson = fakeTimeseriesJson("view.cpu") + val writeBlockCaptor = argumentCaptor<(EventBatchWriter) -> Unit>() + whenever(mockReader.read()) doReturn forge.getForgery>() + whenever(mockEventFactory.create(any(), any(), any())) doReturn fakeJson + whenever(mockDataWriter.write(any(), any(), any())) doThrow fakeThrowable + whenever(mockEventWriteScope.invoke(any())) doAnswer { Unit } + testedPipeline.execute(fakeRumContext) + + // When + testedPipeline.flush(fakeRumContext) + verify(mockEventWriteScope).invoke(writeBlockCaptor.capture()) + writeBlockCaptor.firstValue.invoke(mockEventBatchWriter) + + // Then + mockInternalLogger.verifyLog( + level = InternalLogger.Level.ERROR, + targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY), + message = "Timeseries flush failed", + throwable = fakeThrowable + ) + verifyNoInteractions(mockInsightsCollector) + } + + @Test + fun `M not notify insights W flush() { dataWriter returns false }`(forge: Forge) { + // Given + val fakeJson = fakeTimeseriesJson("view.cpu") + whenever(mockReader.read()) doReturn forge.getForgery>() + whenever(mockEventFactory.create(any(), any(), any())) doReturn fakeJson + whenever(mockDataWriter.write(any(), any(), any())) doReturn false + testedPipeline.execute(fakeRumContext) + + // When + testedPipeline.flush(fakeRumContext) + + // Then + verify(mockDataWriter).write(mockEventBatchWriter, fakeJson, EventType.DEFAULT) + verifyNoInteractions(mockInsightsCollector) + } + + // endregion + + // region concurrency + + @Test + fun `M not lose or duplicate points W execute() { concurrent samplers }`() { + // Given — every read() yields a unique point, every drained batch is recorded + val counter = AtomicLong() + val batches = CopyOnWriteArrayList>>() + stubUniqueReads(counter) + stubBatchRecording(batches) + + // When + runConcurrently { testedPipeline.execute(fakeRumContext) } + val batchesBeforeFlush = batches.toList() + testedPipeline.flush(fakeRumContext) + + // Then + assertThat(batchesBeforeFlush.map { it.size }) + .describedAs("batches drained by execute() are always exactly one buffer worth") + .containsOnly(fakeBufferSize) + assertThat(batches.flatten().map { it.timestampNs }.sorted()) + .isEqualTo((1L..counter.get()).toList()) + } + + @Test + fun `M not lose or duplicate points W execute() and flush() { concurrent }`() { + // Given + val counter = AtomicLong() + val batches = CopyOnWriteArrayList>>() + stubUniqueReads(counter) + stubBatchRecording(batches) + + // When — one thread keeps flushing while the others keep sampling + runConcurrently { threadIndex -> + if (threadIndex == 0) { + testedPipeline.flush(fakeRumContext) + } else { + testedPipeline.execute(fakeRumContext) + } + } + testedPipeline.flush(fakeRumContext) + + // Then + assertThat(batches.flatten().map { it.timestampNs }.sorted()) + .isEqualTo((1L..counter.get()).toList()) + } + + @Test + fun `M eventually capture point W flush() races execute() { flush between read() and add() }`( + forge: Forge + ) { + // Given — reader.read() blocks until released, forcing execute() to sit between + // its (unsynchronized) read() and the synchronized buffer add() + val readStarted = CountDownLatch(1) + val releaseRead = CountDownLatch(1) + val fakePoint = forge.getForgery>() + whenever(mockReader.read()) doAnswer { + readStarted.countDown() + releaseRead.await(CONCURRENT_FLUSH_TIMEOUT_MS, TimeUnit.MILLISECONDS) + fakePoint + } + val batches = CopyOnWriteArrayList>>() + stubBatchRecording(batches) + val executor = Executors.newSingleThreadExecutor() + + // When + executor.execute { testedPipeline.execute(fakeRumContext) } + readStarted.await(CONCURRENT_FLUSH_TIMEOUT_MS, TimeUnit.MILLISECONDS) + testedPipeline.flush(fakeRumContext) // races execute(): read() is in flight, not yet added + releaseRead.countDown() + executor.shutdown() + check(executor.awaitTermination(CONCURRENT_FLUSH_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + "execute() did not complete in time" + } + testedPipeline.flush(fakeRumContext) // point survives for the next flush + + // Then + assertThat(batches.flatten()).containsExactly(fakePoint) + } + + // endregion + + private fun stubUniqueReads(counter: AtomicLong) { + whenever(mockReader.read()) doAnswer { DataPoint(counter.incrementAndGet(), 0.0) } + } + + private fun stubBatchRecording(batches: MutableList>>) { + whenever(mockEventFactory.create(any(), any(), any())) doAnswer { invocation -> + batches.add(invocation.getArgument(2)) + fakeTimeseriesJson("view.cpu") + } + } + + private fun runConcurrently(task: (threadIndex: Int) -> Unit) { + val executor = Executors.newFixedThreadPool(CONCURRENT_THREADS) + val start = CountDownLatch(1) + val done = CountDownLatch(CONCURRENT_THREADS) + repeat(CONCURRENT_THREADS) { threadIndex -> + executor.execute { + start.await() + repeat(ITERATIONS_PER_THREAD) { task(threadIndex) } + done.countDown() + } + } + start.countDown() + val finished = done.await(CONCURRENT_FLUSH_TIMEOUT_MS, TimeUnit.MILLISECONDS) + executor.shutdownNow() + check(finished) { "concurrent tasks did not complete in time" } + } + + // Pipeline forwards whatever the event factory returns without inspecting it, so the shape + // only needs to be a distinct non-null object per name. + private fun fakeTimeseriesJson(name: String): JsonObject = JsonObject().apply { + addProperty("name", name) + } + + private companion object { + const val CONCURRENT_FLUSH_TIMEOUT_MS = 2000L + const val CONCURRENT_THREADS = 4 + const val ITERATIONS_PER_THREAD = 200 + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/csv/CSVReader.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/csv/CSVReader.kt new file mode 100644 index 0000000000..d4ba3b6859 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/csv/CSVReader.kt @@ -0,0 +1,62 @@ +/* + * 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.rum.internal.timeseries.csv + +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.internal.timeseries.DataPoint +import com.datadog.android.rum.internal.timeseries.provider.DataPointsReader + +/** + * A test-only [DataPointsReader] that replays pre-recorded samples from a CSV string. + * + * The CSV is expected to contain a header line plus rows in the form: + * `timestamp_nanos,metric_name,value`. Rows whose `metric_name` does not match the [metric] + * filter are skipped, as are blank or malformed rows. + */ +internal class CSVReader( + csvContent: String, + metric: String, + timeProvider: TimeProvider, + override val intervalMs: Long = DEFAULT_INTERVAL_MS +) : DataPointsReader(timeProvider) { + + private val samples: List> = parseCsv(csvContent, metric) + private var index: Int = 0 + + fun hasNext(): Boolean = index < samples.size + + override fun read(): DataPoint { + check(hasNext()) { "CSVReader exhausted" } + return samples[index++] + } + + override fun readValue(): Double = error("CSVReader overrides read(); readValue() must not be called") + + private fun parseCsv(content: String, metric: String): List> { + return content.lineSequence() + .drop(1) + .mapNotNull { line -> + val trimmed = line.trim() + if (trimmed.isEmpty()) return@mapNotNull null + val cols = trimmed.split(",") + if (cols.size != COLUMN_COUNT) return@mapNotNull null + if (cols[METRIC_INDEX] != metric) return@mapNotNull null + val ts = cols[TIMESTAMP_INDEX].toLongOrNull() ?: return@mapNotNull null + val v = cols[VALUE_INDEX].toDoubleOrNull() ?: return@mapNotNull null + DataPoint(timestampNs = ts, value = v) + } + .toList() + } + + companion object { + const val DEFAULT_INTERVAL_MS: Long = 1_000L + private const val COLUMN_COUNT = 3 + private const val TIMESTAMP_INDEX = 0 + private const val METRIC_INDEX = 1 + private const val VALUE_INDEX = 2 + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/csv/CsvCollector.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/csv/CsvCollector.kt new file mode 100644 index 0000000000..52915d987c --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/csv/CsvCollector.kt @@ -0,0 +1,131 @@ +/* + * 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.rum.internal.timeseries.csv + +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.internal.domain.InfoData +import com.datadog.android.rum.internal.domain.InfoProvider +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.domain.battery.BatteryInfo +import com.datadog.android.rum.internal.domain.display.DisplayInfo +import com.datadog.android.rum.internal.domain.event.RumEventSerializer +import com.datadog.android.rum.internal.timeseries.Buffer +import com.datadog.android.rum.internal.timeseries.TimeseriesCollector +import com.datadog.android.rum.internal.timeseries.factory.CpuEventFactory +import com.datadog.android.rum.internal.timeseries.factory.EventFactory +import com.datadog.android.rum.internal.timeseries.factory.MemoryEventFactory +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import fr.xgouchet.elmyr.Forge + +/** + * A test-only [TimeseriesCollector] that mirrors the wiring done by `DefaultTimeseriesCollectorFactory`, + * but pulls samples from CSV-backed readers instead of `VitalReaderWrapper` and drives the + * pipelines synchronously (no executor) so callers can assert on every emitted JSON. + */ +internal class CsvCollector( + private val pipelines: List, EventFactory>>, + private val datadogContext: DatadogContext, + private val rumContext: RumContext, + private val eventSerializer: RumEventSerializer +) : TimeseriesCollector { + + private val emitted = mutableListOf() + + /** All JSON events produced by the pipelines so far. */ + val captured: List get() = emitted.toList() + + /** + * Walks each (reader, buffer, factory) triple synchronously: samples until the reader is + * exhausted, flushing whenever the buffer is full, then emitting any final remainder. + */ + override fun onSessionStart() { + for ((reader, buffer, eventFactory) in pipelines) { + while (reader.hasNext()) { + buffer.add(reader.read()) + if (buffer.isFull()) flush(buffer, eventFactory) + } + flush(buffer, eventFactory) + } + } + + private fun flush(buffer: Buffer, eventFactory: EventFactory) = buffer.drain() + .takeIf { it.isNotEmpty() } + ?.let { eventFactory.create(datadogContext, rumContext, it) } + ?.let(eventSerializer::serialize) + ?.let(JsonParser::parseString) + ?.let { emitted.add(it.asJsonObject) } + + override fun onSessionStop() = Unit + + override fun onRumContextUpdate(newRumContext: RumContext) = Unit + + companion object { + + /** + * Builds a [CsvCollector] with the same shape as `DefaultTimeseriesCollectorFactory`: + * a memory pipeline followed by a CPU pipeline, each backed by [CSVReader] and the + * production [MemoryEventFactory] / [CpuEventFactory]. + */ + fun create( + csvContent: String, + sessionType: RumSessionType, + totalRamBytes: Long, + bufferSize: Int, + timeProvider: TimeProvider, + forge: Forge, + internalLogger: InternalLogger + ): CsvCollector { + val rumContext = forge.getForgery() + val datadogContext = forge.getForgery() + val batteryInfo = forge.getForgery() + val displayInfo = forge.getForgery() + + return CsvCollector( + datadogContext = datadogContext, + rumContext = rumContext, + eventSerializer = RumEventSerializer(internalLogger), + pipelines = listOf( + Triple( + CSVReader(csvContent, METRIC_MEMORY_USAGE, timeProvider), + Buffer(bufferSize), + MemoryEventFactory( + sessionType = sessionType, + totalRamBytes = totalRamBytes, + timeProvider = timeProvider, + batteryInfoProvider = FixedInfoProvider(batteryInfo), + displayInfoProvider = FixedInfoProvider(displayInfo), + internalLogger = internalLogger + ) + ), + Triple( + CSVReader(csvContent, METRIC_CPU_USAGE, timeProvider), + Buffer(bufferSize), + CpuEventFactory( + sessionType = sessionType, + timeProvider = timeProvider, + batteryInfoProvider = FixedInfoProvider(batteryInfo), + displayInfoProvider = FixedInfoProvider(displayInfo), + internalLogger = internalLogger + ) + ) + ) + ) + } + + private class FixedInfoProvider(private val state: T) : InfoProvider { + override fun getState(): T = state + override fun cleanup() = Unit + } + + const val METRIC_MEMORY_USAGE: String = "memory_usage" + const val METRIC_CPU_USAGE: String = "cpu_usage" + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/csv/TimeseriesCollectorEndToEndTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/csv/TimeseriesCollectorEndToEndTest.kt new file mode 100644 index 0000000000..79ccf67418 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/csv/TimeseriesCollectorEndToEndTest.kt @@ -0,0 +1,157 @@ +/* + * 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.rum.internal.timeseries.csv + +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.assertj.TimeseriesCpuEventAssert +import com.datadog.android.rum.assertj.TimeseriesMemoryEventAssert +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent +import com.datadog.android.rum.utils.forge.Configurator +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +internal class TimeseriesCollectorEndToEndTest { + + @Mock + lateinit var mockTimeProvider: TimeProvider + + private lateinit var capturedMemoryEvents: List + private lateinit var capturedCpuEvents: List + + @BeforeEach + fun `set up`(forge: Forge) { + whenever(mockTimeProvider.getServerTimestampMillis()) doReturn FIXED_DATE_MS + + val testedTimeseriesCollector = CsvCollector.create( + csvContent = loadResource("fixtures/timeseries/input_memory_cpu.csv"), + sessionType = RumSessionType.USER, + totalRamBytes = TOTAL_RAM_BYTES, + bufferSize = BATCH_SIZE, + timeProvider = mockTimeProvider, + forge = forge, + internalLogger = mock() + ) + testedTimeseriesCollector.onSessionStart() + capturedMemoryEvents = testedTimeseriesCollector.captured.mapNotNull { serializedPayload -> + runCatching { TimeseriesMemoryEvent.fromJsonObject(serializedPayload) } + .getOrNull() + } + capturedCpuEvents = testedTimeseriesCollector.captured.mapNotNull { serializedPayload -> + runCatching { TimeseriesCpuEvent.fromJsonObject(serializedPayload) } + .getOrNull() + } + } + + @Test + fun `M emit two memory and two cpu batches W full CSV is fed { batchSize=5, samples=10 }`() { + // Then + assertThat(capturedMemoryEvents.size).isEqualTo(2) + assertThat(capturedCpuEvents.size).isEqualTo(2) + } + + @Test + fun `M match expected timeseries fixture W memory batch 1`() { + val expected = loadExpectedMemoryTimeseries("fixtures/timeseries/expected_memory_batch1.json") + val actual = capturedMemoryEvents[0] + + TimeseriesMemoryEventAssert.assertThat(actual) + .hasDate(expected.date) + .hasSameTimeseriesAs(expected) + } + + @Test + fun `M match expected timeseries fixture W memory batch 2`() { + val expected = loadExpectedMemoryTimeseries("fixtures/timeseries/expected_memory_batch2.json") + val actual = capturedMemoryEvents[1] + + TimeseriesMemoryEventAssert.assertThat(actual) + .hasDate(expected.date) + .hasSameTimeseriesAs(expected) + } + + @Test + fun `M match expected timeseries fixture W cpu batch 1`() { + val expected = loadExpectedCpuTimeseries("fixtures/timeseries/expected_cpu_batch1.json") + val actual = capturedCpuEvents[0] + + TimeseriesCpuEventAssert.assertThat(actual) + .hasDate(expected.date) + .hasSameTimeseriesAs(expected) + } + + @Test + fun `M match expected timeseries fixture W cpu batch 2`() { + val expected = loadExpectedCpuTimeseries("fixtures/timeseries/expected_cpu_batch2.json") + val actual = capturedCpuEvents[1] + + TimeseriesCpuEventAssert.assertThat(actual) + .hasDate(expected.date) + .hasSameTimeseriesAs(expected) + } + + @Test + fun `M emit valid timeseries id W any batch`() { + capturedMemoryEvents.forEach { actual -> + TimeseriesMemoryEventAssert.assertThat(actual) + .hasValidTimeseriesId() + } + capturedCpuEvents.forEach { actual -> + TimeseriesCpuEventAssert.assertThat(actual) + .hasValidTimeseriesId() + } + } + + @Test + fun `M produce monotonic start lt or eq to end W any batch`() { + capturedMemoryEvents.forEach { actual -> + TimeseriesMemoryEventAssert.assertThat(actual) + .hasTimeseriesStartNotAfterEnd() + } + capturedCpuEvents.forEach { actual -> + TimeseriesCpuEventAssert.assertThat(actual) + .hasTimeseriesStartNotAfterEnd() + } + } + + private companion object { + private const val FIXED_DATE_MS: Long = 1_700_000_001_000L + private const val TOTAL_RAM_BYTES: Long = 1_000_000_000L + private const val BATCH_SIZE: Int = 5 + private fun loadExpectedMemoryTimeseries(path: String): TimeseriesMemoryEvent = + TimeseriesMemoryEvent.fromJson(loadResource(path)) + + private fun loadExpectedCpuTimeseries(path: String): TimeseriesCpuEvent = + TimeseriesCpuEvent.fromJson(loadResource(path)) + + private fun loadResource(path: String): String { + val stream = this::class.java.classLoader?.getResourceAsStream(path) + ?: error("Resource not found: $path") + return stream.bufferedReader().use { it.readText() } + } + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/factory/CpuEventFactoryTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/factory/CpuEventFactoryTest.kt new file mode 100644 index 0000000000..f2da0c57a3 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/factory/CpuEventFactoryTest.kt @@ -0,0 +1,469 @@ +/* + * 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.rum.internal.timeseries.factory + +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.api.feature.Feature +import com.datadog.android.core.internal.utils.DdTagsUtils +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.assertj.TimeseriesCpuEventAssert +import com.datadog.android.rum.internal.FeaturesContextResolver +import com.datadog.android.rum.internal.domain.InfoProvider +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.domain.battery.BatteryInfo +import com.datadog.android.rum.internal.domain.display.DisplayInfo +import com.datadog.android.rum.internal.domain.scope.RumSessionScope +import com.datadog.android.rum.internal.domain.scope.RumViewScope +import com.datadog.android.rum.internal.domain.scope.toTimeseriesCpuSchemaType +import com.datadog.android.rum.internal.timeseries.DataPoint +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent.TimeseriesCpuEventSessionType +import com.datadog.android.rum.utils.forge.Configurator +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.annotation.BoolForgery +import fr.xgouchet.elmyr.annotation.DoubleForgery +import fr.xgouchet.elmyr.annotation.FloatForgery +import fr.xgouchet.elmyr.annotation.Forgery +import fr.xgouchet.elmyr.annotation.LongForgery +import fr.xgouchet.elmyr.annotation.StringForgery +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +internal class CpuEventFactoryTest { + + @Mock + lateinit var mockTimeProvider: TimeProvider + + @Mock + lateinit var mockInternalLogger: InternalLogger + + @Mock + lateinit var stubBatteryInfoProvider: InfoProvider + + @Mock + lateinit var stubDisplayInfoProvider: InfoProvider + + @StringForgery + lateinit var fakeSessionId: String + + @StringForgery + lateinit var fakeApplicationId: String + + @LongForgery(min = 1L) + var fakeNowMs: Long = 0L + + @FloatForgery(min = 0f, max = 1f) + var fakeBatteryLevel: Float = 0f + + @BoolForgery + var fakeLowPowerMode: Boolean = false + + @FloatForgery(min = 0f, max = 1f) + var fakeBrightnessLevel: Float = 0f + + @Forgery + lateinit var fakeDatadogContext: DatadogContext + + private var fakeSource: TimeseriesCpuEvent.Source? = null + + @Forgery + lateinit var fakeRumContext: RumContext + + private val fakeSerializedRumContext: RumContext + get() = fakeRumContext.copy(applicationId = fakeApplicationId, sessionId = fakeSessionId) + + private val oneSample = listOf(DataPoint(1L, 1.0)) + + @BeforeEach + fun `set up`(forge: Forge) { + fakeSource = forge.aNullable { aValueFrom(TimeseriesCpuEvent.Source::class.java) } + fakeDatadogContext = fakeDatadogContext.copy( + source = fakeSource?.toJson()?.asString ?: forge.anAlphabeticalString() + ) + whenever(mockTimeProvider.getServerTimestampMillis()) doReturn fakeNowMs + whenever(stubBatteryInfoProvider.getState()) doReturn BatteryInfo( + batteryLevel = fakeBatteryLevel, + lowPowerMode = fakeLowPowerMode + ) + whenever(stubDisplayInfoProvider.getState()) doReturn DisplayInfo(screenBrightness = fakeBrightnessLevel) + } + + private fun testedFactory( + sessionType: RumSessionType = RumSessionType.USER + ) = CpuEventFactory( + sessionType = sessionType, + timeProvider = mockTimeProvider, + batteryInfoProvider = stubBatteryInfoProvider, + displayInfoProvider = stubDisplayInfoProvider, + internalLogger = mockInternalLogger + ) + + @Test + fun `M return null W create() { empty input }`() { + // When + val result = testedFactory().create(fakeDatadogContext, fakeSerializedRumContext, emptyList()) + + // Then + assertThat(result).isNull() + } + + @Test + fun `M fill timeseries W create() { multiple data points }`( + @DoubleForgery(min = 0.0, max = 100.0) fakeCpuValue: Double, + @LongForgery(min = 1L) fakeTs: Long + ) { + // Given + val samples = listOf( + DataPoint(fakeTs, fakeCpuValue), + DataPoint(fakeTs + 1L, fakeCpuValue + 0.1) + ) + + // When + val event = createSerializedEvent(dataPoints = samples) + + // Then + TimeseriesCpuEventAssert.assertThat(event) + .hasTimeseriesName(VALUE_NAME_CPU) + .hasTimeseriesSchema(VALUE_SCHEMA_OBJECT) + .hasDate(fakeNowMs) + .hasValidTimeseriesId() + .hasDataPointsCount(2) + .hasTimeseriesStart(fakeTs) + .hasTimeseriesEnd(fakeTs + 1L) + .hasApplicationId(fakeApplicationId) + .hasSessionId(fakeSessionId) + .hasSessionType(TimeseriesCpuEventSessionType.USER) + .hasService(fakeDatadogContext.service) + .hasVersion(fakeDatadogContext.version) + } + + @Test + fun `M map session type W create() { synthetics }`() { + // When + val event = createEvent(sessionType = RumSessionType.SYNTHETICS) + + // Then + TimeseriesCpuEventAssert.assertThat(event).hasSessionType(TimeseriesCpuEventSessionType.SYNTHETICS) + } + + @Test + fun `M return generated timeseries name W eventName`() { + // When / Then + assertThat(testedFactory().eventName).isEqualTo(createEvent().timeseries.name) + } + + @Test + fun `M fill cpu_usage W create() { one value per data point }`( + @DoubleForgery(min = 1.0, max = 100.0) fakeFirstCpu: Double, + @DoubleForgery(min = 1.0, max = 100.0) fakeSecondCpu: Double, + @LongForgery(min = 1L) fakeTs: Long + ) { + // Given + val samples = listOf( + DataPoint(fakeTs, fakeFirstCpu), + DataPoint(fakeTs + 1L, fakeSecondCpu) + ) + + // When + val event = createSerializedEvent(dataPoints = samples) + + // Then + TimeseriesCpuEventAssert.assertThat(event) + .hasDataPointsCount(2) + .hasCpuUsage(fakeFirstCpu, position = 0) + .hasCpuUsage(fakeSecondCpu, position = 1) + .hasTimestamps(fakeTs, fakeTs + 1L) + } + + @Test + fun `M fill application and build info W create()`( + @StringForgery fakeBuildId: String + ) { + // Given + val datadogContext = fakeDatadogContext.copy(appBuildId = fakeBuildId) + + // When + val event = createEvent(datadogContext = datadogContext) + + // Then + assertThat(event.application.id).isEqualTo(fakeApplicationId) + assertThat(event.application.currentLocale) + .isEqualTo(datadogContext.deviceInfo.localeInfo.currentLocale) + assertThat(event.source).isEqualTo(fakeSource) + assertThat(event.buildVersion).isEqualTo(datadogContext.versionCode.toString()) + assertThat(event.buildId).isEqualTo(fakeBuildId) + assertThat(event.ddtags).isEqualTo(DdTagsUtils.toDdTagsString(datadogContext)) + } + + @Test + fun `M fill os and device W create()`() { + // Given + val deviceInfo = fakeDatadogContext.deviceInfo + + // When + val event = createEvent() + + // Then + val os = checkNotNull(event.os) + assertThat(os.name).isEqualTo(deviceInfo.osName) + assertThat(os.version).isEqualTo(deviceInfo.osVersion) + assertThat(os.versionMajor).isEqualTo(deviceInfo.osMajorVersion) + + val device = checkNotNull(event.device) + assertThat(device.type).isEqualTo(deviceInfo.deviceType.toTimeseriesCpuSchemaType()) + assertThat(device.name).isEqualTo(deviceInfo.deviceName) + assertThat(device.model).isEqualTo(deviceInfo.deviceModel) + assertThat(device.brand).isEqualTo(deviceInfo.deviceBrand) + assertThat(device.architecture).isEqualTo(deviceInfo.architecture) + assertThat(device.locales).isEqualTo(deviceInfo.localeInfo.locales) + assertThat(device.timeZone).isEqualTo(deviceInfo.localeInfo.timeZone) + assertThat(device.logicalCpuCount?.toInt()).isEqualTo(deviceInfo.logicalCpuCount) + assertThat(device.totalRam?.toInt()).isEqualTo(deviceInfo.totalRam) + assertThat(device.isLowRam).isEqualTo(deviceInfo.isLowRam) + assertThat(device.batteryLevel?.toFloat()).isEqualTo(fakeBatteryLevel) + assertThat(device.powerSavingMode).isEqualTo(fakeLowPowerMode) + assertThat(device.brightnessLevel?.toFloat()).isEqualTo(fakeBrightnessLevel) + } + + @Test + fun `M leave device power info null W create() { providers have no data }`() { + // Given + whenever(stubBatteryInfoProvider.getState()) doReturn BatteryInfo() + whenever(stubDisplayInfoProvider.getState()) doReturn DisplayInfo() + + // When + val event = createEvent() + + // Then + val device = checkNotNull(event.device) + assertThat(device.batteryLevel).isNull() + assertThat(device.powerSavingMode).isNull() + assertThat(device.brightnessLevel).isNull() + } + + @Test + fun `M fill dd W create()`( + @DoubleForgery(min = 0.0, max = 100.0) fakeSampleRate: Double + ) { + // Given + val rumContext = fakeSerializedRumContext.copy( + sessionStartReason = RumSessionScope.StartReason.INACTIVITY_TIMEOUT, + sessionSampleRate = fakeSampleRate.toFloat() + ) + + // When + val event = createEvent(rumContext = rumContext) + + // Then + assertThat(event.dd.session?.sessionPrecondition) + .isEqualTo(TimeseriesCpuEvent.SessionPrecondition.INACTIVITY_TIMEOUT) + assertThat(event.dd.configuration?.sessionSampleRate?.toFloat()) + .isEqualTo(fakeSampleRate.toFloat()) + } + + @Test + fun `M fill dd configuration W create() { sample rates in features context }`( + @LongForgery(min = 0L, max = 100L) fakeSessionReplaySampleRate: Long, + @FloatForgery(min = 0f, max = 100f) fakeTraceSampleRate: Float + ) { + // Given + val datadogContext = fakeDatadogContext.copy( + featuresContext = fakeDatadogContext.featuresContext + mapOf( + Feature.SESSION_REPLAY_FEATURE_NAME to mapOf( + RumViewScope.SESSION_REPLAY_SAMPLE_RATE_KEY to fakeSessionReplaySampleRate + ), + Feature.TRACING_FEATURE_NAME to mapOf( + RumViewScope.TRACE_SAMPLE_RATE to fakeTraceSampleRate + ) + ) + ) + + // When + val event = createEvent(datadogContext = datadogContext) + + // Then + val configuration = checkNotNull(event.dd.configuration) + assertThat(configuration.sessionReplaySampleRate?.toLong()).isEqualTo(fakeSessionReplaySampleRate) + assertThat(configuration.traceSampleRate?.toFloat()).isEqualTo(fakeTraceSampleRate) + } + + @Test + fun `M fill dd configuration W create() { sample rates missing or of wrong type }`( + @StringForgery fakeNotASampleRate: String + ) { + // Given + val datadogContext = fakeDatadogContext.copy( + featuresContext = fakeDatadogContext.featuresContext + mapOf( + Feature.SESSION_REPLAY_FEATURE_NAME to emptyMap(), + Feature.TRACING_FEATURE_NAME to mapOf(RumViewScope.TRACE_SAMPLE_RATE to fakeNotASampleRate) + ) + ) + + // When + val event = createEvent(datadogContext = datadogContext) + + // Then + val configuration = checkNotNull(event.dd.configuration) + assertThat(configuration.sessionReplaySampleRate).isNull() + assertThat(configuration.traceSampleRate).isNull() + } + + @Test + fun `M fill session hasReplay W create() { view is recorded }`( + @StringForgery fakeViewId: String + ) { + // Given + val rumContext = fakeSerializedRumContext.copy(viewId = fakeViewId) + val datadogContext = fakeDatadogContext.copy( + featuresContext = fakeDatadogContext.featuresContext + mapOf( + Feature.SESSION_REPLAY_FEATURE_NAME to mapOf( + fakeViewId to mapOf(FeaturesContextResolver.HAS_REPLAY_KEY to true) + ) + ) + ) + + // When + val event = createEvent(datadogContext = datadogContext, rumContext = rumContext) + + // Then + assertThat(event.session.hasReplay).isTrue() + } + + @Test + fun `M fill session hasReplay W create() { view is not recorded }`( + @StringForgery fakeViewId: String + ) { + // Given + val rumContext = fakeSerializedRumContext.copy(viewId = fakeViewId) + val datadogContext = fakeDatadogContext.copy( + featuresContext = fakeDatadogContext.featuresContext + mapOf( + Feature.SESSION_REPLAY_FEATURE_NAME to mapOf( + fakeViewId to mapOf(FeaturesContextResolver.HAS_REPLAY_KEY to false) + ) + ) + ) + + // When + val event = createEvent(datadogContext = datadogContext, rumContext = rumContext) + + // Then + assertThat(event.session.hasReplay).isFalse() + } + + @Test + fun `M fill synthetics W create() { synthetics ids are set }`( + @StringForgery fakeTestId: String, + @StringForgery fakeResultId: String + ) { + // Given + val rumContext = fakeSerializedRumContext.copy( + syntheticsTestId = fakeTestId, + syntheticsResultId = fakeResultId + ) + + // When + val event = createEvent(rumContext = rumContext) + + // Then + assertThat(event.synthetics?.testId).isEqualTo(fakeTestId) + assertThat(event.synthetics?.resultId).isEqualTo(fakeResultId) + } + + @ParameterizedTest + @MethodSource("incompleteSyntheticsIds") + fun `M not fill synthetics W create() { synthetics ids are incomplete }`( + syntheticsTestId: String?, + syntheticsResultId: String? + ) { + // Given + val rumContext = fakeSerializedRumContext.copy( + syntheticsTestId = syntheticsTestId, + syntheticsResultId = syntheticsResultId + ) + + // When + val event = createEvent(rumContext = rumContext) + + // Then + assertThat(event.synthetics).isNull() + } + + @Test + fun `M leave unsupported fields null W create()`() { + // When + val event = createEvent() + + // Then + assertThat(event.connectivity).isNull() + assertThat(event.usr).isNull() + assertThat(event.account).isNull() + assertThat(event.context).isNull() + assertThat(event.view).isNull() + assertThat(event.ciTest).isNull() + assertThat(event.display).isNull() + } + + private fun createSerializedEvent( + datadogContext: DatadogContext = fakeDatadogContext, + rumContext: RumContext = fakeSerializedRumContext, + sessionType: RumSessionType = RumSessionType.USER, + dataPoints: List> = oneSample + ): TimeseriesCpuEvent = TimeseriesCpuEvent.fromJson( + checkNotNull( + testedFactory(sessionType = sessionType) + .create(datadogContext, rumContext, dataPoints) + ).toJson().toString() + ) + + private fun createEvent( + datadogContext: DatadogContext = fakeDatadogContext, + rumContext: RumContext = fakeSerializedRumContext, + sessionType: RumSessionType = RumSessionType.USER + ): TimeseriesCpuEvent = checkNotNull( + testedFactory(sessionType = sessionType) + .create(datadogContext, rumContext, oneSample) + ) + + companion object { + private const val VALUE_NAME_CPU: String = "cpu" + private const val VALUE_SCHEMA_OBJECT: String = "object-v2" + + private const val FAKE_SYNTHETICS_ID: String = "synthetics-id" + + @JvmStatic + fun incompleteSyntheticsIds(): List = listOf( + Arguments.of(null, null), + Arguments.of("", " "), + Arguments.of(FAKE_SYNTHETICS_ID, null), + Arguments.of(null, FAKE_SYNTHETICS_ID), + Arguments.of(FAKE_SYNTHETICS_ID, " "), + Arguments.of("", FAKE_SYNTHETICS_ID) + ) + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/factory/MemoryEventFactoryTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/factory/MemoryEventFactoryTest.kt new file mode 100644 index 0000000000..18c807e857 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/factory/MemoryEventFactoryTest.kt @@ -0,0 +1,501 @@ +/* + * 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.rum.internal.timeseries.factory + +import com.datadog.android.api.InternalLogger +import com.datadog.android.api.context.DatadogContext +import com.datadog.android.api.feature.Feature +import com.datadog.android.core.internal.utils.DdTagsUtils +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.RumSessionType +import com.datadog.android.rum.assertj.TimeseriesMemoryEventAssert +import com.datadog.android.rum.internal.FeaturesContextResolver +import com.datadog.android.rum.internal.domain.InfoProvider +import com.datadog.android.rum.internal.domain.RumContext +import com.datadog.android.rum.internal.domain.battery.BatteryInfo +import com.datadog.android.rum.internal.domain.display.DisplayInfo +import com.datadog.android.rum.internal.domain.scope.RumSessionScope +import com.datadog.android.rum.internal.domain.scope.RumViewScope +import com.datadog.android.rum.internal.domain.scope.toTimeseriesMemorySchemaType +import com.datadog.android.rum.internal.timeseries.DataPoint +import com.datadog.android.rum.model.TimeseriesMemoryEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent.TimeseriesMemoryEventSessionType +import com.datadog.android.rum.utils.forge.Configurator +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.annotation.BoolForgery +import fr.xgouchet.elmyr.annotation.DoubleForgery +import fr.xgouchet.elmyr.annotation.FloatForgery +import fr.xgouchet.elmyr.annotation.Forgery +import fr.xgouchet.elmyr.annotation.LongForgery +import fr.xgouchet.elmyr.annotation.StringForgery +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import org.junit.jupiter.params.provider.ValueSource +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +internal class MemoryEventFactoryTest { + + @Mock + lateinit var mockTimeProvider: TimeProvider + + @Mock + lateinit var mockInternalLogger: InternalLogger + + @Mock + lateinit var stubBatteryInfoProvider: InfoProvider + + @Mock + lateinit var stubDisplayInfoProvider: InfoProvider + + @StringForgery + lateinit var fakeSessionId: String + + @StringForgery + lateinit var fakeApplicationId: String + + @LongForgery(min = 1_000_000_000L, max = 16_000_000_000L) + var fakeTotalRamBytes: Long = 0L + + @LongForgery(min = 1L) + var fakeNowMs: Long = 0L + + @FloatForgery(min = 0f, max = 1f) + var fakeBatteryLevel: Float = 0f + + @BoolForgery + var fakeLowPowerMode: Boolean = false + + @FloatForgery(min = 0f, max = 1f) + var fakeBrightnessLevel: Float = 0f + + @Forgery + lateinit var fakeDatadogContext: DatadogContext + + private var fakeSource: TimeseriesMemoryEvent.Source? = null + + @Forgery + lateinit var fakeRumContext: RumContext + + private val fakeSerializedRumContext: RumContext + get() = fakeRumContext.copy(applicationId = fakeApplicationId, sessionId = fakeSessionId) + + private val oneSample = listOf(DataPoint(1L, 1.0)) + + @BeforeEach + fun `set up`(forge: Forge) { + fakeSource = forge.aNullable { aValueFrom(TimeseriesMemoryEvent.Source::class.java) } + fakeDatadogContext = fakeDatadogContext.copy( + source = fakeSource?.toJson()?.asString ?: forge.anAlphabeticalString() + ) + whenever(mockTimeProvider.getServerTimestampMillis()) doReturn fakeNowMs + whenever(stubBatteryInfoProvider.getState()) doReturn BatteryInfo( + batteryLevel = fakeBatteryLevel, + lowPowerMode = fakeLowPowerMode + ) + whenever(stubDisplayInfoProvider.getState()) doReturn DisplayInfo(screenBrightness = fakeBrightnessLevel) + } + + private fun testedFactory( + sessionType: RumSessionType = RumSessionType.USER, + totalRamBytes: Long = fakeTotalRamBytes + ) = MemoryEventFactory( + sessionType = sessionType, + totalRamBytes = totalRamBytes, + timeProvider = mockTimeProvider, + batteryInfoProvider = stubBatteryInfoProvider, + displayInfoProvider = stubDisplayInfoProvider, + internalLogger = mockInternalLogger + ) + + @Test + fun `M return null W create() { empty input }`() { + // When + val result = testedFactory().create(fakeDatadogContext, fakeSerializedRumContext, emptyList()) + + // Then + assertThat(result).isNull() + } + + @ParameterizedTest + @ValueSource(longs = [0L, -1L, Long.MIN_VALUE]) + fun `M return null W create() { totalRamBytes is not positive }`(totalRamBytes: Long) { + // When + val result = testedFactory(totalRamBytes = totalRamBytes) + .create(fakeDatadogContext, fakeSerializedRumContext, oneSample) + + // Then + assertThat(result).isNull() + } + + @Test + fun `M fill timeseries W create() { multiple data points }`( + @DoubleForgery(min = 1.0) fakeMemory: Double, + @LongForgery(min = 1L) fakeTs: Long + ) { + // Given + val samples = listOf( + DataPoint(fakeTs, fakeMemory), + DataPoint(fakeTs + 1L, fakeMemory + 1.0) + ) + + // When + val event = createSerializedEvent(dataPoints = samples) + + // Then + TimeseriesMemoryEventAssert.assertThat(event) + .hasTimeseriesName(VALUE_NAME_MEMORY) + .hasTimeseriesSchema(VALUE_SCHEMA_OBJECT) + .hasDate(fakeNowMs) + .hasValidTimeseriesId() + .hasDataPointsCount(2) + .hasTimeseriesStart(fakeTs) + .hasTimeseriesEnd(fakeTs + 1L) + .hasApplicationId(fakeApplicationId) + .hasSessionId(fakeSessionId) + .hasSessionType(TimeseriesMemoryEventSessionType.USER) + .hasService(fakeDatadogContext.service) + .hasVersion(fakeDatadogContext.version) + } + + @Test + fun `M map session type W create() { synthetics }`() { + // When + val event = createEvent(sessionType = RumSessionType.SYNTHETICS) + + // Then + TimeseriesMemoryEventAssert.assertThat(event) + .hasSessionType(TimeseriesMemoryEventSessionType.SYNTHETICS) + } + + @Test + fun `M return generated timeseries name W eventName`() { + // When / Then + assertThat(testedFactory().eventName).isEqualTo(createEvent().timeseries.name) + } + + @Test + fun `M fill memory values W create() { one value per data point }`( + @DoubleForgery(min = 1.0, max = 16_000_000_000.0) fakeFirstMemory: Double, + @DoubleForgery(min = 1.0, max = 16_000_000_000.0) fakeSecondMemory: Double, + @LongForgery(min = 1L) fakeTs: Long + ) { + // Given + val samples = listOf( + DataPoint(fakeTs, fakeFirstMemory), + DataPoint(fakeTs + 1L, fakeSecondMemory) + ) + + // When + val event = createSerializedEvent(dataPoints = samples) + + // Then + TimeseriesMemoryEventAssert.assertThat(event) + .hasDataPointsCount(2) + .hasMemoryFootprint(fakeFirstMemory / BYTES_IN_KB, MEMORY_OFFSET, position = 0) + .hasMemoryFootprint(fakeSecondMemory / BYTES_IN_KB, MEMORY_OFFSET, position = 1) + .hasMemoryPercent( + fakeFirstMemory / fakeTotalRamBytes * PERCENT_FACTOR, + MEMORY_OFFSET, + position = 0 + ) + .hasMemoryPercent( + fakeSecondMemory / fakeTotalRamBytes * PERCENT_FACTOR, + MEMORY_OFFSET, + position = 1 + ) + .hasTimestamps(fakeTs, fakeTs + 1L) + } + + @Test + fun `M fill application and build info W create()`( + @StringForgery fakeBuildId: String + ) { + // Given + val datadogContext = fakeDatadogContext.copy(appBuildId = fakeBuildId) + + // When + val event = createEvent(datadogContext = datadogContext) + + // Then + assertThat(event.application.id).isEqualTo(fakeApplicationId) + assertThat(event.application.currentLocale) + .isEqualTo(datadogContext.deviceInfo.localeInfo.currentLocale) + assertThat(event.source).isEqualTo(fakeSource) + assertThat(event.buildVersion).isEqualTo(datadogContext.versionCode.toString()) + assertThat(event.buildId).isEqualTo(fakeBuildId) + assertThat(event.ddtags).isEqualTo(DdTagsUtils.toDdTagsString(datadogContext)) + } + + @Test + fun `M fill os and device W create()`() { + // Given + val deviceInfo = fakeDatadogContext.deviceInfo + + // When + val event = createEvent() + + // Then + val os = checkNotNull(event.os) + assertThat(os.name).isEqualTo(deviceInfo.osName) + assertThat(os.version).isEqualTo(deviceInfo.osVersion) + assertThat(os.versionMajor).isEqualTo(deviceInfo.osMajorVersion) + + val device = checkNotNull(event.device) + assertThat(device.type).isEqualTo(deviceInfo.deviceType.toTimeseriesMemorySchemaType()) + assertThat(device.name).isEqualTo(deviceInfo.deviceName) + assertThat(device.model).isEqualTo(deviceInfo.deviceModel) + assertThat(device.brand).isEqualTo(deviceInfo.deviceBrand) + assertThat(device.architecture).isEqualTo(deviceInfo.architecture) + assertThat(device.locales).isEqualTo(deviceInfo.localeInfo.locales) + assertThat(device.timeZone).isEqualTo(deviceInfo.localeInfo.timeZone) + assertThat(device.logicalCpuCount?.toInt()).isEqualTo(deviceInfo.logicalCpuCount) + assertThat(device.totalRam?.toInt()).isEqualTo(deviceInfo.totalRam) + assertThat(device.isLowRam).isEqualTo(deviceInfo.isLowRam) + assertThat(device.batteryLevel?.toFloat()).isEqualTo(fakeBatteryLevel) + assertThat(device.powerSavingMode).isEqualTo(fakeLowPowerMode) + assertThat(device.brightnessLevel?.toFloat()).isEqualTo(fakeBrightnessLevel) + } + + @Test + fun `M leave device power info null W create() { providers have no data }`() { + // Given + whenever(stubBatteryInfoProvider.getState()) doReturn BatteryInfo() + whenever(stubDisplayInfoProvider.getState()) doReturn DisplayInfo() + + // When + val event = createEvent() + + // Then + val device = checkNotNull(event.device) + assertThat(device.batteryLevel).isNull() + assertThat(device.powerSavingMode).isNull() + assertThat(device.brightnessLevel).isNull() + } + + @Test + fun `M fill dd W create()`( + @DoubleForgery(min = 0.0, max = 100.0) fakeSampleRate: Double + ) { + // Given + val rumContext = fakeSerializedRumContext.copy( + sessionStartReason = RumSessionScope.StartReason.INACTIVITY_TIMEOUT, + sessionSampleRate = fakeSampleRate.toFloat() + ) + + // When + val event = createEvent(rumContext = rumContext) + + // Then + assertThat(event.dd.session?.sessionPrecondition) + .isEqualTo(TimeseriesMemoryEvent.SessionPrecondition.INACTIVITY_TIMEOUT) + assertThat(event.dd.configuration?.sessionSampleRate?.toFloat()) + .isEqualTo(fakeSampleRate.toFloat()) + } + + @Test + fun `M fill dd configuration W create() { sample rates in features context }`( + @LongForgery(min = 0L, max = 100L) fakeSessionReplaySampleRate: Long, + @FloatForgery(min = 0f, max = 100f) fakeTraceSampleRate: Float + ) { + // Given + val datadogContext = fakeDatadogContext.copy( + featuresContext = fakeDatadogContext.featuresContext + mapOf( + Feature.SESSION_REPLAY_FEATURE_NAME to mapOf( + RumViewScope.SESSION_REPLAY_SAMPLE_RATE_KEY to fakeSessionReplaySampleRate + ), + Feature.TRACING_FEATURE_NAME to mapOf( + RumViewScope.TRACE_SAMPLE_RATE to fakeTraceSampleRate + ) + ) + ) + + // When + val event = createEvent(datadogContext = datadogContext) + + // Then + val configuration = checkNotNull(event.dd.configuration) + assertThat(configuration.sessionReplaySampleRate?.toLong()).isEqualTo(fakeSessionReplaySampleRate) + assertThat(configuration.traceSampleRate?.toFloat()).isEqualTo(fakeTraceSampleRate) + } + + @Test + fun `M fill dd configuration W create() { sample rates missing or of wrong type }`( + @StringForgery fakeNotASampleRate: String + ) { + // Given + val datadogContext = fakeDatadogContext.copy( + featuresContext = fakeDatadogContext.featuresContext + mapOf( + Feature.SESSION_REPLAY_FEATURE_NAME to emptyMap(), + Feature.TRACING_FEATURE_NAME to mapOf(RumViewScope.TRACE_SAMPLE_RATE to fakeNotASampleRate) + ) + ) + + // When + val event = createEvent(datadogContext = datadogContext) + + // Then + val configuration = checkNotNull(event.dd.configuration) + assertThat(configuration.sessionReplaySampleRate).isNull() + assertThat(configuration.traceSampleRate).isNull() + } + + @Test + fun `M fill session hasReplay W create() { view is recorded }`( + @StringForgery fakeViewId: String + ) { + // Given + val rumContext = fakeSerializedRumContext.copy(viewId = fakeViewId) + val datadogContext = fakeDatadogContext.copy( + featuresContext = fakeDatadogContext.featuresContext + mapOf( + Feature.SESSION_REPLAY_FEATURE_NAME to mapOf( + fakeViewId to mapOf(FeaturesContextResolver.HAS_REPLAY_KEY to true) + ) + ) + ) + + // When + val event = createEvent(datadogContext = datadogContext, rumContext = rumContext) + + // Then + assertThat(event.session.hasReplay).isTrue() + } + + @Test + fun `M fill session hasReplay W create() { view is not recorded }`( + @StringForgery fakeViewId: String + ) { + // Given + val rumContext = fakeSerializedRumContext.copy(viewId = fakeViewId) + val datadogContext = fakeDatadogContext.copy( + featuresContext = fakeDatadogContext.featuresContext + mapOf( + Feature.SESSION_REPLAY_FEATURE_NAME to mapOf( + fakeViewId to mapOf(FeaturesContextResolver.HAS_REPLAY_KEY to false) + ) + ) + ) + + // When + val event = createEvent(datadogContext = datadogContext, rumContext = rumContext) + + // Then + assertThat(event.session.hasReplay).isFalse() + } + + @Test + fun `M fill synthetics W create() { synthetics ids are set }`( + @StringForgery fakeTestId: String, + @StringForgery fakeResultId: String + ) { + // Given + val rumContext = fakeSerializedRumContext.copy( + syntheticsTestId = fakeTestId, + syntheticsResultId = fakeResultId + ) + + // When + val event = createEvent(rumContext = rumContext) + + // Then + assertThat(event.synthetics?.testId).isEqualTo(fakeTestId) + assertThat(event.synthetics?.resultId).isEqualTo(fakeResultId) + } + + @ParameterizedTest + @MethodSource("incompleteSyntheticsIds") + fun `M not fill synthetics W create() { synthetics ids are incomplete }`( + syntheticsTestId: String?, + syntheticsResultId: String? + ) { + // Given + val rumContext = fakeSerializedRumContext.copy( + syntheticsTestId = syntheticsTestId, + syntheticsResultId = syntheticsResultId + ) + + // When + val event = createEvent(rumContext = rumContext) + + // Then + assertThat(event.synthetics).isNull() + } + + @Test + fun `M leave unsupported fields null W create()`() { + // When + val event = createEvent() + + // Then + assertThat(event.connectivity).isNull() + assertThat(event.usr).isNull() + assertThat(event.account).isNull() + assertThat(event.context).isNull() + assertThat(event.view).isNull() + assertThat(event.ciTest).isNull() + assertThat(event.display).isNull() + } + + private fun createSerializedEvent( + datadogContext: DatadogContext = fakeDatadogContext, + rumContext: RumContext = fakeSerializedRumContext, + sessionType: RumSessionType = RumSessionType.USER, + dataPoints: List> = oneSample + ): TimeseriesMemoryEvent = TimeseriesMemoryEvent.fromJson( + checkNotNull( + testedFactory(sessionType = sessionType) + .create(datadogContext, rumContext, dataPoints) + ).toJson().toString() + ) + + private fun createEvent( + datadogContext: DatadogContext = fakeDatadogContext, + rumContext: RumContext = fakeSerializedRumContext, + sessionType: RumSessionType = RumSessionType.USER + ): TimeseriesMemoryEvent = checkNotNull( + testedFactory(sessionType = sessionType) + .create(datadogContext, rumContext, oneSample) + ) + + companion object { + private const val PERCENT_FACTOR: Double = 100.0 + private const val BYTES_IN_KB: Double = 1000.0 + private const val MEMORY_OFFSET: Double = 0.0001 + + private const val VALUE_NAME_MEMORY: String = "memory" + private const val VALUE_SCHEMA_OBJECT: String = "object-v2" + + private const val FAKE_SYNTHETICS_ID: String = "synthetics-id" + + @JvmStatic + fun incompleteSyntheticsIds(): List = listOf( + Arguments.of(null, null), + Arguments.of("", " "), + Arguments.of(FAKE_SYNTHETICS_ID, null), + Arguments.of(null, FAKE_SYNTHETICS_ID), + Arguments.of(FAKE_SYNTHETICS_ID, " "), + Arguments.of("", FAKE_SYNTHETICS_ID) + ) + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/provider/CpuDatapointReaderTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/provider/CpuDatapointReaderTest.kt new file mode 100644 index 0000000000..ad7b954c7f --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/provider/CpuDatapointReaderTest.kt @@ -0,0 +1,208 @@ +/* + * 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.rum.internal.timeseries.provider + +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.internal.timeseries.DataPoint +import com.datadog.android.rum.internal.vitals.CpuStatReader +import com.datadog.android.rum.utils.forge.Configurator +import fr.xgouchet.elmyr.annotation.DoubleForgery +import fr.xgouchet.elmyr.annotation.IntForgery +import fr.xgouchet.elmyr.annotation.LongForgery +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.data.Offset +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doReturnConsecutively +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness +import java.util.concurrent.TimeUnit + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +internal class CpuDatapointReaderTest { + + @LongForgery(min = 100L, max = 60_000L) + var fakeIntervalMs: Long = 0L + + @LongForgery(min = 1_000L, max = 1_000_000L) + var fakeStartTimestampMs: Long = 0L + + @IntForgery(min = 1, max = 10_000) + var fakeBaselineTicks: Int = 0 + + val mockCpuStatReader: CpuStatReader = mock() + + val mockTimeProvider: TimeProvider = mock { + on { getServerTimestampMillis() } doAnswer { fakeStartTimestampMs } + on { getDeviceElapsedTimeNanos() } doAnswer { fakeStartTimestampMs * NS_PER_MS } + } + + private fun buildReader(availableProcessors: Int = 1) = CpuDatapointReader( + cpuStatReader = mockCpuStatReader, + timeProvider = mockTimeProvider, + intervalMs = fakeIntervalMs, + availableProcessors = availableProcessors + ) + + /** + * Primes the reader with [fakeBaselineTicks] (returns null — no baseline yet), advances the + * clock by [elapsedMs], then returns the second sample built from [secondTicks] (or `null` to + * simulate the stat read failing between samples). Elapsed time is stubbed as a sequence so + * the prime read sees the start instant and the second read sees start + [elapsedMs]. + */ + private fun readSecondSample( + elapsedMs: Long, + secondTicks: Double?, + availableProcessors: Int = 1 + ): DataPoint? { + whenever(mockTimeProvider.getDeviceElapsedTimeNanos()).doReturn( + fakeStartTimestampMs * NS_PER_MS, + (fakeStartTimestampMs + elapsedMs) * NS_PER_MS + ) + whenever(mockTimeProvider.getServerTimestampMillis()) doReturn (fakeStartTimestampMs + elapsedMs) + whenever(mockCpuStatReader.readActiveTime()) + .doReturnConsecutively(listOf(fakeBaselineTicks.toDouble(), secondTicks)) + return buildReader(availableProcessors).run { + read() + read() + } + } + + @Test + fun `M return null W read() {first sample}`() { + // Given + whenever(mockCpuStatReader.readActiveTime()) doReturn fakeBaselineTicks.toDouble() + + // When + val result = buildReader().read() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return null W read() {stat read returns null}`() { + // Given + whenever(mockCpuStatReader.readActiveTime()) doReturn null + + // When + val result = buildReader().read() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return null W read() {stat read fails on second sample}`( + @LongForgery(min = 500L, max = 5000L) fakeElapsedMs: Long + ) { + // When + val result = readSecondSample(elapsedMs = fakeElapsedMs, secondTicks = null) + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return 0 W read() {zero elapsed and no tick delta}`() { + // When — both samples at the same nano instant with unchanged ticks. + // Without the elapsedMs floor this would be 0.0 / 0.0 = NaN (NaN survives coerceIn). + val result = readSecondSample(elapsedMs = 0L, secondTicks = fakeBaselineTicks.toDouble()) + + // Then — the 1 ms floor keeps the result finite + checkNotNull(result) + assertThat(result.value).isEqualTo(0.0) + } + + @Test + fun `M return cpu percent W read() {second sample}`( + @DoubleForgery(min = 1.0, max = 80.0) fakeCpuPercent: Double, + @LongForgery(min = 500L, max = 5000L) fakeElapsedMs: Long + ) { + // Given + val deltaTicks = (fakeCpuPercent * fakeElapsedMs / 1000.0).toInt().coerceAtLeast(2) + + // When + val result = readSecondSample( + elapsedMs = fakeElapsedMs, + secondTicks = (fakeBaselineTicks + deltaTicks).toDouble() + ) + + // Then + checkNotNull(result) + val expectedPercent = deltaTicks * 1000.0 / fakeElapsedMs + assertThat(result.value).isCloseTo(expectedPercent, Offset.offset(0.1)) + assertThat(result.timestampNs).isEqualTo(TimeUnit.MILLISECONDS.toNanos(fakeStartTimestampMs + fakeElapsedMs)) + } + + @Test + fun `M return 0 W read() {ticks unchanged}`(@LongForgery(min = 500L, max = 5000L) fakeElapsedMs: Long) { + // When + val result = readSecondSample(elapsedMs = fakeElapsedMs, secondTicks = fakeBaselineTicks.toDouble()) + + // Then + checkNotNull(result) + assertThat(result.value).isEqualTo(0.0) + } + + @Test + fun `M clamp to 100 W read() {spike exceeds total capacity}`( + @LongForgery(min = 500L, max = 2000L) fakeElapsedMs: Long + ) { + // Given — 200 ticks/s on one core with availableProcessors=1 → 200% → clamped to 100 + val deltaTicks = (200.0 * fakeElapsedMs / 1000.0).toInt() + + // When + val result = readSecondSample( + elapsedMs = fakeElapsedMs, + secondTicks = (fakeBaselineTicks + deltaTicks).toDouble() + ) + + // Then + checkNotNull(result) + assertThat(result.value).isEqualTo(100.0) + } + + @Test + fun `M normalise by core count W read() {multi-core usage}`( + @IntForgery(min = 2, max = 8) fakeCoreCount: Int, + @LongForgery(min = 500L, max = 5000L) fakeElapsedMs: Long, + @DoubleForgery(min = 1.0, max = 50.0) fakePerCorePct: Double + ) { + // Given — deltaTicks = fakePerCorePct% on ONE core → fakePerCorePct/fakeCoreCount % of total + val deltaTicks = (fakePerCorePct * fakeElapsedMs / 1000.0).toInt().coerceAtLeast(1) + + // When + val result = readSecondSample( + elapsedMs = fakeElapsedMs, + availableProcessors = fakeCoreCount, + secondTicks = (fakeBaselineTicks + deltaTicks).toDouble() + ) + + // Then + checkNotNull(result) + val expectedPercent = (deltaTicks * 1000.0 / fakeElapsedMs) / fakeCoreCount + assertThat(result.value).isCloseTo(expectedPercent, Offset.offset(0.1)) + } + + private companion object { + private const val NS_PER_MS = 1_000_000L + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/provider/VitalReaderWrapperTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/provider/VitalReaderWrapperTest.kt new file mode 100644 index 0000000000..d863626dfa --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/timeseries/provider/VitalReaderWrapperTest.kt @@ -0,0 +1,83 @@ +/* + * 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.rum.internal.timeseries.provider + +import com.datadog.android.internal.time.TimeProvider +import com.datadog.android.rum.internal.vitals.VitalReader +import com.datadog.android.rum.utils.forge.Configurator +import fr.xgouchet.elmyr.annotation.DoubleForgery +import fr.xgouchet.elmyr.annotation.LongForgery +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import org.mockito.quality.Strictness +import java.util.concurrent.TimeUnit + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +internal class VitalReaderWrapperTest { + + @LongForgery(min = 1L) + var fakeTimestamp: Long = 0L + + @LongForgery(min = 1L) + var fakeIntervalMs: Long = 0L + + @Mock + lateinit var mockTimeProvider: TimeProvider + + @BeforeEach + fun `set up`() { + whenever(mockTimeProvider.getServerTimestampMillis()) doReturn fakeTimestamp + } + + @Test + fun `M return sample W read() { reader has value }`(@DoubleForgery fakeValue: Double) { + // Given + val mockVitalReader: VitalReader = mock { + on { readVitalData() } doReturn fakeValue + } + val testedReader = VitalReaderWrapper(mockVitalReader, mockTimeProvider, fakeIntervalMs) + + // When + val result = testedReader.read() + + // Then + checkNotNull(result) + assertThat(result.timestampNs).isEqualTo(TimeUnit.MILLISECONDS.toNanos(fakeTimestamp)) + assertThat(result.value).isEqualTo(fakeValue) + } + + @Test + fun `M return null W read() { reader has no value }`() { + // Given + val mockVitalReader: VitalReader = mock { + on { readVitalData() } doReturn null + } + val testedReader = VitalReaderWrapper(mockVitalReader, mockTimeProvider, fakeIntervalMs) + + // When + val result = testedReader.read() + + // Then + assertThat(result).isNull() + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/vitals/CPUVitalReaderTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/vitals/CPUVitalReaderTest.kt index 1a3b4d4414..abadf83ece 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/vitals/CPUVitalReaderTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/vitals/CPUVitalReaderTest.kt @@ -6,158 +6,53 @@ package com.datadog.android.rum.internal.vitals -import com.datadog.android.rum.utils.forge.Configurator -import fr.xgouchet.elmyr.annotation.IntForgery -import fr.xgouchet.elmyr.annotation.StringForgery -import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.annotation.DoubleForgery import fr.xgouchet.elmyr.junit5.ForgeExtension import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.Extensions -import org.junit.jupiter.api.io.TempDir +import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoSettings import org.mockito.kotlin.doReturn -import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import org.mockito.quality.Strictness -import java.io.File @Extensions( ExtendWith(MockitoExtension::class), ExtendWith(ForgeExtension::class) ) @MockitoSettings(strictness = Strictness.LENIENT) -@ForgeConfiguration(Configurator::class) internal class CPUVitalReaderTest { lateinit var testedReader: VitalReader - @TempDir - lateinit var tempDir: File - - lateinit var fakeFile: File - - @IntForgery(1) - var fakePid: Int = 0 - - @StringForgery(regex = "\\(\\w+\\)") - lateinit var fakeCommand: String - - @StringForgery(regex = "[RSDZTtWXxKWP]") - lateinit var fakeState: String - - @IntForgery(1) - var fakePpid: Int = 0 - - @IntForgery(1) - var fakePgrp: Int = 0 - - @IntForgery(1) - var fakeSession: Int = 0 - - @IntForgery(1) - var fakeTtyNr: Int = 0 - - @IntForgery(1) - var fakeTpgid: Int = 0 - - @IntForgery(1) - var fakeFlags: Int = 0 - - @IntForgery(1) - var fakeMinFlt: Int = 0 - - @IntForgery(1) - var fakeCMinFlt: Int = 0 - - @IntForgery(1) - var fakeMajFlt: Int = 0 - - @IntForgery(1) - var fakeCMajFlt: Int = 0 - - @IntForgery(1) - var fakeUtime: Int = 0 - - @IntForgery(1) - var fakeStime: Int = 0 - - @IntForgery(1) - var fakeCUtime: Int = 0 - - @IntForgery(1) - var fakeCStime: Int = 0 - - @IntForgery(-100, -2) - var fakePriority: Int = 0 - - lateinit var fakeStatContent: String + @Mock + lateinit var mockCpuStatReader: CpuStatReader @BeforeEach fun `set up`() { - fakeFile = File(tempDir, "stat") - fakeStatContent = generateFakeContent() - testedReader = CPUVitalReader(fakeFile, internalLogger = mock()) - } - - @Test - fun `M read unix stats file W init()`() { - // When - val testedReader = CPUVitalReader(internalLogger = mock()) - - // Then - assertThat(testedReader.statFile).isEqualTo(CPUVitalReader.STAT_FILE) - } - - @Test - fun `M read correct data W readVitalData()`() { - // Given - fakeFile.writeText(fakeStatContent) - - // When - val result = testedReader.readVitalData() - - // Then - assertThat(result).isEqualTo(fakeUtime.toDouble()) + testedReader = CPUVitalReader(mockCpuStatReader) } @Test - fun `M read correct data W readVitalData() {multiple times}`( - @IntForgery(1) utimes: List - ) { + fun `M return user time W readVitalData()`(@DoubleForgery fakeUserTime: Double) { // Given - val results = mutableListOf() - - // When - utimes.forEach { utime -> - fakeUtime = utime - fakeFile.writeText(generateFakeContent()) - val result = testedReader.readVitalData() - results.add(result!!) - } + whenever(mockCpuStatReader.readUserTime()) doReturn fakeUserTime - // Then - assertThat(results).isEqualTo(utimes.map { utime -> utime.toDouble() }) - } - - @Test - fun `M return null W readVitalData() {file doesn't exist}`() { // When val result = testedReader.readVitalData() // Then - assertThat(result).isNull() + assertThat(result).isEqualTo(fakeUserTime) } @Test - fun `M return null W readVitalData() {file isn't readable}`() { + fun `M return null W readVitalData() {no cpu data}`() { // Given - val restrictedFile = mock() - whenever(restrictedFile.exists()) doReturn true - whenever(restrictedFile.canRead()) doReturn false + whenever(mockCpuStatReader.readUserTime()) doReturn null // When val result = testedReader.readVitalData() @@ -165,28 +60,4 @@ internal class CPUVitalReaderTest { // Then assertThat(result).isNull() } - - @Test - fun `M return null W readVitalData() {file has invalid data}`( - @StringForgery content: String - ) { - // Given - fakeFile.writeText(content) - - // When - val result = testedReader.readVitalData() - - // Then - assertThat(result).isNull() - } - - private fun generateFakeContent(): String { - return listOf( - fakePid, fakeCommand, fakeState, fakePpid, fakePgrp, - fakeSession, fakeTtyNr, fakeTpgid, fakeFlags, - fakeMinFlt, fakeCMinFlt, fakeMajFlt, fakeCMajFlt, - fakeUtime, fakeStime, fakeCUtime, fakeCStime, - fakePriority - ).joinToString(" ") - } } diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/vitals/CpuStatReaderTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/vitals/CpuStatReaderTest.kt new file mode 100644 index 0000000000..edab0078be --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/vitals/CpuStatReaderTest.kt @@ -0,0 +1,294 @@ +/* + * 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.rum.internal.vitals + +import com.datadog.android.rum.utils.forge.Configurator +import fr.xgouchet.elmyr.annotation.IntForgery +import fr.xgouchet.elmyr.annotation.StringForgery +import fr.xgouchet.elmyr.junit5.ForgeConfiguration +import fr.xgouchet.elmyr.junit5.ForgeExtension +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.junit.jupiter.api.extension.Extensions +import org.junit.jupiter.api.io.TempDir +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.junit.jupiter.MockitoSettings +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.quality.Strictness +import java.io.File + +@Extensions( + ExtendWith(MockitoExtension::class), + ExtendWith(ForgeExtension::class) +) +@MockitoSettings(strictness = Strictness.LENIENT) +@ForgeConfiguration(Configurator::class) +internal class CpuStatReaderTest { + + lateinit var testedReader: CpuStatReader + + @TempDir + lateinit var tempDir: File + + lateinit var fakeFile: File + + // /proc/self/stat fields (indices 0–12 before utime at index 13) + @IntForgery(1) + var fakePid: Int = 0 + + @StringForgery(regex = "\\(\\w+\\)") + lateinit var fakeCommand: String + + @StringForgery(regex = "[RSDZTtWXxKWP]") + lateinit var fakeState: String + + @IntForgery(1) + var fakePpid: Int = 0 + + @IntForgery(1) + var fakePgrp: Int = 0 + + @IntForgery(1) + var fakeSession: Int = 0 + + @IntForgery(1) + var fakeTtyNr: Int = 0 + + @IntForgery(1) + var fakeTpgid: Int = 0 + + @IntForgery(1) + var fakeFlags: Int = 0 + + @IntForgery(1) + var fakeMinFlt: Int = 0 + + @IntForgery(1) + var fakeCMinFlt: Int = 0 + + @IntForgery(1) + var fakeMajFlt: Int = 0 + + @IntForgery(1) + var fakeCMajFlt: Int = 0 + + @IntForgery(min = 1, max = 10_000) + var fakeUtime: Int = 0 + + @IntForgery(min = 1, max = 10_000) + var fakeStime: Int = 0 + + @BeforeEach + fun `set up`() { + fakeFile = File(tempDir, "stat") + testedReader = CpuStatReader(fakeFile, internalLogger = mock()) + } + + @Test + fun `M use default stat file W init() {no file provided}`() { + // When + val reader = CpuStatReader(internalLogger = mock()) + + // Then + assertThat(reader.statFile).isEqualTo(CpuStatReader.STAT_FILE) + } + + @Test + fun `M read utime W readUserTime()`() { + // Given + fakeFile.writeText(generateStatContent(fakeUtime)) + + // When + val result = testedReader.readUserTime() + + // Then + assertThat(result).isEqualTo(fakeUtime.toDouble()) + } + + @Test + fun `M read utime W readUserTime() {multiple times}`(@IntForgery(1) fakeUtimes: List) { + // Given + val results = mutableListOf() + + // When + fakeUtimes.forEach { utime -> + fakeFile.writeText(generateStatContent(utime)) + results.add(testedReader.readUserTime()) + } + + // Then + assertThat(results).isEqualTo(fakeUtimes.map { it.toDouble() }) + } + + @Test + fun `M ignore stime W readUserTime() {non-numeric stime}`( + @StringForgery(regex = "[a-z]{3}") fakeNonNumeric: String + ) { + // Given — utime is well-formed, only stime is garbage; utime must still be returned + fakeFile.writeText(generateStatContent(utime = fakeUtime, stime = fakeNonNumeric)) + + // When + val result = testedReader.readUserTime() + + // Then + assertThat(result).isEqualTo(fakeUtime.toDouble()) + } + + @Test + fun `M return null W readUserTime() {file doesn't exist}`() { + // When + val result = testedReader.readUserTime() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return null W readUserTime() {file isn't readable}`() { + // Given + val restrictedFile = mock { + on { exists() } doReturn true + on { canRead() } doReturn false + } + val reader = CpuStatReader(restrictedFile, internalLogger = mock()) + + // When + val result = reader.readUserTime() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return null W readUserTime() {invalid content}`(@StringForgery fakeContent: String) { + // Given + fakeFile.writeText(fakeContent) + + // When + val result = testedReader.readUserTime() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return null W readUserTime() {non-numeric utime}`( + @StringForgery(regex = "[a-z]{3}") fakeNonNumeric: String + ) { + // Given + fakeFile.writeText(generateStatContent(utime = fakeNonNumeric)) + + // When + val result = testedReader.readUserTime() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M read utime plus stime W readActiveTime()`() { + // Given + fakeFile.writeText(generateStatContent(fakeUtime)) + + // When + val result = testedReader.readActiveTime() + + // Then + assertThat(result).isEqualTo((fakeUtime + fakeStime).toDouble()) + } + + @Test + fun `M use only utime W readActiveTime() {stime field absent}`() { + // Given — content with exactly 14 tokens (utime at [13], no stime at [14]) + fakeFile.writeText(generateStatContent(fakeUtime, includeStime = false)) + + // When + val result = testedReader.readActiveTime() + + // Then + assertThat(result).isEqualTo(fakeUtime.toDouble()) + } + + @Test + fun `M return null W readActiveTime() {non-numeric utime}`( + @StringForgery(regex = "[a-z]{3}") fakeNonNumeric: String + ) { + // Given + fakeFile.writeText(generateStatContent(utime = fakeNonNumeric)) + + // When + val result = testedReader.readActiveTime() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return null W readActiveTime() {non-numeric stime}`( + @StringForgery(regex = "[a-z]{3}") fakeNonNumeric: String + ) { + // Given — 15 tokens, numeric utime but non-numeric stime + fakeFile.writeText(generateStatContent(utime = fakeUtime, stime = fakeNonNumeric)) + + // When + val result = testedReader.readActiveTime() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return null W readActiveTime() {file doesn't exist}`() { + // When + val result = testedReader.readActiveTime() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return null W readActiveTime() {file isn't readable}`() { + // Given + val restrictedFile = mock { + on { exists() } doReturn true + on { canRead() } doReturn false + } + val reader = CpuStatReader(restrictedFile, internalLogger = mock()) + + // When + val result = reader.readActiveTime() + + // Then + assertThat(result).isNull() + } + + @Test + fun `M return null W readActiveTime() {invalid content}`(@StringForgery fakeContent: String) { + // Given + fakeFile.writeText(fakeContent) + + // When + val result = testedReader.readActiveTime() + + // Then + assertThat(result).isNull() + } + + private fun generateStatContent(utime: Any, stime: Any = fakeStime, includeStime: Boolean = true): String { + val fields = mutableListOf( + fakePid, fakeCommand, fakeState, fakePpid, fakePgrp, + fakeSession, fakeTtyNr, fakeTpgid, fakeFlags, + fakeMinFlt, fakeCMinFlt, fakeMajFlt, fakeCMajFlt, + utime + ) + if (includeStime) fields.add(stime) + return fields.joinToString(" ") + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/timeseries/TimeseriesConfigurationTests.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/timeseries/TimeseriesConfigurationTests.kt new file mode 100644 index 0000000000..1c3575ae9d --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/timeseries/TimeseriesConfigurationTests.kt @@ -0,0 +1,49 @@ +/* + * 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.rum.timeseries + +import com.datadog.android.rum.ExperimentalRumApi +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +@OptIn(ExperimentalRumApi::class) +internal class TimeseriesConfigurationTests { + + @Test + fun `M collect all types W build() { collectOnly not called }`() { + // When + val config = TimeseriesConfiguration.Builder().build() + + // Then + assertThat(config.enabledTypes).containsExactlyInAnyOrderElementsOf(TimeseriesType.values().toList()) + } + + @ParameterizedTest + @EnumSource(TimeseriesType::class) + fun `M collect selected type W collectOnly()`(fakeType: TimeseriesType) { + // When + val config = TimeseriesConfiguration.Builder() + .collectOnly(fakeType) + .build() + + // Then + assertThat(config.enabledTypes).containsExactly(fakeType) + } + + @Test + fun `M collect no types W collectOnly() { empty array }`() { + // When + val config = TimeseriesConfiguration.Builder() + .collectOnly(*emptyArray()) + .build() + + // Then + assertThat(config.enabledTypes).isEmpty() + } +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/ConfigurationRumForgeryFactory.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/ConfigurationRumForgeryFactory.kt index 390c3cc0a7..89d752a810 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/ConfigurationRumForgeryFactory.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/ConfigurationRumForgeryFactory.kt @@ -6,6 +6,7 @@ package com.datadog.android.rum.utils.forge +import com.datadog.android.rum.ExperimentalRumApi import com.datadog.android.rum.RumSessionType import com.datadog.android.rum.configuration.VitalsUpdateFrequency import com.datadog.android.rum.internal.RumFeature @@ -13,6 +14,7 @@ import com.datadog.android.rum.metric.interactiontonextview.NoOpLastInteractionI import com.datadog.android.rum.metric.interactiontonextview.TimeBasedInteractionIdentifier import com.datadog.android.rum.metric.networksettled.NoOpInitialResourceIdentifier import com.datadog.android.rum.metric.networksettled.TimeBasedInitialResourceIdentifier +import com.datadog.android.rum.timeseries.TimeseriesConfiguration import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy import com.datadog.android.rum.tracking.FragmentViewTrackingStrategy import com.datadog.android.rum.tracking.MixedViewTrackingStrategy @@ -21,6 +23,7 @@ import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.ForgeryFactory import org.mockito.kotlin.mock +@OptIn(ExperimentalRumApi::class) internal class ConfigurationRumForgeryFactory : ForgeryFactory { override fun getForgery(forge: Forge): RumFeature.Configuration { @@ -74,7 +77,8 @@ internal class ConfigurationRumForgeryFactory : collectAccessibility = forge.aBool(), disableJankStats = false, insightsCollector = mock(), - appStartupActivityPredicate = mock() + appStartupActivityPredicate = mock(), + timeseriesConfiguration = forge.aNullable { TimeseriesConfiguration.Builder().build() } ) } } diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/Configurator.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/Configurator.kt index b101c8da11..9609d1854f 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/Configurator.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/Configurator.kt @@ -57,6 +57,7 @@ internal class Configurator : BaseConfigurator() { forge.addFactory(SlowFramesConfigurationForgeryFactory()) forge.addFactory(DisplayInfoForgeryFactory()) forge.addFactory(BatteryInfoForgeryFactory()) + forge.addFactory(DataPointForgeryFactory()) forge.addFactory(NativeHeatmapActionDataForgeryFactory()) forge.addFactory(CrossPlatformHeatmapActionDataForgeryFactory()) diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/DataPointForgeryFactory.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/DataPointForgeryFactory.kt new file mode 100644 index 0000000000..58c2769cd3 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/utils/forge/DataPointForgeryFactory.kt @@ -0,0 +1,18 @@ +/* + * 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.rum.utils.forge + +import com.datadog.android.rum.internal.timeseries.DataPoint +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.ForgeryFactory + +internal class DataPointForgeryFactory : ForgeryFactory> { + override fun getForgery(forge: Forge): DataPoint = DataPoint( + timestampNs = forge.aPositiveLong(), + value = forge.aDouble() + ) +} diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/assertj/TelemetryUsageEventAssert.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/assertj/TelemetryUsageEventAssert.kt index 1bad1f04c7..38950c8fda 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/assertj/TelemetryUsageEventAssert.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/assertj/TelemetryUsageEventAssert.kt @@ -181,6 +181,11 @@ internal class TelemetryUsageEventAssert(actual: TelemetryUsageEvent) : .isInstanceOf(TelemetryUsageEvent.Usage.TrackWebView::class.java) } + is InternalTelemetryEvent.ApiUsage.Timeseries -> { + assertThat(actual.telemetry.usage) + .isInstanceOf(TelemetryUsageEvent.Usage.Timeseries::class.java) + } + is InternalTelemetryEvent.ApiUsage.NetworkInstrumentation -> { val actualUsage = actual.telemetry.usage as TelemetryUsageEvent.Usage.AndroidNetworkInstrumentation diff --git a/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_cpu_batch1.json b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_cpu_batch1.json new file mode 100644 index 0000000000..9808a056a7 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_cpu_batch1.json @@ -0,0 +1,78 @@ +{ + "date": 1700000001000, + "application": { + "id": "fake-app-id", + "current_locale": "en-US" + }, + "service": "fake-service", + "version": "1.2.3", + "build_version": "42", + "build_id": "fake-app-build-id", + "ddtags": "service:fake-service,version:1.2.3,sdk_version:2.0.0,env:fake-env,variant:fake-variant", + "session": { + "id": "fake-session-id", + "type": "user", + "has_replay": true + }, + "source": "android", + "os": { + "name": "Android", + "version": "13.0.1", + "version_major": "13" + }, + "device": { + "type": "mobile", + "name": "fake-device-name", + "model": "fake-device-model", + "brand": "fake-device-brand", + "architecture": "arm64-v8a", + "locales": [ + "en-US", + "fr-FR" + ], + "time_zone": "America/New_York", + "battery_level": 0.42, + "power_saving_mode": true, + "brightness_level": 128, + "logical_cpu_count": 8, + "total_ram": 4096, + "is_low_ram": false + }, + "_dd": { + "format_version": 2, + "session": { + "session_precondition": "user_app_launch" + }, + "configuration": { + "session_sample_rate": 42.0, + "session_replay_sample_rate": 75, + "trace_sample_rate": 20.0 + } + }, + "type": "timeseries", + "timeseries": { + "id": "00000000-0000-0000-0000-000000000000", + "name": "cpu", + "schema": "object-v2", + "start": 1700000001000000000, + "end": 1700000005000000000, + "data": { + "timestamps": [ + 1700000001000000000, + 1700000002000000000, + 1700000003000000000, + 1700000004000000000, + 1700000005000000000 + ], + "values": { + "cpu_usage": [ + 12.5, + 14.2, + 11.8, + 16.3, + 13.7 + ] + } + } + } +} diff --git a/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_cpu_batch2.json b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_cpu_batch2.json new file mode 100644 index 0000000000..80fce478c4 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_cpu_batch2.json @@ -0,0 +1,78 @@ +{ + "date": 1700000001000, + "application": { + "id": "fake-app-id", + "current_locale": "en-US" + }, + "service": "fake-service", + "version": "1.2.3", + "build_version": "42", + "build_id": "fake-app-build-id", + "ddtags": "service:fake-service,version:1.2.3,sdk_version:2.0.0,env:fake-env,variant:fake-variant", + "session": { + "id": "fake-session-id", + "type": "user", + "has_replay": true + }, + "source": "android", + "os": { + "name": "Android", + "version": "13.0.1", + "version_major": "13" + }, + "device": { + "type": "mobile", + "name": "fake-device-name", + "model": "fake-device-model", + "brand": "fake-device-brand", + "architecture": "arm64-v8a", + "locales": [ + "en-US", + "fr-FR" + ], + "time_zone": "America/New_York", + "battery_level": 0.42, + "power_saving_mode": true, + "brightness_level": 128, + "logical_cpu_count": 8, + "total_ram": 4096, + "is_low_ram": false + }, + "_dd": { + "format_version": 2, + "session": { + "session_precondition": "user_app_launch" + }, + "configuration": { + "session_sample_rate": 42.0, + "session_replay_sample_rate": 75, + "trace_sample_rate": 20.0 + } + }, + "type": "timeseries", + "timeseries": { + "id": "00000000-0000-0000-0000-000000000000", + "name": "cpu", + "schema": "object-v2", + "start": 1700000006000000000, + "end": 1700000010000000000, + "data": { + "timestamps": [ + 1700000006000000000, + 1700000007000000000, + 1700000008000000000, + 1700000009000000000, + 1700000010000000000 + ], + "values": { + "cpu_usage": [ + 18.1, + 22.4, + 19.6, + 15.9, + 13.2 + ] + } + } + } +} diff --git a/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_memory_batch1.json b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_memory_batch1.json new file mode 100644 index 0000000000..c3eb2f54c2 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_memory_batch1.json @@ -0,0 +1,85 @@ +{ + "date": 1700000001000, + "application": { + "id": "fake-app-id", + "current_locale": "en-US" + }, + "service": "fake-service", + "version": "1.2.3", + "build_version": "42", + "build_id": "fake-app-build-id", + "ddtags": "service:fake-service,version:1.2.3,sdk_version:2.0.0,env:fake-env,variant:fake-variant", + "session": { + "id": "fake-session-id", + "type": "user", + "has_replay": true + }, + "source": "android", + "os": { + "name": "Android", + "version": "13.0.1", + "version_major": "13" + }, + "device": { + "type": "mobile", + "name": "fake-device-name", + "model": "fake-device-model", + "brand": "fake-device-brand", + "architecture": "arm64-v8a", + "locales": [ + "en-US", + "fr-FR" + ], + "time_zone": "America/New_York", + "battery_level": 0.42, + "power_saving_mode": true, + "brightness_level": 128, + "logical_cpu_count": 8, + "total_ram": 4096, + "is_low_ram": false + }, + "_dd": { + "format_version": 2, + "session": { + "session_precondition": "user_app_launch" + }, + "configuration": { + "session_sample_rate": 42.0, + "session_replay_sample_rate": 75, + "trace_sample_rate": 20.0 + } + }, + "type": "timeseries", + "timeseries": { + "id": "00000000-0000-0000-0000-000000000000", + "name": "memory", + "schema": "object-v2", + "start": 1700000001000000000, + "end": 1700000005000000000, + "data": { + "timestamps": [ + 1700000001000000000, + 1700000002000000000, + 1700000003000000000, + 1700000004000000000, + 1700000005000000000 + ], + "values": { + "memory_footprint": [ + 31233.3, + 31245.5, + 31300.8, + 31289.1, + 31350.0 + ], + "memory_percent": [ + 3.12333, + 3.12455, + 3.13008, + 3.12891, + 3.135 + ] + } + } + } +} diff --git a/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_memory_batch2.json b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_memory_batch2.json new file mode 100644 index 0000000000..ed1a216f6c --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/expected_memory_batch2.json @@ -0,0 +1,85 @@ +{ + "date": 1700000001000, + "application": { + "id": "fake-app-id", + "current_locale": "en-US" + }, + "service": "fake-service", + "version": "1.2.3", + "build_version": "42", + "build_id": "fake-app-build-id", + "ddtags": "service:fake-service,version:1.2.3,sdk_version:2.0.0,env:fake-env,variant:fake-variant", + "session": { + "id": "fake-session-id", + "type": "user", + "has_replay": true + }, + "source": "android", + "os": { + "name": "Android", + "version": "13.0.1", + "version_major": "13" + }, + "device": { + "type": "mobile", + "name": "fake-device-name", + "model": "fake-device-model", + "brand": "fake-device-brand", + "architecture": "arm64-v8a", + "locales": [ + "en-US", + "fr-FR" + ], + "time_zone": "America/New_York", + "battery_level": 0.42, + "power_saving_mode": true, + "brightness_level": 128, + "logical_cpu_count": 8, + "total_ram": 4096, + "is_low_ram": false + }, + "_dd": { + "format_version": 2, + "session": { + "session_precondition": "user_app_launch" + }, + "configuration": { + "session_sample_rate": 42.0, + "session_replay_sample_rate": 75, + "trace_sample_rate": 20.0 + } + }, + "type": "timeseries", + "timeseries": { + "id": "00000000-0000-0000-0000-000000000000", + "name": "memory", + "schema": "object-v2", + "start": 1700000006000000000, + "end": 1700000010000000000, + "data": { + "timestamps": [ + 1700000006000000000, + 1700000007000000000, + 1700000008000000000, + 1700000009000000000, + 1700000010000000000 + ], + "values": { + "memory_footprint": [ + 31420.2, + 31510.4, + 31498.7, + 31550.3, + 31600.1 + ], + "memory_percent": [ + 3.14202, + 3.15104, + 3.14987, + 3.15503, + 3.16001 + ] + } + } + } +} diff --git a/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/input_memory_cpu.csv b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/input_memory_cpu.csv new file mode 100644 index 0000000000..992dead619 --- /dev/null +++ b/features/dd-sdk-android-rum/src/test/resources/fixtures/timeseries/input_memory_cpu.csv @@ -0,0 +1,21 @@ +timestamp,metric,value +1700000001000000000,memory_usage,31233300 +1700000001000000000,cpu_usage,12.5 +1700000002000000000,memory_usage,31245500 +1700000002000000000,cpu_usage,14.2 +1700000003000000000,memory_usage,31300800 +1700000003000000000,cpu_usage,11.8 +1700000004000000000,memory_usage,31289100 +1700000004000000000,cpu_usage,16.3 +1700000005000000000,memory_usage,31350000 +1700000005000000000,cpu_usage,13.7 +1700000006000000000,memory_usage,31420200 +1700000006000000000,cpu_usage,18.1 +1700000007000000000,memory_usage,31510400 +1700000007000000000,cpu_usage,22.4 +1700000008000000000,memory_usage,31498700 +1700000008000000000,cpu_usage,19.6 +1700000009000000000,memory_usage,31550300 +1700000009000000000,cpu_usage,15.9 +1700000010000000000,memory_usage,31600100 +1700000010000000000,cpu_usage,13.2 diff --git a/features/dd-sdk-android-rum/src/testFixtures/kotlin/com/datadog/android/rum/assertj/TimeseriesCpuEventAssert.kt b/features/dd-sdk-android-rum/src/testFixtures/kotlin/com/datadog/android/rum/assertj/TimeseriesCpuEventAssert.kt new file mode 100644 index 0000000000..c93475340d --- /dev/null +++ b/features/dd-sdk-android-rum/src/testFixtures/kotlin/com/datadog/android/rum/assertj/TimeseriesCpuEventAssert.kt @@ -0,0 +1,169 @@ +/* + * 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.rum.assertj + +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesCpuEvent.TimeseriesCpuEventSessionType +import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.data.Offset +import java.util.UUID + +class TimeseriesCpuEventAssert private constructor( + private val actual: TimeseriesCpuEvent +) { + + fun hasApplicationId(expected: String) = apply { + assertThat(actual.application.id) + .overridingErrorMessage { + "Expected event to have application.id $expected " + + "but was ${actual.application.id}" + } + .isEqualTo(expected) + } + + fun hasSessionId(expected: String) = apply { + assertThat(actual.session.id) + .overridingErrorMessage { + "Expected event to have session.id $expected but was ${actual.session.id}" + } + .isEqualTo(expected) + } + + fun hasSessionType(expected: TimeseriesCpuEventSessionType) = apply { + assertThat(actual.session.type) + .overridingErrorMessage { + "Expected event to have session.type $expected but was ${actual.session.type}" + } + .isEqualTo(expected) + } + + fun hasService(expected: String) = apply { + assertThat(actual.service) + .overridingErrorMessage { "Expected event to have service $expected but was ${actual.service}" } + .isEqualTo(expected) + } + + fun hasVersion(expected: String) = apply { + assertThat(actual.version) + .overridingErrorMessage { "Expected event to have version $expected but was ${actual.version}" } + .isEqualTo(expected) + } + + fun hasDate(expected: Long) = apply { + assertThat(actual.date) + .overridingErrorMessage { "Expected event to have date $expected but was ${actual.date}" } + .isEqualTo(expected) + } + + fun hasTimeseriesName(expected: String) = apply { + assertThat(actual.timeseries.name) + .overridingErrorMessage { + "Expected event to have timeseries.name $expected but was ${actual.timeseries.name}" + } + .isEqualTo(expected) + } + + fun hasTimeseriesSchema(expected: String) = apply { + assertThat(actual.timeseries.schema) + .overridingErrorMessage { + "Expected event to have timeseries.schema $expected but was ${actual.timeseries.schema}" + } + .isEqualTo(expected) + } + + fun hasTimeseriesStart(expected: Long) = apply { + assertThat(actual.timeseries.start) + .overridingErrorMessage { + "Expected event to have timeseries.start $expected but was ${actual.timeseries.start}" + } + .isEqualTo(expected) + } + + fun hasTimeseriesEnd(expected: Long) = apply { + assertThat(actual.timeseries.end) + .overridingErrorMessage { + "Expected event to have timeseries.end $expected but was ${actual.timeseries.end}" + } + .isEqualTo(expected) + } + + fun hasTimeseriesStartNotAfterEnd() = apply { + assertThat(actual.timeseries.start) + .overridingErrorMessage { + "Expected timeseries.start ${actual.timeseries.start} to be less than or equal to " + + "timeseries.end ${actual.timeseries.end}" + } + .isLessThanOrEqualTo(actual.timeseries.end) + } + + fun hasValidTimeseriesId() = apply { + val parsedTimeseriesId = runCatching { UUID.fromString(actual.timeseries.id) }.getOrNull() + + assertThat(parsedTimeseriesId) + .overridingErrorMessage { "Expected timeseries.id to be a valid UUID but was ${actual.timeseries.id}" } + .isNotNull() + } + + fun hasSameTimeseriesAs(expected: TimeseriesCpuEvent) = apply { + val expectedCpuUsage = expected.timeseries.data.values.cpuUsage + val actualCpuUsage = actual.timeseries.data.values.cpuUsage + + hasTimeseriesName(expected.timeseries.name) + .hasTimeseriesSchema(expected.timeseries.schema) + .hasTimeseriesStart(expected.timeseries.start) + .hasTimeseriesEnd(expected.timeseries.end) + .hasTimestamps(*expected.timeseries.data.timestamps.toLongArray()) + + assertThat(actualCpuUsage) + .overridingErrorMessage { + "Expected CPU values count ${expectedCpuUsage.size} but was ${actualCpuUsage.size}" + } + .hasSameSizeAs(expectedCpuUsage) + + expectedCpuUsage.forEachIndexed { position, expectedValue -> + hasCpuUsage(expectedValue.toDouble(), position) + } + } + + fun hasDataPointsCount(expected: Int) = apply { + val timestampsCount = actual.timeseries.data.timestamps.size + + assertThat(timestampsCount) + .overridingErrorMessage { + "Expected timeseries data to contain $expected datapoints but contained $timestampsCount" + } + .isEqualTo(expected) + } + + fun hasTimestamps(vararg expected: Long) = apply { + assertThat(actual.timeseries.data.timestamps) + .overridingErrorMessage { + "Expected timeseries timestamps ${expected.toList()} but was ${actual.timeseries.data.timestamps}" + } + .containsExactlyElementsOf(expected.toList()) + } + + fun hasCpuUsage(expected: Double, position: Int = 0) = apply { + val cpuUsage = actual.timeseries.data.values.cpuUsage.getOrNull(position)?.toDouble() + + assertThat(checkNotNull(cpuUsage)) + .overridingErrorMessage { "Expected first data point cpu_usage to be close to $expected but was $cpuUsage" } + .isCloseTo(expected, Offset.offset(NUMBER_COMPARISON_TOLERANCE)) + } + + companion object { + private const val NUMBER_COMPARISON_TOLERANCE = 1e-9 + + fun assertThat(actual: TimeseriesCpuEvent?): TimeseriesCpuEventAssert { + Assertions.assertThat(actual) + .overridingErrorMessage { "Expected timeseries event to be present" } + .isNotNull() + return TimeseriesCpuEventAssert(checkNotNull(actual)) + } + } +} diff --git a/features/dd-sdk-android-rum/src/testFixtures/kotlin/com/datadog/android/rum/assertj/TimeseriesMemoryEventAssert.kt b/features/dd-sdk-android-rum/src/testFixtures/kotlin/com/datadog/android/rum/assertj/TimeseriesMemoryEventAssert.kt new file mode 100644 index 0000000000..33837b7b57 --- /dev/null +++ b/features/dd-sdk-android-rum/src/testFixtures/kotlin/com/datadog/android/rum/assertj/TimeseriesMemoryEventAssert.kt @@ -0,0 +1,203 @@ +/* + * 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.rum.assertj + +import com.datadog.android.rum.model.TimeseriesMemoryEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent.TimeseriesMemoryEventSessionType +import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.data.Offset +import java.util.UUID + +class TimeseriesMemoryEventAssert private constructor( + private val actual: TimeseriesMemoryEvent +) { + + fun hasApplicationId(expected: String) = apply { + assertThat(actual.application.id) + .overridingErrorMessage { + "Expected event to have application.id $expected " + + "but was ${actual.application.id}" + } + .isEqualTo(expected) + } + + fun hasSessionId(expected: String) = apply { + assertThat(actual.session.id) + .overridingErrorMessage { + "Expected event to have session.id $expected but was ${actual.session.id}" + } + .isEqualTo(expected) + } + + fun hasSessionType(expected: TimeseriesMemoryEventSessionType) = apply { + assertThat(actual.session.type) + .overridingErrorMessage { + "Expected event to have session.type $expected but was ${actual.session.type}" + } + .isEqualTo(expected) + } + + fun hasService(expected: String) = apply { + assertThat(actual.service) + .overridingErrorMessage { "Expected event to have service $expected but was ${actual.service}" } + .isEqualTo(expected) + } + + fun hasVersion(expected: String) = apply { + assertThat(actual.version) + .overridingErrorMessage { "Expected event to have version $expected but was ${actual.version}" } + .isEqualTo(expected) + } + + fun hasDate(expected: Long) = apply { + assertThat(actual.date) + .overridingErrorMessage { "Expected event to have date $expected but was ${actual.date}" } + .isEqualTo(expected) + } + + fun hasTimeseriesName(expected: String) = apply { + assertThat(actual.timeseries.name) + .overridingErrorMessage { + "Expected event to have timeseries.name $expected but was ${actual.timeseries.name}" + } + .isEqualTo(expected) + } + + fun hasTimeseriesSchema(expected: String) = apply { + assertThat(actual.timeseries.schema) + .overridingErrorMessage { + "Expected event to have timeseries.schema $expected but was ${actual.timeseries.schema}" + } + .isEqualTo(expected) + } + + fun hasTimeseriesStart(expected: Long) = apply { + assertThat(actual.timeseries.start) + .overridingErrorMessage { + "Expected event to have timeseries.start $expected but was ${actual.timeseries.start}" + } + .isEqualTo(expected) + } + + fun hasTimeseriesEnd(expected: Long) = apply { + assertThat(actual.timeseries.end) + .overridingErrorMessage { + "Expected event to have timeseries.end $expected but was ${actual.timeseries.end}" + } + .isEqualTo(expected) + } + + fun hasTimeseriesStartNotAfterEnd() = apply { + assertThat(actual.timeseries.start) + .overridingErrorMessage { + "Expected timeseries.start ${actual.timeseries.start} to be less than or equal to " + + "timeseries.end ${actual.timeseries.end}" + } + .isLessThanOrEqualTo(actual.timeseries.end) + } + + fun hasValidTimeseriesId() = apply { + val parsedTimeseriesId = runCatching { UUID.fromString(actual.timeseries.id) }.getOrNull() + + assertThat(parsedTimeseriesId) + .overridingErrorMessage { "Expected timeseries.id to be a valid UUID but was ${actual.timeseries.id}" } + .isNotNull() + } + + fun hasSameTimeseriesAs(expected: TimeseriesMemoryEvent) = apply { + val expectedTimeseries = expected.timeseries + val expectedMemoryFootprint = expectedTimeseries.data.values.memoryFootprint + val actualMemoryFootprint = actual.timeseries.data.values.memoryFootprint + val expectedMemoryPercent = expectedTimeseries.data.values.memoryPercent + val actualMemoryPercent = actual.timeseries.data.values.memoryPercent + + hasTimeseriesName(expectedTimeseries.name) + .hasTimeseriesSchema(expectedTimeseries.schema) + .hasTimeseriesStart(expectedTimeseries.start) + .hasTimeseriesEnd(expectedTimeseries.end) + .hasTimestamps(*expectedTimeseries.data.timestamps.toLongArray()) + + assertThat(actualMemoryFootprint) + .overridingErrorMessage { + "Expected memory footprint values count ${expectedMemoryFootprint.size} " + + "but was ${actualMemoryFootprint.size}" + } + .hasSameSizeAs(expectedMemoryFootprint) + assertThat(actualMemoryPercent) + .overridingErrorMessage { + "Expected memory percent values count ${expectedMemoryPercent.size} " + + "but was ${actualMemoryPercent.size}" + } + .hasSameSizeAs(expectedMemoryPercent) + expectedMemoryFootprint.forEachIndexed { position, expectedValue -> + hasMemoryFootprint(expectedValue.toDouble(), NUMBER_COMPARISON_TOLERANCE, position) + } + expectedMemoryPercent.forEachIndexed { position, expectedValue -> + hasMemoryPercent(expectedValue.toDouble(), NUMBER_COMPARISON_TOLERANCE, position) + } + } + + fun hasDataPointsCount(expected: Int) = apply { + val timestampsCount = actual.timeseries.data.timestamps.size + + assertThat(timestampsCount) + .overridingErrorMessage { + "Expected timeseries data to contain $expected datapoints but contained $timestampsCount" + } + .isEqualTo(expected) + } + + fun hasTimestamps(vararg expected: Long) = apply { + assertThat(actual.timeseries.data.timestamps) + .overridingErrorMessage { + "Expected timeseries timestamps ${expected.toList()} but was ${actual.timeseries.data.timestamps}" + } + .containsExactlyElementsOf(expected.toList()) + } + + fun hasMemoryFootprint(expected: Double, offset: Double, position: Int = 0) = apply { + val memoryFootprint = actual.timeseries.data.values.memoryFootprint.getOrNull(position)?.toDouble() + + assertThat(memoryFootprint) + .overridingErrorMessage { + "Expected memory footprint data point at position $position to be present" + } + .isNotNull() + assertThat(checkNotNull(memoryFootprint)) + .overridingErrorMessage { + "Expected memory footprint at position $position to be close to $expected but was $memoryFootprint" + } + .isCloseTo(expected, Offset.offset(offset)) + } + + fun hasMemoryPercent(expected: Double, offset: Double, position: Int = 0) = apply { + val memoryPercent = actual.timeseries.data.values.memoryPercent.getOrNull(position)?.toDouble() + + assertThat(memoryPercent) + .overridingErrorMessage { + "Expected memory percent data point at position $position to be present" + } + .isNotNull() + assertThat(checkNotNull(memoryPercent)) + .overridingErrorMessage { + "Expected memory percent at position $position to be close to $expected but was $memoryPercent" + } + .isCloseTo(expected, Offset.offset(offset)) + } + + companion object { + private const val NUMBER_COMPARISON_TOLERANCE = 1e-9 + + fun assertThat(actual: TimeseriesMemoryEvent?): TimeseriesMemoryEventAssert { + Assertions.assertThat(actual) + .overridingErrorMessage { "Expected timeseries event to be present" } + .isNotNull() + return TimeseriesMemoryEventAssert(checkNotNull(actual)) + } + } +} diff --git a/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/rum/TimeseriesCollectionTest.kt b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/rum/TimeseriesCollectionTest.kt new file mode 100644 index 0000000000..928faadfb9 --- /dev/null +++ b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/integration/rum/TimeseriesCollectionTest.kt @@ -0,0 +1,176 @@ +/* + * 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.sdk.integration.rum + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.platform.app.InstrumentationRegistry +import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.rum.model.TimeseriesCpuEvent +import com.datadog.android.rum.model.TimeseriesMemoryEvent +import com.datadog.android.sdk.integration.RuntimeConfig +import com.datadog.android.sdk.integration.rum.TimeseriesTrackingPlaygroundActivity.Companion.SAMPLE_INTERVAL_MS +import com.datadog.android.sdk.rules.HandledRequest +import com.datadog.android.sdk.rules.RumMockServerActivityTestRule +import com.datadog.tools.unit.ConditionWatcher +import com.google.gson.JsonObject +import org.assertj.core.api.Assertions.assertThat +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@LargeTest +internal class TimeseriesCollectionTest { + + @get:Rule + val mockServerRule = RumMockServerActivityTestRule( + TimeseriesTrackingPlaygroundActivity::class.java, + keepRequests = true, + trackingConsent = TrackingConsent.GRANTED + ) + + @Test + fun verifyCpuAndMemoryTimeseriesAreCollected() { + // Given + Thread.sleep(FOREGROUND_COLLECTION_DURATION_MS) + + // When + moveActivityToBackground() + val events: List = waitForTimeseriesEvents(expectedCount = TIMESERIES_PIPELINE_COUNT) + + // Then + assertTrue(events.size >= TIMESERIES_PIPELINE_COUNT) + events.assertForegroundDataPointCounts(EXPECTED_FOREGROUND_MEMORY_DATA_POINTS) + } + + @Test + fun verifyCollectionFlushesPausesAndResumesAcrossBackgroundTransition() { + // Given + Thread.sleep(FOREGROUND_COLLECTION_DURATION_MS) + + // When + moveActivityToBackground() + val firstForegroundEvents = waitForTimeseriesEvents(expectedCount = TIMESERIES_PIPELINE_COUNT) + Thread.sleep(BACKGROUND_OBSERVATION_DURATION_MS) + val backgroundEvents = timeseriesEvents() + moveActivityToForeground() + Thread.sleep(FOREGROUND_COLLECTION_DURATION_MS) + moveActivityToBackground() + val secondForegroundEvents = waitForTimeseriesEvents(expectedCount = TIMESERIES_PIPELINE_COUNT * 2) + + // Then + assertEquals(TIMESERIES_PIPELINE_COUNT, firstForegroundEvents.size) + firstForegroundEvents.assertForegroundDataPointCounts(EXPECTED_FOREGROUND_MEMORY_DATA_POINTS) + assertThat(firstForegroundEvents.size).isEqualTo(backgroundEvents.size) + assertThat(secondForegroundEvents.size).isEqualTo(TIMESERIES_PIPELINE_COUNT * 2) + secondForegroundEvents.assertForegroundDataPointCounts(EXPECTED_FOREGROUND_MEMORY_DATA_POINTS) + } + + private fun moveActivityToBackground() { + val instrumentation = InstrumentationRegistry.getInstrumentation() + instrumentation.runOnMainSync { + instrumentation.callActivityOnPause(mockServerRule.activity) + instrumentation.callActivityOnStop(mockServerRule.activity) + } + instrumentation.waitForIdleSync() + } + + private fun moveActivityToForeground() { + val instrumentation = InstrumentationRegistry.getInstrumentation() + instrumentation.runOnMainSync { + instrumentation.callActivityOnStart(mockServerRule.activity) + instrumentation.callActivityOnResume(mockServerRule.activity) + } + instrumentation.waitForIdleSync() + } + + private fun waitForTimeseriesEvents(expectedCount: Int): List { + var events = emptyList() + ConditionWatcher { + events = timeseriesEvents() + assertTrue(events.size >= expectedCount) + true + }.doWait(timeoutMs = RumTest.FINAL_WAIT_MS) + return events + } + + private fun timeseriesEvents(): List = mockServerRule + .getRequests(RuntimeConfig.rumEndpointUrl) + .rumEvents() + .filter { it.get(TYPE_KEY)?.asString == TIMESERIES_TYPE } + + private fun List.rumEvents(): List = flatMap { request -> + request.textBody?.let(::rumPayloadToJsonList).orEmpty() + } + + companion object { + private const val CPU_TIMESERIES_NAME = "cpu" + private const val MEMORY_TIMESERIES_NAME = "memory" + private const val TIMESERIES_TYPE = "timeseries" + private const val TYPE_KEY = "type" + private const val TIMESERIES_KEY = "timeseries" + private const val NAME_KEY = "name" + + // One independent pipeline for each timeseries source: CPU and memory. + private const val TIMESERIES_PIPELINE_COUNT = 2 + + // Backgrounding defers the flush twice: ActivityViewTrackingStrategy waits before stopping + // the view, then the collector waits before suspending sampling and flushing the buffers. + private const val ACTIVITY_STOP_DELAY_MS = 200L + private const val TIMESERIES_SUSPEND_DELAY_MS = 200L + private const val FLUSH_DELAY_MS = ACTIVITY_STOP_DELAY_MS + TIMESERIES_SUSPEND_DELAY_MS + + // Sized so the flush lands in the middle of a sampling interval, leaving half an interval + // of room on either side before the expected data point count changes. + private const val FOREGROUND_COLLECTION_DURATION_MS = + SAMPLE_INTERVAL_MS * 3 + SAMPLE_INTERVAL_MS / 2 - FLUSH_DELAY_MS + private const val UPLOAD_GRACE_PERIOD_MS = 500L + private const val BACKGROUND_OBSERVATION_DURATION_MS = + SAMPLE_INTERVAL_MS + UPLOAD_GRACE_PERIOD_MS + + private const val EXPECTED_FOREGROUND_MEMORY_DATA_POINTS = + ((FOREGROUND_COLLECTION_DURATION_MS + FLUSH_DELAY_MS) / SAMPLE_INTERVAL_MS).toInt() + + // Sampling shares a single executor with the other vitals on a device the test does not + // own, so a stalled tick costs a data point and a late flush adds one. Keeps the lower + // bound at two points, so the CPU event — which trails memory by one — always exists. + private const val DATA_POINTS_TOLERANCE = 1 + + private val JsonObject.timeseriesName: String? + get() = getAsJsonObject(TIMESERIES_KEY).get(NAME_KEY).asString + + private fun List.filterByName(name: String): List = filter { it.timeseriesName == name } + + private fun List.cpuEvents(): List = + filterByName(CPU_TIMESERIES_NAME).map(TimeseriesCpuEvent::fromJsonObject) + + private fun List.memoryEvents(): List = + filterByName(MEMORY_TIMESERIES_NAME).map(TimeseriesMemoryEvent::fromJsonObject) + + /** + * Asserts the data point count of every foreground batch: memory within the tolerance of + * the collection window, CPU exactly one point behind memory, because the first CPU read + * only establishes the delta baseline and yields no data point. + */ + private fun List.assertForegroundDataPointCounts( + expected: Int, + tolerance: Int = DATA_POINTS_TOLERANCE + ) { + val memoryDataPointCounts = memoryEvents().map { it.timeseries.data.timestamps.size } + val cpuDataPointCounts = cpuEvents().map { it.timeseries.data.timestamps.size } + + memoryDataPointCounts.forEach { count -> + assertThat(count).isBetween(expected - tolerance, expected + tolerance) + } + assertThat(cpuDataPointCounts) + .containsExactlyElementsOf(memoryDataPointCounts.map { it - 1 }) + } + } +} diff --git a/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/rules/MockServerActivityTestRule.kt b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/rules/MockServerActivityTestRule.kt index 1c5393f0a5..8389680c76 100644 --- a/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/rules/MockServerActivityTestRule.kt +++ b/instrumented/integration/src/androidTest/kotlin/com/datadog/android/sdk/rules/MockServerActivityTestRule.kt @@ -26,6 +26,7 @@ import okhttp3.mockwebserver.MockWebServer import org.junit.runner.Description import org.junit.runners.model.Statement import java.io.File +import java.util.concurrent.CopyOnWriteArrayList internal open class MockServerActivityTestRule( val activityClass: Class, @@ -35,7 +36,7 @@ internal open class MockServerActivityTestRule( private val mockWebServer: MockWebServer = MockWebServer() - private val requests = mutableListOf() + private val requests = CopyOnWriteArrayList() val forge = Forge() diff --git a/instrumented/integration/src/main/AndroidManifest.xml b/instrumented/integration/src/main/AndroidManifest.xml index 2386dcf50c..63ab3ac188 100644 --- a/instrumented/integration/src/main/AndroidManifest.xml +++ b/instrumented/integration/src/main/AndroidManifest.xml @@ -29,6 +29,9 @@ android:name=".rum.ActivityTrackingPlaygroundActivity" android:label="@string/rum_activity_view_tracking_end_to_end" android:windowSoftInputMode="adjustResize"/> + Button1 Rum Gestures (End to End) Rum Activity View (End to End) + RUM timeseries end-to-end Telemetry (End to End) Session Replay (End to End) Session Replay Text Fields (End to End) diff --git a/sample/kotlin/src/main/kotlin/com/datadog/android/sample/SampleApplication.kt b/sample/kotlin/src/main/kotlin/com/datadog/android/sample/SampleApplication.kt index c25127996f..6c83ddc477 100644 --- a/sample/kotlin/src/main/kotlin/com/datadog/android/sample/SampleApplication.kt +++ b/sample/kotlin/src/main/kotlin/com/datadog/android/sample/SampleApplication.kt @@ -41,6 +41,7 @@ import com.datadog.android.rum.RumConfiguration import com.datadog.android.rum.RumErrorSource import com.datadog.android.rum.configuration.RumNetworkInstrumentationConfiguration import com.datadog.android.rum.resource.ResourceHeadersExtractor +import com.datadog.android.rum.timeseries.TimeseriesConfiguration import com.datadog.android.rum.tracking.NavigationViewTrackingStrategy import com.datadog.android.sample.account.AccountFragment import com.datadog.android.sample.data.db.LocalDataSource @@ -431,6 +432,7 @@ class SampleApplication : Application() { .trackAnonymousUser(true) .enableComposeActionTracking() .collectAccessibility(true) + .setTimeseriesConfiguration(TimeseriesConfiguration.DEFAULT) .build() }