diff --git a/dd-sdk-android-core/api/apiSurface b/dd-sdk-android-core/api/apiSurface index 6c7560c9ca..467989ba77 100644 --- a/dd-sdk-android-core/api/apiSurface +++ b/dd-sdk-android-core/api/apiSurface @@ -44,6 +44,7 @@ interface com.datadog.android.api.InternalLogger - TELEMETRY fun log(Level, Target, () -> String, Throwable? = null, Boolean = false, Map? = null) fun log(Level, List, () -> String, Throwable? = null, Boolean = false, Map? = null) + fun logMetric(() -> String, Map) companion object val UNBOUND: InternalLogger interface com.datadog.android.api.SdkCore diff --git a/dd-sdk-android-core/api/dd-sdk-android-core.api b/dd-sdk-android-core/api/dd-sdk-android-core.api index 492a1e6b2d..b6d1db9d88 100644 --- a/dd-sdk-android-core/api/dd-sdk-android-core.api +++ b/dd-sdk-android-core/api/dd-sdk-android-core.api @@ -77,6 +77,7 @@ public abstract interface class com/datadog/android/api/InternalLogger { public static final field Companion Lcom/datadog/android/api/InternalLogger$Companion; public abstract fun log (Lcom/datadog/android/api/InternalLogger$Level;Lcom/datadog/android/api/InternalLogger$Target;Lkotlin/jvm/functions/Function0;Ljava/lang/Throwable;ZLjava/util/Map;)V public abstract fun log (Lcom/datadog/android/api/InternalLogger$Level;Ljava/util/List;Lkotlin/jvm/functions/Function0;Ljava/lang/Throwable;ZLjava/util/Map;)V + public abstract fun logMetric (Lkotlin/jvm/functions/Function0;Ljava/util/Map;)V } public final class com/datadog/android/api/InternalLogger$Companion { diff --git a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/api/InternalLogger.kt b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/api/InternalLogger.kt index cf470e1986..49ee2c4c22 100644 --- a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/api/InternalLogger.kt +++ b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/api/InternalLogger.kt @@ -96,6 +96,15 @@ interface InternalLogger { additionalProperties: Map? = null ) + /** + * Logs a specific metric from the internal implementation. The metric values will be sent + * as key-value pairs in the additionalProperties and as part of the + * [com.datadog.android.telemetry.model.TelemetryDebugEvent.Telemetry] event. + * @param messageBuilder the lambda building the metric message + * @param additionalProperties additional properties to add to the metric + */ + fun logMetric(messageBuilder: () -> String, additionalProperties: Map) + companion object { /** diff --git a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/SdkInternalLogger.kt b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/SdkInternalLogger.kt index 7bb37fae5b..c0ab793047 100644 --- a/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/SdkInternalLogger.kt +++ b/dd-sdk-android-core/src/main/kotlin/com/datadog/android/core/SdkInternalLogger.kt @@ -88,6 +88,18 @@ internal class SdkInternalLogger( } } + override fun logMetric(messageBuilder: () -> String, additionalProperties: Map) { + val rumFeature = sdkCore?.getFeature(Feature.RUM_FEATURE_NAME) ?: return + val message = messageBuilder() + val telemetryEvent = + mapOf( + TYPE_KEY to "mobile_metric", + MESSAGE_KEY to message, + ADDITIONAL_PROPERTIES_KEY to additionalProperties + ) + rumFeature.sendEvent(telemetryEvent) + } + // endregion // region Internal diff --git a/dd-sdk-android-core/src/test/kotlin/com/datadog/android/core/SdkInternalLoggerTest.kt b/dd-sdk-android-core/src/test/kotlin/com/datadog/android/core/SdkInternalLoggerTest.kt index 71d1cd3c88..1de21ba5c2 100644 --- a/dd-sdk-android-core/src/test/kotlin/com/datadog/android/core/SdkInternalLoggerTest.kt +++ b/dd-sdk-android-core/src/test/kotlin/com/datadog/android/core/SdkInternalLoggerTest.kt @@ -14,6 +14,7 @@ import com.datadog.android.api.feature.FeatureScope import com.datadog.android.api.feature.FeatureSdkCore import com.datadog.android.utils.forge.Configurator import com.datadog.tools.unit.forge.aThrowable +import com.datadog.tools.unit.forge.exhaustiveAttributes import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.annotation.IntForgery import fr.xgouchet.elmyr.annotation.StringForgery @@ -23,6 +24,7 @@ import fr.xgouchet.elmyr.junit5.ForgeExtension import org.assertj.core.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.Extensions import org.mockito.Mock @@ -444,6 +446,53 @@ internal class SdkInternalLoggerTest { ) } + @Test + fun `𝕄 send metric 𝕎 metric()`( + @StringForgery fakeMessage: String, + forge: Forge + ) { + // Given + val mockRumFeatureScope = mock() + whenever(mockSdkCore.getFeature(Feature.RUM_FEATURE_NAME)) doReturn mockRumFeatureScope + val fakeAdditionalProperties = forge.exhaustiveAttributes() + val mockLambda: () -> String = mock() + whenever(mockLambda.invoke()) doReturn fakeMessage + // When + testedInternalLogger.logMetric( + mockLambda, + fakeAdditionalProperties + ) + + // Then + verify(mockRumFeatureScope) + .sendEvent( + mapOf( + "type" to "mobile_metric", + "message" to fakeMessage, + "additionalProperties" to fakeAdditionalProperties + ) + ) + } + + @Test + fun `𝕄 do nothing metric 𝕎 metric { rum feature not initialized }`( + @StringForgery fakeMessage: String, + forge: Forge + ) { + // Given + whenever(mockSdkCore.getFeature(Feature.RUM_FEATURE_NAME)) doReturn null + val fakeAdditionalProperties = forge.exhaustiveAttributes() + val mockLambda: () -> String = mock() + whenever(mockLambda.invoke()) doReturn fakeMessage + // When + assertDoesNotThrow { + testedInternalLogger.logMetric( + mockLambda, + fakeAdditionalProperties + ) + } + } + private fun InternalLogger.Level.toLogLevel(): Int { return when (this) { InternalLogger.Level.VERBOSE -> Log.VERBOSE 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 d17554151d..887ea5fa02 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 @@ -247,18 +247,20 @@ internal class RumFeature constructor( } when (event["type"]) { - "jvm_crash" -> addJvmCrash(event) - "ndk_crash" -> ndkCrashEventHandler.handleEvent(event, sdkCore, dataWriter) - "logger_error" -> addLoggerError(event) - "logger_error_with_stacktrace" -> addLoggerErrorWithStacktrace(event) - "web_view_ingested_notification" -> { + JVM_CRASH_BUS_MESSAGE_TYPE -> addJvmCrash(event) + NDK_CRASH_BUS_MESSAGE_TYPE -> + ndkCrashEventHandler.handleEvent(event, sdkCore, dataWriter) + LOGGER_ERROR_BUS_MESSAGE_TYPE -> addLoggerError(event) + LOGGER_ERROR_WITH_STACK_TRACE_MESSAGE_TYPE -> addLoggerErrorWithStacktrace(event) + WEB_VIEW_INGESTED_NOTIFICATION_MESSAGE_TYPE -> { (GlobalRumMonitor.get(sdkCore) as? AdvancedRumMonitor)?.sendWebViewEvent() } - "telemetry_error" -> logTelemetryError(event) - "telemetry_debug" -> logTelemetryDebug(event) - "telemetry_configuration" -> logTelemetryConfiguration(event) - "flush_and_stop_monitor" -> { + TELEMETRY_ERROR_MESSAGE_TYPE -> logTelemetryError(event) + TELEMETRY_DEBUG_MESSAGE_TYPE -> logTelemetryDebug(event) + MOBILE_METRIC_MESSAGE_TYPE -> logMetric(event) + TELEMETRY_CONFIG_MESSAGE_TYPE -> logTelemetryConfiguration(event) + FLUSH_AND_STOP_MONITOR_MESSAGE_TYPE -> { (GlobalRumMonitor.get(sdkCore) as? DatadogRumMonitor)?.let { it.stopKeepAliveCallback() it.drainExecutorService() @@ -493,6 +495,22 @@ internal class RumFeature constructor( telemetry.debug(message, additionalProperties) } + private fun logMetric(metricEvent: Map<*, *>) { + val message = metricEvent[EVENT_MESSAGE_PROPERTY] as? String + + @Suppress("UNCHECKED_CAST") + val additionalProperties = metricEvent[EVENT_ADDITIONAL_PROPERTIES] as? Map + if (message == null) { + sdkCore.internalLogger.log( + InternalLogger.Level.WARN, + InternalLogger.Target.MAINTAINER, + { TELEMETRY_MISSING_MESSAGE_FIELD } + ) + return + } + telemetry.metric(message, additionalProperties) + } + private fun logTelemetryConfiguration(event: Map<*, *>) { TelemetryCoreConfiguration.fromEvent(event, sdkCore.internalLogger)?.let { (GlobalRumMonitor.get(sdkCore) as? AdvancedRumMonitor) @@ -527,6 +545,17 @@ internal class RumFeature constructor( internal companion object { + internal const val JVM_CRASH_BUS_MESSAGE_TYPE = "jvm_crash" + internal const val NDK_CRASH_BUS_MESSAGE_TYPE = "ndk_crash" + internal const val LOGGER_ERROR_BUS_MESSAGE_TYPE = "logger_error" + internal const val LOGGER_ERROR_WITH_STACK_TRACE_MESSAGE_TYPE = "logger_error_with_stacktrace" + internal const val WEB_VIEW_INGESTED_NOTIFICATION_MESSAGE_TYPE = "web_view_ingested_notification" + internal const val TELEMETRY_ERROR_MESSAGE_TYPE = "telemetry_error" + internal const val TELEMETRY_DEBUG_MESSAGE_TYPE = "telemetry_debug" + internal const val MOBILE_METRIC_MESSAGE_TYPE = "mobile_metric" + internal const val TELEMETRY_CONFIG_MESSAGE_TYPE = "telemetry_configuration" + internal const val FLUSH_AND_STOP_MONITOR_MESSAGE_TYPE = "flush_and_stop_monitor" + internal const val ALL_IN_SAMPLE_RATE: Float = 100f internal const val DEFAULT_SAMPLE_RATE: Float = 100f internal const val DEFAULT_TELEMETRY_SAMPLE_RATE: Float = 20f diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEvent.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEvent.kt index 17ff0d2d5f..fb6ed56339 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEvent.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEvent.kt @@ -205,6 +205,8 @@ internal sealed class RumRawEvent { val kind: String?, val coreConfiguration: TelemetryCoreConfiguration?, val additionalProperties: Map?, - override val eventTime: Time = Time() + val onlyOnce: Boolean = false, + override val eventTime: Time = Time(), + val isMetric: Boolean = false ) : RumRawEvent() } diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/monitor/AdvancedRumMonitor.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/monitor/AdvancedRumMonitor.kt index ae5b576cab..abb68364f5 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/monitor/AdvancedRumMonitor.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/monitor/AdvancedRumMonitor.kt @@ -54,6 +54,11 @@ internal interface AdvancedRumMonitor : RumMonitor, AdvancedNetworkRumMonitor { kind: String? ) + fun sendMetricEvent( + message: String, + additionalProperties: Map? + ) + @Suppress("FunctionMaxLength") fun sendConfigurationTelemetryEvent(coreConfiguration: TelemetryCoreConfiguration) 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 e52c7fe538..f4da27f870 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 @@ -409,6 +409,20 @@ internal class DatadogRumMonitor( ) } + override fun sendMetricEvent(message: String, additionalProperties: Map?) { + handleEvent( + RumRawEvent.SendTelemetry( + type = TelemetryType.DEBUG, + message = message, + stack = null, + kind = null, + coreConfiguration = null, + additionalProperties = additionalProperties, + isMetric = true + ) + ) + } + override fun sendErrorTelemetryEvent( message: String, throwable: Throwable? diff --git a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/telemetry/internal/Telemetry.kt b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/telemetry/internal/Telemetry.kt index 179a625362..1781369c0b 100644 --- a/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/telemetry/internal/Telemetry.kt +++ b/features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/telemetry/internal/Telemetry.kt @@ -39,4 +39,8 @@ internal class Telemetry( (GlobalRumMonitor.get(sdkCore) as? AdvancedRumMonitor) ?.sendDebugTelemetryEvent(message, additionalProperties) } + fun metric(message: String, additionalProperties: Map? = null) { + (GlobalRumMonitor.get(sdkCore) as? AdvancedRumMonitor) + ?.sendMetricEvent(message, additionalProperties) + } } 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 f182a61a8c..4a790cbe4c 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 @@ -113,7 +113,7 @@ internal class TelemetryEventHandler( val eventIdentity = event.identity - if (seenInCurrentSession.contains(eventIdentity)) { + if (!event.isMetric && seenInCurrentSession.contains(eventIdentity)) { sdkCore.internalLogger.log( InternalLogger.Level.INFO, InternalLogger.Target.MAINTAINER, 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 e173daf104..36e89d0786 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 @@ -1124,6 +1124,69 @@ internal class RumFeatureTest { verifyNoInteractions(mockInternalLogger) } + @Test + fun `𝕄 handle metric event 𝕎 onReceive()`( + @StringForgery fakeMessage: String, + forge: Forge + ) { + // Given + val fakeAdditionalProperties = forge.exhaustiveAttributes() + testedFeature.onInitialize(appContext.mockInstance) + val event = mapOf( + "type" to RumFeature.MOBILE_METRIC_MESSAGE_TYPE, + "message" to fakeMessage, + "additionalProperties" to fakeAdditionalProperties + ) + + // When + testedFeature.onReceive(event) + + // Then + verify(mockRumMonitor).sendMetricEvent(fakeMessage, fakeAdditionalProperties) + verifyNoMoreInteractions(mockRumMonitor) + verifyNoInteractions(mockInternalLogger) + } + + @Test + fun `𝕄 handle metric event 𝕎 onReceive(){no additionalProperties}`( + @StringForgery fakeMessage: String + ) { + // Given + testedFeature.onInitialize(appContext.mockInstance) + val event = mapOf( + "type" to RumFeature.MOBILE_METRIC_MESSAGE_TYPE, + "message" to fakeMessage + ) + + // When + testedFeature.onReceive(event) + + // Then + verify(mockRumMonitor).sendMetricEvent(fakeMessage, null) + verifyNoMoreInteractions(mockRumMonitor) + verifyNoInteractions(mockInternalLogger) + } + + @Test + fun `𝕄 handle metric event 𝕎 onReceive(){no message}`() { + // Given + testedFeature.onInitialize(appContext.mockInstance) + val event = mapOf( + "type" to RumFeature.MOBILE_METRIC_MESSAGE_TYPE + ) + + // When + testedFeature.onReceive(event) + + // Then + mockInternalLogger.verifyLog( + InternalLogger.Level.WARN, + InternalLogger.Target.MAINTAINER, + RumFeature.TELEMETRY_MISSING_MESSAGE_FIELD + ) + verifyNoInteractions(mockRumMonitor) + } + @Test fun `𝕄 log warning 𝕎 onReceive() { telemetry error + message is missing }`() { // Given 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 1af1707459..d89483c54a 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 @@ -1399,6 +1399,7 @@ internal class DatadogRumMonitorTest { assertThat(lastValue.stack).isNull() assertThat(lastValue.kind).isNull() assertThat(lastValue.coreConfiguration).isNull() + assertThat(lastValue.isMetric).isFalse assertThat(lastValue.additionalProperties).isEqualTo(fakeAdditionalProperties) } } @@ -1422,6 +1423,7 @@ internal class DatadogRumMonitorTest { assertThat(lastValue.type).isEqualTo(TelemetryType.ERROR) assertThat(lastValue.stack).isEqualTo(stackTrace) assertThat(lastValue.kind).isEqualTo(kind) + assertThat(lastValue.isMetric).isFalse assertThat(lastValue.coreConfiguration).isNull() } } @@ -1445,6 +1447,7 @@ internal class DatadogRumMonitorTest { assertThat(lastValue.type).isEqualTo(TelemetryType.ERROR) assertThat(lastValue.stack).isEqualTo(throwable?.loggableStackTrace()) assertThat(lastValue.kind).isEqualTo(throwable?.javaClass?.canonicalName) + assertThat(lastValue.isMetric).isFalse assertThat(lastValue.coreConfiguration).isNull() } } @@ -1466,10 +1469,60 @@ internal class DatadogRumMonitorTest { assertThat(lastValue.type).isEqualTo(TelemetryType.CONFIGURATION) assertThat(lastValue.stack).isNull() assertThat(lastValue.kind).isNull() + assertThat(lastValue.isMetric).isFalse assertThat(lastValue.coreConfiguration).isSameAs(fakeConfiguration) } } + @Test + fun `M handle metric event W sendMetricEvent()`( + @StringForgery message: String, + forge: Forge + ) { + // When + val fakeAdditionalProperties = forge.exhaustiveAttributes() + testedMonitor.sendMetricEvent(message, fakeAdditionalProperties) + + // Then + argumentCaptor { + verify(mockTelemetryEventHandler).handleEvent( + capture(), + eq(mockWriter) + ) + assertThat(lastValue.message).isEqualTo(message) + assertThat(lastValue.type).isEqualTo(TelemetryType.DEBUG) + assertThat(lastValue.stack).isNull() + assertThat(lastValue.kind).isNull() + assertThat(lastValue.coreConfiguration).isNull() + assertThat(lastValue.isMetric).isTrue + assertThat(lastValue.additionalProperties) + .containsExactlyInAnyOrderEntriesOf(fakeAdditionalProperties) + } + } + + @Test + fun `M handle metric event W sendMetricEvent(){additionalProperties is null}`( + @StringForgery message: String + ) { + // When + testedMonitor.sendMetricEvent(message, null) + + // Then + argumentCaptor { + verify(mockTelemetryEventHandler).handleEvent( + capture(), + eq(mockWriter) + ) + assertThat(lastValue.message).isEqualTo(message) + assertThat(lastValue.type).isEqualTo(TelemetryType.DEBUG) + assertThat(lastValue.stack).isNull() + assertThat(lastValue.kind).isNull() + assertThat(lastValue.coreConfiguration).isNull() + assertThat(lastValue.isMetric).isTrue + assertThat(lastValue.additionalProperties).isNull() + } + } + @Test fun `M handle interceptor event W notifyInterceptorInstantiated()`() { // When @@ -1485,6 +1538,7 @@ internal class DatadogRumMonitorTest { assertThat(lastValue.type).isEqualTo(TelemetryType.INTERCEPTOR_SETUP) assertThat(lastValue.stack).isNull() assertThat(lastValue.kind).isNull() + assertThat(lastValue.isMetric).isFalse assertThat(lastValue.coreConfiguration).isNull() } } diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/internal/TelemetryEventHandlerTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/internal/TelemetryEventHandlerTest.kt index eac97a81cd..3865a0b526 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/internal/TelemetryEventHandlerTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/internal/TelemetryEventHandlerTest.kt @@ -473,9 +473,11 @@ internal class TelemetryEventHandlerTest { } @Test - fun `𝕄 not write event 𝕎 handleEvent(SendTelemetry) { seen in the session }`(forge: Forge) { + fun `𝕄 not write event 𝕎 handleEvent(SendTelemetry){seen in the session, not metric}`( + forge: Forge + ) { // Given - val rawEvent = forge.createRumRawTelemetryEvent() + val rawEvent = forge.createRumRawTelemetryEvent().copy(isMetric = false) val anotherEvent = rawEvent.copy() // When @@ -519,6 +521,55 @@ internal class TelemetryEventHandlerTest { } } + @Test + fun `𝕄 write event 𝕎 handleEvent(SendTelemetry){seen in the session, is metric}`( + forge: Forge + ) { + // Given + val rawEvent = forge.createRumRawTelemetryEvent().copy(isMetric = true) + val events = listOf(rawEvent, rawEvent.copy()) + + // When + testedTelemetryHandler.handleEvent(events[0], mockWriter) + testedTelemetryHandler.handleEvent(events[1], mockWriter) + + // Then + argumentCaptor { + verify(mockWriter, times(2)).write(eq(mockEventBatchWriter), capture()) + allValues.withIndex().forEach { + when (val capturedValue = it.value) { + is TelemetryDebugEvent -> { + assertDebugEventMatchesRawEvent( + capturedValue, + events[it.index], + fakeRumContext + ) + } + + is TelemetryErrorEvent -> { + assertErrorEventMatchesRawEvent( + capturedValue, + events[it.index], + fakeRumContext + ) + } + + is TelemetryConfigurationEvent -> { + assertConfigEventMatchesRawEvent( + capturedValue, + events[it.index], + fakeRumContext + ) + } + + else -> throw IllegalArgumentException( + "Unexpected type=${lastValue::class.jvmName} of the captured value." + ) + } + } + } + } + @Test fun `𝕄 not write events over the limit 𝕎 handleEvent(SendTelemetry)`(forge: Forge) { // Given @@ -765,7 +816,8 @@ internal class TelemetryEventHandlerTest { null, null, coreConfiguration = null, - additionalProperties = aNullable { exhaustiveAttributes() } + additionalProperties = aNullable { exhaustiveAttributes() }, + isMetric = aBool() ) } @@ -777,7 +829,8 @@ internal class TelemetryEventHandlerTest { throwable?.loggableStackTrace(), throwable?.javaClass?.canonicalName, coreConfiguration = null, - additionalProperties = null + additionalProperties = null, + isMetric = aBool() ) } @@ -790,7 +843,8 @@ internal class TelemetryEventHandlerTest { null, null, coreConfiguration = (configuration ?: getForgery()), - additionalProperties = null + additionalProperties = null, + isMetric = aBool() ) } diff --git a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/internal/TelemetryTest.kt b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/internal/TelemetryTest.kt index 9ef97cf65e..97d2d054a5 100644 --- a/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/internal/TelemetryTest.kt +++ b/features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/telemetry/internal/TelemetryTest.kt @@ -74,6 +74,21 @@ internal class TelemetryTest { .sendDebugTelemetryEvent(message, fakeAdditionalProperties) } + @Test + fun `𝕄 report metric event 𝕎 metric()`( + @StringForgery message: String, + forge: Forge + ) { + // Given + val fakeAdditionalProperties = forge.aNullable { exhaustiveAttributes() } + // When + testedTelemetry.metric(message, fakeAdditionalProperties) + + // Then + verify(rumMonitor.mockInstance as AdvancedRumMonitor) + .sendMetricEvent(message, fakeAdditionalProperties) + } + companion object { val rumMonitor = GlobalRumMonitorTestConfiguration()