-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RUMM-2754: Create implementation of InternalLogger #1155
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2016-Present Datadog, Inc. | ||
*/ | ||
|
||
package com.datadog.android.v2.core | ||
|
||
import android.util.Log | ||
import com.datadog.android.core.internal.utils.devLogger | ||
import com.datadog.android.core.internal.utils.sdkLogger | ||
import com.datadog.android.core.internal.utils.telemetry | ||
import com.datadog.android.v2.api.InternalLogger | ||
|
||
internal object SdkInternalLogger : InternalLogger { | ||
|
||
// region InternalLogger | ||
|
||
override fun log( | ||
level: InternalLogger.Level, | ||
target: InternalLogger.Target, | ||
message: String, | ||
error: Throwable?, | ||
attributes: Map<String, Any?> | ||
) { | ||
when (target) { | ||
// TODO RUMM-2764 we should remove sdkLogger, devLogger and telemetry | ||
// and use only this instance for logging | ||
InternalLogger.Target.USER -> logToUser(level, message, error, attributes) | ||
InternalLogger.Target.MAINTAINER -> logToMaintainer(level, message, error, attributes) | ||
InternalLogger.Target.TELEMETRY -> logToTelemetry(level, message, error) | ||
} | ||
} | ||
|
||
override fun log( | ||
level: InternalLogger.Level, | ||
targets: List<InternalLogger.Target>, | ||
message: String, | ||
error: Throwable?, | ||
attributes: Map<String, Any?> | ||
) { | ||
targets.forEach { | ||
log(level, it, message, error, attributes) | ||
} | ||
} | ||
|
||
// endregion | ||
|
||
// region Internal | ||
|
||
private fun logToUser( | ||
level: InternalLogger.Level, | ||
message: String, | ||
error: Throwable?, | ||
attributes: Map<String, Any?> | ||
) { | ||
devLogger.log( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you don't want to pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, don't want to reference them in the constructor. Anyway it has no real benefit (other than mocking). |
||
level.toLogLevel(), | ||
message, | ||
error, | ||
attributes | ||
) | ||
} | ||
|
||
private fun logToMaintainer( | ||
level: InternalLogger.Level, | ||
message: String, | ||
error: Throwable?, | ||
attributes: Map<String, Any?> | ||
) { | ||
sdkLogger.log( | ||
level.toLogLevel(), | ||
message, | ||
error, | ||
attributes | ||
) | ||
} | ||
|
||
private fun logToTelemetry( | ||
level: InternalLogger.Level, | ||
message: String, | ||
error: Throwable? | ||
) { | ||
if (level == InternalLogger.Level.ERROR || | ||
level == InternalLogger.Level.WARN || | ||
error != null | ||
) { | ||
telemetry.error(message, error) | ||
} else { | ||
telemetry.debug(message) | ||
} | ||
} | ||
|
||
private fun InternalLogger.Level.toLogLevel(): Int { | ||
return when (this) { | ||
InternalLogger.Level.DEBUG -> Log.DEBUG | ||
InternalLogger.Level.INFO -> Log.INFO | ||
InternalLogger.Level.WARN -> Log.WARN | ||
InternalLogger.Level.ERROR -> Log.ERROR | ||
} | ||
} | ||
|
||
// endregion | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
/* | ||
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
* This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
* Copyright 2016-Present Datadog, Inc. | ||
*/ | ||
|
||
package com.datadog.android.v2.core | ||
|
||
import android.util.Log | ||
import com.datadog.android.utils.config.GlobalRumMonitorTestConfiguration | ||
import com.datadog.android.utils.config.LoggerTestConfiguration | ||
import com.datadog.android.utils.forge.Configurator | ||
import com.datadog.android.utils.forge.exhaustiveAttributes | ||
import com.datadog.android.v2.api.InternalLogger | ||
import com.datadog.tools.unit.annotations.TestConfigurationsProvider | ||
import com.datadog.tools.unit.extensions.TestConfigurationExtension | ||
import com.datadog.tools.unit.extensions.config.TestConfiguration | ||
import com.datadog.tools.unit.forge.aThrowable | ||
import com.nhaarman.mockitokotlin2.verify | ||
import fr.xgouchet.elmyr.Forge | ||
import fr.xgouchet.elmyr.annotation.StringForgery | ||
import fr.xgouchet.elmyr.junit5.ForgeConfiguration | ||
import fr.xgouchet.elmyr.junit5.ForgeExtension | ||
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.MockitoSettings | ||
import org.mockito.quality.Strictness | ||
|
||
@Extensions( | ||
ExtendWith(ForgeExtension::class), | ||
ExtendWith(TestConfigurationExtension::class) | ||
) | ||
@MockitoSettings(strictness = Strictness.LENIENT) | ||
@ForgeConfiguration(Configurator::class) | ||
internal class SdkInternalLoggerTest { | ||
|
||
private val testedInternalLogger = SdkInternalLogger | ||
|
||
@Test | ||
fun `𝕄 send dev log 𝕎 log { USER target }`( | ||
@StringForgery fakeMessage: String, | ||
forge: Forge | ||
) { | ||
// Given | ||
val fakeLevel = forge.aValueFrom(InternalLogger.Level::class.java) | ||
val fakeThrowable = forge.aNullable { forge.aThrowable() } | ||
val fakeAttributes = forge.exhaustiveAttributes() | ||
|
||
// When | ||
testedInternalLogger.log( | ||
fakeLevel, | ||
InternalLogger.Target.USER, | ||
fakeMessage, | ||
fakeThrowable, | ||
fakeAttributes | ||
) | ||
|
||
// Then | ||
verify(logger.mockDevLogHandler) | ||
.handleLog( | ||
fakeLevel.toLogLevel(), | ||
fakeMessage, | ||
fakeThrowable, | ||
fakeAttributes | ||
) | ||
} | ||
|
||
@Test | ||
fun `𝕄 send sdk log 𝕎 log { MAINTAINER target }`( | ||
@StringForgery fakeMessage: String, | ||
forge: Forge | ||
) { | ||
// Given | ||
val fakeLevel = forge.aValueFrom(InternalLogger.Level::class.java) | ||
val fakeThrowable = forge.aNullable { forge.aThrowable() } | ||
val fakeAttributes = forge.exhaustiveAttributes() | ||
|
||
// When | ||
testedInternalLogger.log( | ||
fakeLevel, | ||
InternalLogger.Target.MAINTAINER, | ||
fakeMessage, | ||
fakeThrowable, | ||
fakeAttributes | ||
) | ||
|
||
// Then | ||
verify(logger.mockSdkLogHandler) | ||
.handleLog( | ||
fakeLevel.toLogLevel(), | ||
fakeMessage, | ||
fakeThrowable, | ||
fakeAttributes | ||
) | ||
} | ||
|
||
@Test | ||
fun `𝕄 send telemetry log 𝕎 log { TELEMETRY target, no throwable + info or debug }`( | ||
@StringForgery fakeMessage: String, | ||
forge: Forge | ||
) { | ||
// Given | ||
val fakeLevel = forge.anElementFrom(InternalLogger.Level.INFO, InternalLogger.Level.DEBUG) | ||
val fakeAttributes = forge.exhaustiveAttributes() | ||
|
||
// When | ||
testedInternalLogger.log( | ||
fakeLevel, | ||
InternalLogger.Target.TELEMETRY, | ||
fakeMessage, | ||
null, | ||
fakeAttributes | ||
) | ||
|
||
// Then | ||
verify(rumMonitor.mockInstance) | ||
.sendDebugTelemetryEvent(fakeMessage) | ||
} | ||
|
||
@Test | ||
fun `𝕄 send telemetry log 𝕎 log { TELEMETRY target, no throwable + warn or error }`( | ||
@StringForgery fakeMessage: String, | ||
forge: Forge | ||
) { | ||
// Given | ||
val fakeLevel = forge.anElementFrom(InternalLogger.Level.WARN, InternalLogger.Level.ERROR) | ||
val fakeAttributes = forge.exhaustiveAttributes() | ||
|
||
// When | ||
testedInternalLogger.log( | ||
fakeLevel, | ||
InternalLogger.Target.TELEMETRY, | ||
fakeMessage, | ||
null, | ||
fakeAttributes | ||
) | ||
|
||
// Then | ||
verify(rumMonitor.mockInstance) | ||
.sendErrorTelemetryEvent(fakeMessage, null) | ||
} | ||
|
||
@Test | ||
fun `𝕄 send telemetry log 𝕎 log { TELEMETRY target, with throwable}`( | ||
@StringForgery fakeMessage: String, | ||
forge: Forge | ||
) { | ||
// Given | ||
val fakeLevel = forge.aValueFrom(InternalLogger.Level::class.java) | ||
val fakeThrowable = forge.aThrowable() | ||
val fakeAttributes = forge.exhaustiveAttributes() | ||
|
||
// When | ||
testedInternalLogger.log( | ||
fakeLevel, | ||
InternalLogger.Target.TELEMETRY, | ||
fakeMessage, | ||
fakeThrowable, | ||
fakeAttributes | ||
) | ||
|
||
// Then | ||
verify(rumMonitor.mockInstance) | ||
.sendErrorTelemetryEvent(fakeMessage, fakeThrowable) | ||
} | ||
|
||
private fun InternalLogger.Level.toLogLevel(): Int { | ||
return when (this) { | ||
InternalLogger.Level.DEBUG -> Log.DEBUG | ||
InternalLogger.Level.INFO -> Log.INFO | ||
InternalLogger.Level.WARN -> Log.WARN | ||
InternalLogger.Level.ERROR -> Log.ERROR | ||
} | ||
} | ||
|
||
companion object { | ||
val logger = LoggerTestConfiguration() | ||
val rumMonitor = GlobalRumMonitorTestConfiguration() | ||
|
||
@TestConfigurationsProvider | ||
@JvmStatic | ||
fun getTestConfigurations(): List<TestConfiguration> { | ||
return listOf(logger, rumMonitor) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point