Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,37 @@ import com.facebook.react.bridge.ReadableMap
* The entry point to use Datadog's Logs feature.
*/
class DdLogsImplementation(
logger: Logger? = null,
private val datadog: DatadogWrapper = DatadogSDKWrapper()
) {
private val reactNativeLogger: Logger by lazy {
val bundleLogsWithRum = datadog.bundleLogsWithRum
val bundleLogsWithTraces = datadog.bundleLogsWithTraces

logger ?: Logger.Builder(Datadog.getInstance())
private val datadog: DatadogWrapper = DatadogSDKWrapper(),
private val logger: () -> Logger = {
Logger.Builder(Datadog.getInstance())
.setLogcatLogsEnabled(true)
.setBundleWithRumEnabled(bundleLogsWithRum)
.setBundleWithTraceEnabled(bundleLogsWithTraces)
.setBundleWithRumEnabled(datadog.bundleLogsWithRum)
.setBundleWithTraceEnabled(datadog.bundleLogsWithTraces)
.setName("DdLogs")
.build()
}
) {
private var loggerInstance: Logger? = null
private val reactNativeLogger: Logger
get() {
if (loggerInstance == null) {
loggerInstance = logger()
}
return loggerInstance!!
}

init {
DatadogSDKWrapperStorage.addOnInitializedListener {
loggerInstance = null
}
}

/**
* Send a log with Debug level.
* @param message The message to send.
* @param context The additional context to send.
*/
fun debug(message: String, context: ReadableMap, promise: Promise) {
if (!datadog.isInitialized()) {
promise.reject(IllegalStateException(SDK_NOT_INITIALIZED_MESSAGE))
return
}
reactNativeLogger.d(
message = message,
attributes = context.toHashMap() + GlobalState.globalAttributes
Expand All @@ -54,10 +60,6 @@ class DdLogsImplementation(
* @param context The additional context to send.
*/
fun info(message: String, context: ReadableMap, promise: Promise) {
if (!datadog.isInitialized()) {
promise.reject(IllegalStateException(SDK_NOT_INITIALIZED_MESSAGE))
return
}
reactNativeLogger.i(
message = message,
attributes = context.toHashMap() + GlobalState.globalAttributes
Expand All @@ -71,10 +73,6 @@ class DdLogsImplementation(
* @param context The additional context to send.
*/
fun warn(message: String, context: ReadableMap, promise: Promise) {
if (!datadog.isInitialized()) {
promise.reject(IllegalStateException(SDK_NOT_INITIALIZED_MESSAGE))
return
}
reactNativeLogger.w(
message = message,
attributes = context.toHashMap() + GlobalState.globalAttributes
Expand All @@ -88,10 +86,6 @@ class DdLogsImplementation(
* @param context The additional context to send.
*/
fun error(message: String, context: ReadableMap, promise: Promise) {
if (!datadog.isInitialized()) {
promise.reject(IllegalStateException(SDK_NOT_INITIALIZED_MESSAGE))
return
}
reactNativeLogger.e(
message = message,
attributes = context.toHashMap() + GlobalState.globalAttributes
Expand All @@ -116,10 +110,6 @@ class DdLogsImplementation(
context: ReadableMap,
promise: Promise
) {
if (!datadog.isInitialized()) {
promise.reject(IllegalStateException(SDK_NOT_INITIALIZED_MESSAGE))
return
}
reactNativeLogger.log(
priority = AndroidLog.DEBUG,
message = message,
Expand Down Expand Up @@ -148,10 +138,6 @@ class DdLogsImplementation(
context: ReadableMap,
promise: Promise
) {
if (!datadog.isInitialized()) {
promise.reject(IllegalStateException(SDK_NOT_INITIALIZED_MESSAGE))
return
}
reactNativeLogger.log(
priority = AndroidLog.INFO,
message = message,
Expand Down Expand Up @@ -180,10 +166,6 @@ class DdLogsImplementation(
context: ReadableMap,
promise: Promise
) {
if (!datadog.isInitialized()) {
promise.reject(IllegalStateException(SDK_NOT_INITIALIZED_MESSAGE))
return
}
reactNativeLogger.log(
priority = AndroidLog.WARN,
message = message,
Expand Down Expand Up @@ -212,10 +194,6 @@ class DdLogsImplementation(
context: ReadableMap,
promise: Promise
) {
if (!datadog.isInitialized()) {
promise.reject(IllegalStateException(SDK_NOT_INITIALIZED_MESSAGE))
return
}
reactNativeLogger.log(
priority = AndroidLog.ERROR,
message = message,
Expand All @@ -228,7 +206,6 @@ class DdLogsImplementation(
}

internal companion object {
private const val SDK_NOT_INITIALIZED_MESSAGE = "DD_INTERNAL_LOG_SENT_BEFORE_SDK_INIT"
internal const val NAME = "DdLogs"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package com.datadog.reactnative

import android.util.Log
import com.datadog.android.log.Logger
import com.datadog.tools.unit.GenericAssert.Companion.assertThat
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReadableMap
import fr.xgouchet.elmyr.Forge
Expand All @@ -25,11 +24,9 @@ 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.argumentCaptor
import org.mockito.kotlin.doReturn
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
import org.mockito.quality.Strictness

Expand Down Expand Up @@ -71,8 +68,7 @@ internal class DdLogsTest {

@BeforeEach
fun `set up`(forge: Forge) {
whenever(mockDatadog.isInitialized()) doReturn true
testedLogs = DdLogsImplementation(mockLogger, mockDatadog)
testedLogs = DdLogsImplementation(datadog = mockDatadog, logger = { mockLogger })
fakeErrorKind = forge.aNullable { forge.aString() }
fakeErrorMessage = forge.aNullable { forge.aString() }
fakeStacktrace = forge.aNullable { forge.aString() }
Expand Down Expand Up @@ -272,129 +268,26 @@ internal class DdLogsTest {
}

@Test
fun `M not forward logs W SDK is not initialized`() {
// When
whenever(mockDatadog.isInitialized()) doReturn false
var newTestedLogs = DdLogsImplementation(mockLogger, mockDatadog)
newTestedLogs.debug(fakeMessage, mockContext, mockPromise)
newTestedLogs.info(fakeMessage, mockContext, mockPromise)
newTestedLogs.warn(fakeMessage, mockContext, mockPromise)
newTestedLogs.error(fakeMessage, mockContext, mockPromise)
testedLogs.debugWithError(
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
mockContext,
mockPromise
)
testedLogs.infoWithError(
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
mockContext,
mockPromise
)
testedLogs.warnWithError(
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
mockContext,
mockPromise
)
testedLogs.errorWithError(
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
mockContext,
mockPromise
fun `M recreate logger W SDK is initialized`() {
// Given
val mockLoggerFactory = mock<() -> Logger>()
whenever(mockLoggerFactory()).thenReturn(mockLogger)
val testedLogs = DdLogsImplementation(
datadog = mockDatadog,
logger = mockLoggerFactory
)

// When
testedLogs.debug(fakeMessage, mockContext, mockPromise)

// Then
verifyNoInteractions(mockLogger)
val exceptionCaptor = argumentCaptor<IllegalStateException>()
verify(mockPromise, times(8)).reject(exceptionCaptor.capture())
assertThat(exceptionCaptor.firstValue.message)
.isEqualTo("DD_INTERNAL_LOG_SENT_BEFORE_SDK_INIT")

// When SDK is finally initialized
whenever(mockDatadog.isInitialized()) doReturn true
newTestedLogs.debug(fakeMessage, mockContext, mockPromise)
newTestedLogs.info(fakeMessage, mockContext, mockPromise)
newTestedLogs.warn(fakeMessage, mockContext, mockPromise)
newTestedLogs.error(fakeMessage, mockContext, mockPromise)
testedLogs.debugWithError(
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
mockContext,
mockPromise
)
testedLogs.infoWithError(
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
mockContext,
mockPromise
)
testedLogs.warnWithError(
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
mockContext,
mockPromise
)
testedLogs.errorWithError(
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
mockContext,
mockPromise
)
verify(mockLoggerFactory, times(1)).invoke()

// When
DatadogSDKWrapperStorage.notifyOnInitializedListeners(mock())

// Then
verify(mockLogger).i(fakeMessage, attributes = mockContext.toHashMap())
verify(mockLogger).d(fakeMessage, attributes = mockContext.toHashMap())
verify(mockLogger).w(fakeMessage, attributes = mockContext.toHashMap())
verify(mockLogger).e(fakeMessage, attributes = mockContext.toHashMap())
verify(mockLogger).log(
Log.DEBUG,
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
attributes = mockContext.toHashMap()
)
verify(mockLogger).log(
Log.INFO,
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
attributes = mockContext.toHashMap()
)
verify(mockLogger).log(
Log.WARN,
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
attributes = mockContext.toHashMap()
)
verify(mockLogger).log(
Log.ERROR,
fakeMessage,
fakeErrorKind,
fakeErrorMessage,
fakeStacktrace,
attributes = mockContext.toHashMap()
)
testedLogs.debug(fakeMessage, mockContext, mockPromise)
verify(mockLoggerFactory, times(2)).invoke()
}
}
16 changes: 13 additions & 3 deletions packages/core/ios/Sources/DdLogsImplementation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ import DatadogCore

@objc
public class DdLogsImplementation: NSObject {
private lazy var logger: LoggerProtocol = loggerProvider()
private var loggerInstance: LoggerProtocol?
private var logger: LoggerProtocol {
if loggerInstance == nil {
loggerInstance = loggerProvider()
}
return loggerInstance!
}
private let loggerProvider: () -> LoggerProtocol

internal init(_ loggerProvider: @escaping () -> LoggerProtocol) {
self.loggerProvider = loggerProvider
super.init()
DatadogSDKWrapper.shared.addOnSdkInitializedListener { [weak self] _ in
self?.loggerInstance = nil
}
}

@objc
Expand Down Expand Up @@ -94,4 +104,4 @@ internal extension DatadogLogs.Logger.Configuration {
consoleLogFormat: .short
)
}
}
}
Loading
Loading