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
7 changes: 0 additions & 7 deletions packages/core/ios/Sources/Attributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,3 @@ internal struct InternalConfigurationAttributes {
/// Expects `Bool` value.
static let dropAction = "_dd.action.drop_action"
}

/// Error messages that can be thrown to the JS SDK
internal struct Errors {
/// Error thrown when a log was sent before the SDK was initialized.
/// Not sending the log prevent the logger to be set to a Noop logger.
static let logSentBeforeSDKInit = "DD_INTERNAL_LOG_SENT_BEFORE_SDK_INIT"
}
39 changes: 2 additions & 37 deletions packages/core/ios/Sources/DdLogsImplementation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,104 +13,69 @@ import DatadogCore
public class DdLogsImplementation: NSObject {
private lazy var logger: LoggerProtocol = loggerProvider()
private let loggerProvider: () -> LoggerProtocol
private let isSDKInitialized: () -> Bool

internal init(_ loggerProvider: @escaping () -> LoggerProtocol, _ isSDKInitialized: @escaping () -> Bool) {
internal init(_ loggerProvider: @escaping () -> LoggerProtocol) {
self.loggerProvider = loggerProvider
self.isSDKInitialized = isSDKInitialized
}

@objc
public override convenience init() {
self.init(
{ DatadogLogs.Logger.create(with: DatadogSDKWrapper.shared.loggerConfiguration) },
{ Datadog.isInitialized() }
{ DatadogLogs.Logger.create(with: DatadogSDKWrapper.shared.loggerConfiguration) }
)
}

@objc
public func debug(message: String, context: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
if (!self.isSDKInitialized()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed these for two reasons:

  • It's a bit weird that the logs module is checking for this when the native SDK does it too.
  • When running the app with the internal testing tools module, this check will always be false, since the way in which the core SDK checks if the core is initialized is by checking the core type and comparing it with DatadogCore. Since the internal testing tools wrap it into a DatadogCoreProxy to allow for intercepting events this check always fails, even if the SDK is running fine.

And for those curious, this worked fine on v2 because the DatadogSdkWrapper kept a local reference to the core sdk instance, and the internal testing tools were wrapping that one instead, so calls to Datadog.isInitialized would still work fine as they would not deal with the wrapped core but with the internal SDK one.

reject(nil, Errors.logSentBeforeSDKInit, nil)
return
}
let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes()
logger.debug(message, error: nil, attributes: attributes)
resolve(nil)
}

@objc
public func info(message: String, context: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
if (!self.isSDKInitialized()) {
reject(nil, Errors.logSentBeforeSDKInit, nil)
return
}
let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes()
logger.info(message, error: nil, attributes: attributes)
resolve(nil)
}

@objc
public func warn(message: String, context: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
if (!self.isSDKInitialized()) {
reject(nil, Errors.logSentBeforeSDKInit, nil)
return
}
let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes()
logger.warn(message, error: nil, attributes: attributes)
resolve(nil)
}

@objc
public func error(message: String, context: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
if (!self.isSDKInitialized()) {
reject(nil, Errors.logSentBeforeSDKInit, nil)
return
}
let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes()
logger.error(message, error: nil, attributes: attributes)
resolve(nil)
}

@objc
public func debugWithError(message: String, errorKind: String?, errorMessage: String?, stacktrace: String?, context: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
if (!self.isSDKInitialized()) {
reject(nil, Errors.logSentBeforeSDKInit, nil)
return
}
let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes()
logger._internal.log(level: .debug, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes)
resolve(nil)
}

@objc
public func infoWithError(message: String, errorKind: String?, errorMessage: String?, stacktrace: String?, context: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
if (!self.isSDKInitialized()) {
reject(nil, Errors.logSentBeforeSDKInit, nil)
return
}
let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes()
logger._internal.log(level: .info, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes)
resolve(nil)
}

@objc
public func warnWithError(message: String, errorKind: String?, errorMessage: String?, stacktrace: String?, context: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
if (!self.isSDKInitialized()) {
reject(nil, Errors.logSentBeforeSDKInit, nil)
return
}
let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes()
logger._internal.log(level: .warn, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes)
resolve(nil)
}

@objc
public func errorWithError(message: String, errorKind: String?, errorMessage: String?, stacktrace: String?, context: NSDictionary, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
if (!self.isSDKInitialized()) {
reject(nil, Errors.logSentBeforeSDKInit, nil)
return
}
let attributes = castAttributesToSwift(context).mergeWithGlobalAttributes()
logger._internal.log(level: .error, message: message, errorKind: errorKind, errorMessage: errorMessage, stackTrace: stacktrace, attributes: attributes)
resolve(nil)
Expand Down
33 changes: 2 additions & 31 deletions packages/core/ios/Tests/DdLogsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func mockReject(args: String?, arg: String?, err: Error?) {}

internal class DdLogsTests: XCTestCase {
private let mockNativeLogger = MockNativeLogger()
private lazy var logger = DdLogsImplementation({ self.mockNativeLogger }, { true })
private lazy var logger = DdLogsImplementation({ self.mockNativeLogger })

private let testMessage_swift: String = "message"
private let testMessage_objc: NSString = "message"
Expand Down Expand Up @@ -80,7 +80,7 @@ internal class DdLogsTests: XCTestCase {
let logger = DdLogsImplementation({ [unowned self] in
expectation.fulfill()
return self.mockNativeLogger
}, { true })
})

// When
(0..<10).forEach { _ in logger.debug(message: "foo", context: [:], resolve: mockResolve, reject: mockReject)}
Expand Down Expand Up @@ -372,35 +372,6 @@ internal class DdLogsTests: XCTestCase {
GlobalState.globalAttributes.keys
)
}

func testDoesNotInitializeLoggerBeforeSdkIsInitialized() throws {
var isInitialized = false
let newLogger = DdLogsImplementation({ self.mockNativeLogger }, { isInitialized })

newLogger.debug(message: testMessage_objc as String, context: validTestAttributes_objc, resolve: mockResolve, reject: mockReject)
newLogger.info(message: testMessage_objc as String, context: validTestAttributes_objc, resolve: mockResolve, reject: mockReject)
newLogger.warn(message: testMessage_objc as String, context: validTestAttributes_objc, resolve: mockResolve, reject: mockReject)
newLogger.error(message: testMessage_objc as String, context: validTestAttributes_objc, resolve: mockResolve, reject: mockReject)
newLogger.debugWithError(message: testMessage_objc as String, errorKind: testErrorKind_objc as String, errorMessage: testErrorMessage_objc as String, stacktrace: testErrorStacktrace_objc as String, context: invalidTestAttributes, resolve: mockResolve, reject: mockReject)
newLogger.infoWithError(message: testMessage_objc as String, errorKind: testErrorKind_objc as String, errorMessage: testErrorMessage_objc as String, stacktrace: testErrorStacktrace_objc as String, context: invalidTestAttributes, resolve: mockResolve, reject: mockReject)
newLogger.warnWithError(message: testMessage_objc as String, errorKind: testErrorKind_objc as String, errorMessage: testErrorMessage_objc as String, stacktrace: testErrorStacktrace_objc as String, context: invalidTestAttributes, resolve: mockResolve, reject: mockReject)
newLogger.errorWithError(message: testMessage_objc as String, errorKind: testErrorKind_objc as String, errorMessage: testErrorMessage_objc as String, stacktrace: testErrorStacktrace_objc as String, context: invalidTestAttributes, resolve: mockResolve, reject: mockReject)

XCTAssertEqual(mockNativeLogger.receivedMethodCalls.count, 0)

isInitialized = true

newLogger.debug(message: testMessage_objc as String, context: validTestAttributes_objc, resolve: mockResolve, reject: mockReject)
newLogger.info(message: testMessage_objc as String, context: validTestAttributes_objc, resolve: mockResolve, reject: mockReject)
newLogger.warn(message: testMessage_objc as String, context: validTestAttributes_objc, resolve: mockResolve, reject: mockReject)
newLogger.error(message: testMessage_objc as String, context: validTestAttributes_objc, resolve: mockResolve, reject: mockReject)
newLogger.debugWithError(message: testMessage_objc as String, errorKind: testErrorKind_objc as String, errorMessage: testErrorMessage_objc as String, stacktrace: testErrorStacktrace_objc as String, context: invalidTestAttributes, resolve: mockResolve, reject: mockReject)
newLogger.infoWithError(message: testMessage_objc as String, errorKind: testErrorKind_objc as String, errorMessage: testErrorMessage_objc as String, stacktrace: testErrorStacktrace_objc as String, context: invalidTestAttributes, resolve: mockResolve, reject: mockReject)
newLogger.warnWithError(message: testMessage_objc as String, errorKind: testErrorKind_objc as String, errorMessage: testErrorMessage_objc as String, stacktrace: testErrorStacktrace_objc as String, context: invalidTestAttributes, resolve: mockResolve, reject: mockReject)
newLogger.errorWithError(message: testMessage_objc as String, errorKind: testErrorKind_objc as String, errorMessage: testErrorMessage_objc as String, stacktrace: testErrorStacktrace_objc as String, context: invalidTestAttributes, resolve: mockResolve, reject: mockReject)

XCTAssertEqual(mockNativeLogger.receivedMethodCalls.count, 8)
}
}

private class MockNativeLogger: LoggerProtocol {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private final class FeatureScopeInterceptor: @unchecked Sendable {
let actualWriter: Writer
unowned var interception: FeatureScopeInterceptor?

func write<T: Encodable, M: Encodable>(value: T, metadata: M) {
func write<T, M>(value: T, metadata: M?, completion: @escaping DatadogInternal.CompletionHandler) where T : Encodable, M : Encodable {
group.enter()
defer { group.leave() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import DatadogInternal
public class DdInternalTestingImplementation: NSObject {
@objc
public func clearData(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
let coreProxy = (DatadogSDKWrapper.shared.getCoreInstance() as! DatadogCoreProxy)
let coreProxy = CoreRegistry.default as! DatadogCoreProxy
coreProxy.waitAndDeleteEvents(ofFeature: "rum")
coreProxy.waitAndDeleteEvents(ofFeature: "logging")
coreProxy.waitAndDeleteEvents(ofFeature: "tracing")
Expand All @@ -26,7 +26,7 @@ public class DdInternalTestingImplementation: NSObject {
@objc
public func getAllEvents(feature: String, resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
do {
let coreProxy = (DatadogSDKWrapper.shared.getCoreInstance() as! DatadogCoreProxy)
let coreProxy = CoreRegistry.default as! DatadogCoreProxy
let events = coreProxy.waitAndReturnEventsData(ofFeature: feature)
let data = try JSONSerialization.data(withJSONObject: events, options: .prettyPrinted)
resolve(String(data: data, encoding: String.Encoding.utf8) ?? "")
Expand All @@ -39,9 +39,10 @@ public class DdInternalTestingImplementation: NSObject {

@objc
public func enable(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void {
DatadogSDKWrapper.shared.addOnCoreInitializedListener(listener: {core in
DatadogSDKWrapper.shared.addOnSdkInitializedListener(listener: {core in
let proxiedCore = DatadogCoreProxy(core: core)
DatadogSDKWrapper.shared.setCoreInstance(core: proxiedCore)
CoreRegistry.unregisterDefault()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling register directly with the same name does not overwrite its value, so we need to call unregsiterDefault first to be able to set the proxied core as the default core.

CoreRegistry.register(default: proxiedCore)
})
resolve(nil)
}
Expand All @@ -51,9 +52,10 @@ public class DdInternalTestingImplementation: NSObject {
public class DdInternalTestingNativeInitialization: NSObject {
@objc
public func enableFromNative() -> Void {
DatadogSDKWrapper.shared.addOnCoreInitializedListener(listener: {core in
DatadogSDKWrapper.shared.addOnSdkInitializedListener(listener: {core in
let proxiedCore = DatadogCoreProxy(core: core)
DatadogSDKWrapper.shared.setCoreInstance(core: proxiedCore)
CoreRegistry.unregisterDefault()
CoreRegistry.register(default: proxiedCore)
})
}
}