diff --git a/Datadog/Example/ExampleAppDelegate.swift b/Datadog/Example/ExampleAppDelegate.swift index 1cc4d4c852..db54a0571b 100644 --- a/Datadog/Example/ExampleAppDelegate.swift +++ b/Datadog/Example/ExampleAppDelegate.swift @@ -33,7 +33,7 @@ class ExampleAppDelegate: UIResponder, UIApplicationDelegate { ) // Set user information - Datadog.setUserInfo(id: "abcd-1234", name: "foo", email: "foo@example.com") + Datadog.setUserInfo(id: "abcd-1234", name: "foo", email: "foo@example.com", extraInfo: ["key-extraUserInfo": "value-extraUserInfo"]) // Create Logger logger = Logger.builder diff --git a/Sources/Datadog/Core/Attributes/UserInfoProvider.swift b/Sources/Datadog/Core/Attributes/UserInfoProvider.swift index 02a84e0c57..93e2bfed47 100644 --- a/Sources/Datadog/Core/Attributes/UserInfoProvider.swift +++ b/Sources/Datadog/Core/Attributes/UserInfoProvider.swift @@ -12,11 +12,26 @@ internal class UserInfoProvider { /// `UserInfo` can be mutated by any user thread with `Datadog.setUserInfo(id:name:email:)` - at the same /// time it might be accessed by different queues running in the SDK. private let queue = DispatchQueue(label: "com.datadoghq.user-info-provider", qos: .userInteractive) - private var current = UserInfo(id: nil, name: nil, email: nil) + private var _value = UserInfo(id: nil, name: nil, email: nil) + private var _extraInfo = [AttributeKey: AttributeValue]() var value: UserInfo { - set { queue.async { self.current = newValue } } - get { queue.sync { self.current } } + set { queue.async { self._value = newValue } } + get { queue.sync { self._value } } + } + + var extraInfo: [AttributeKey: AttributeValue] { + set { + queue.async { + var processedInfo = newValue + newValue.keys.forEach { + let value = processedInfo.removeValue(forKey: $0) + processedInfo["usr.\($0)"] = value + } + self._extraInfo = processedInfo + } + } + get { queue.sync { self._extraInfo } } } } diff --git a/Sources/Datadog/Datadog.swift b/Sources/Datadog/Datadog.swift index 0bf15a1193..331de6e5de 100644 --- a/Sources/Datadog/Datadog.swift +++ b/Sources/Datadog/Datadog.swift @@ -78,9 +78,11 @@ public class Datadog { public static func setUserInfo( id: String? = nil, name: String? = nil, - email: String? = nil + email: String? = nil, + extraInfo: [AttributeKey: AttributeValue] = [:] ) { instance?.userInfoProvider.value = UserInfo(id: id, name: name, email: email) + instance?.userInfoProvider.extraInfo = extraInfo } // MARK: - Internal diff --git a/Sources/Datadog/Logging/Log/LogBuilder.swift b/Sources/Datadog/Logging/Log/LogBuilder.swift index 9b63c7e1be..ed53af42a7 100644 --- a/Sources/Datadog/Logging/Log/LogBuilder.swift +++ b/Sources/Datadog/Logging/Log/LogBuilder.swift @@ -24,6 +24,9 @@ internal struct LogBuilder { let carrierInfoProvider: CarrierInfoProviderType? func createLogWith(level: LogLevel, message: String, date: Date, attributes: LogAttributes, tags: Set) -> Log { + let extraUserInfo = userInfoProvider.extraInfo + var mergedAttributes = attributes + mergedAttributes.userAttributes.merge(extraUserInfo) { userAttr, _ in userAttr } return Log( date: date, status: logStatus(for: level), @@ -37,7 +40,7 @@ internal struct LogBuilder { userInfo: userInfoProvider.value, networkConnectionInfo: networkConnectionInfoProvider?.current, mobileCarrierInfo: carrierInfoProvider?.current, - attributes: attributes, + attributes: mergedAttributes, tags: !tags.isEmpty ? Array(tags) : nil ) } diff --git a/Sources/Datadog/Logging/LogOutputs/LogOutput.swift b/Sources/Datadog/Logging/LogOutputs/LogOutput.swift index 107cbb20b5..897eb28e84 100644 --- a/Sources/Datadog/Logging/LogOutputs/LogOutput.swift +++ b/Sources/Datadog/Logging/LogOutputs/LogOutput.swift @@ -8,7 +8,7 @@ import Foundation internal struct LogAttributes { /// Log attributes received from the user. They are subject for sanitization. - let userAttributes: [String: Encodable] + var userAttributes: [String: Encodable] /// Log attributes added internally by the SDK. They are not a subject for sanitization. let internalAttributes: [String: Encodable]? } diff --git a/Sources/Datadog/RUM/RUMEvent/RUMEventBuilder.swift b/Sources/Datadog/RUM/RUMEvent/RUMEventBuilder.swift index e2ba7c2e6f..ebc4732652 100644 --- a/Sources/Datadog/RUM/RUMEvent/RUMEventBuilder.swift +++ b/Sources/Datadog/RUM/RUMEvent/RUMEventBuilder.swift @@ -6,8 +6,16 @@ import Foundation -internal struct RUMEventBuilder { +internal class RUMEventBuilder { + let userInfoProvider: UserInfoProvider + + init(userInfoProvider: UserInfoProvider) { + self.userInfoProvider = userInfoProvider + } + func createRUMEvent(with model: DM, attributes: [String: Encodable]) -> RUMEvent { - return RUMEvent(model: model, attributes: attributes) + var mergedAttributes = attributes + mergedAttributes.merge(userInfoProvider.extraInfo) { userAttr, _ in userAttr } + return RUMEvent(model: model, attributes: mergedAttributes) } } diff --git a/Sources/Datadog/RUMMonitor.swift b/Sources/Datadog/RUMMonitor.swift index be2a150930..629105ad4d 100644 --- a/Sources/Datadog/RUMMonitor.swift +++ b/Sources/Datadog/RUMMonitor.swift @@ -182,7 +182,7 @@ public class RUMMonitor: DDRUMMonitor, RUMCommandSubscriber { networkConnectionInfoProvider: rumFeature.networkConnectionInfoProvider, carrierInfoProvider: rumFeature.carrierInfoProvider ), - eventBuilder: RUMEventBuilder(), + eventBuilder: RUMEventBuilder(userInfoProvider: rumFeature.userInfoProvider), eventOutput: RUMEventFileOutput( fileWriter: rumFeature.storage.writer ), diff --git a/Sources/Datadog/Tracing/Span/SpanBuilder.swift b/Sources/Datadog/Tracing/Span/SpanBuilder.swift index 36d4f9a1c0..e9b41ccd0a 100644 --- a/Sources/Datadog/Tracing/Span/SpanBuilder.swift +++ b/Sources/Datadog/Tracing/Span/SpanBuilder.swift @@ -27,7 +27,10 @@ internal struct SpanBuilder { func createSpan(from ddspan: DDSpan, finishTime: Date) -> Span { let tagsReducer = SpanTagsReducer(spanTags: ddspan.tags, logFields: ddspan.logFields) - var jsonStringEncodedTags: [String: JSONStringEncodableValue] = [:] + var jsonStringEncodedTags: [String: JSONStringEncodableValue] + jsonStringEncodedTags = userInfoProvider.extraInfo.compactMapValues { + JSONStringEncodableValue($0, encodedUsing: tagsJSONEncoder) + } // First, add baggage items as tags... for (itemKey, itemValue) in ddspan.ddContext.baggageItems.all { diff --git a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift index 50c3bd7587..19decf79fe 100644 --- a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift @@ -80,7 +80,7 @@ struct RUMDataModelMock: RUMDataModel, Equatable { extension RUMEventBuilder { static func mockAny() -> RUMEventBuilder { - return RUMEventBuilder() + return RUMEventBuilder(userInfoProvider: UserInfoProvider.mockAny()) } } @@ -323,7 +323,7 @@ extension RUMScopeDependencies { networkConnectionInfoProvider: NetworkConnectionInfoProviderMock(networkConnectionInfo: nil), carrierInfoProvider: CarrierInfoProviderMock(carrierInfo: nil) ), - eventBuilder: RUMEventBuilder = RUMEventBuilder(), + eventBuilder: RUMEventBuilder = RUMEventBuilder(userInfoProvider: UserInfoProvider.mockAny()), eventOutput: RUMEventOutput = RUMEventOutputMock(), rumUUIDGenerator: RUMUUIDGenerator = DefaultRUMUUIDGenerator() ) -> RUMScopeDependencies { diff --git a/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMEventBuilderTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMEventBuilderTests.swift index 2de99c5443..37fb6d3883 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMEventBuilderTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMEvent/RUMEventBuilderTests.swift @@ -9,7 +9,7 @@ import XCTest class RUMEventBuilderTests: XCTestCase { func testItBuildsRUMEvent() { - let builder = RUMEventBuilder() + let builder = RUMEventBuilder(userInfoProvider: UserInfoProvider.mockAny()) let event = builder.createRUMEvent( with: RUMDataModelMock(attribute: "foo"), attributes: ["foo": "bar", "fizz": "buzz"] diff --git a/Tests/DatadogTests/Datadog/RUM/RUMEventOutputs/RUMEventFileOutputTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMEventOutputs/RUMEventFileOutputTests.swift index 91c506a0b7..dce443e5e7 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMEventOutputs/RUMEventFileOutputTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMEventOutputs/RUMEventFileOutputTests.swift @@ -21,7 +21,7 @@ class RUMEventFileOutputTests: XCTestCase { func testItWritesRUMEventToFileAsJSON() throws { let fileCreationDateProvider = RelativeDateProvider(startingFrom: .mockDecember15th2019At10AMUTC()) let queue = DispatchQueue(label: "com.datadohq.testItWritesRUMEventToFileAsJSON") - let builder = RUMEventBuilder() + let builder = RUMEventBuilder(userInfoProvider: UserInfoProvider.mockAny()) let output = RUMEventFileOutput( fileWriter: FileWriter( dataFormat: RUMFeature.dataFormat,