From e72a3aece7aa82ae6d585e5e78ca4509400cf165 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Fri, 23 Jun 2023 16:20:40 +0200 Subject: [PATCH 01/87] RUMM-3151 feat: reduce number of view updates by filtering events from payload ### What and why? There are several view updates happens which are not needed. These view updates are reduced by the backend anyway, but we could reduce the number of view updates by filtering them out from the payload. ### How? While saving RUMViewEvent to disk, we save the metadata along with it. This allows us to access key information without decoding the whole event. While preparing the request body, we filter out the events which are duplicate and will be sent in the same batch. --- Datadog/Datadog.xcodeproj/project.pbxproj | 32 +++++ .../RequestBuilder/RequestBuilder.swift | 4 +- .../DatadogCore/Storage/DataBlock.swift | 4 + .../Storage/Reading/FileReader.swift | 20 +-- .../DatadogCore/Storage/Reading/Reader.swift | 11 +- .../Storage/Writing/FileWriter.swift | 27 +++- .../DatadogCore/Storage/Writing/Writer.swift | 16 ++- .../DatadogCore/Upload/DataUploader.swift | 4 +- .../DatadogInternal/Upload/Event.swift | 93 +++++++++++++ .../Upload/FeatureRequestBuilder.swift | 2 +- .../Logging/LoggingV2Configuration.swift | 4 +- .../RUM/RUMMonitor/Scopes/RUMViewScope.swift | 2 +- Sources/Datadog/RUM/RUMV2Configuration.swift | 51 +++++++- .../Tracing/TracingV2Configuration.swift | 4 +- TestUtilities/Mocks/FileWriterMock.swift | 2 +- .../BenchmarkMocks.swift | 2 +- .../Datadog/Core/FeatureTests.swift | 8 +- .../Core/Persistence/DataBlockTests.swift | 30 +++++ .../Persistence/EventGeneratorTests.swift | 71 ++++++++++ .../Persistence/Reading/FileReaderTests.swift | 47 +++++-- .../Persistence/Writing/FileWriterTests.swift | 53 +++++++- .../DatadogCore/DatadogCoreTests.swift | 6 +- .../Upload/DataFormatTests.swift | 28 ++++ .../Datadog/Mocks/CoreMocks.swift | 2 +- .../DatadogInternal/DatadogCoreProxy.swift | 4 +- .../Mocks/DatadogInternal/UploadMock.swift | 10 +- .../Datadog/RUM/RUMFeatureTests.swift | 13 +- .../RUM/RUMViewEventsFilterTests.swift | 123 ++++++++++++++++++ 28 files changed, 605 insertions(+), 68 deletions(-) create mode 100644 Sources/Datadog/DatadogInternal/Upload/Event.swift create mode 100644 Tests/DatadogTests/Datadog/Core/Persistence/EventGeneratorTests.swift create mode 100644 Tests/DatadogTests/Datadog/DatadogInternal/Upload/DataFormatTests.swift create mode 100644 Tests/DatadogTests/Datadog/RUM/RUMViewEventsFilterTests.swift diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index 846268f29f..c5f70d2cdd 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -7,6 +7,14 @@ objects = { /* Begin PBXBuildFile section */ + 3C0839F12A431E930040A213 /* DataFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0839F02A431E930040A213 /* DataFormatTests.swift */; }; + 3C0839F22A431E9E0040A213 /* DataFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0839F02A431E930040A213 /* DataFormatTests.swift */; }; + 3C6953532A45C02D00542049 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C6953522A45C02D00542049 /* Event.swift */; }; + 3C6953542A45C02D00542049 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C6953522A45C02D00542049 /* Event.swift */; }; + 3C9A376A2A4595EF00414CD6 /* EventGeneratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9A37692A4595EF00414CD6 /* EventGeneratorTests.swift */; }; + 3C9A376B2A4595EF00414CD6 /* EventGeneratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9A37692A4595EF00414CD6 /* EventGeneratorTests.swift */; }; + 3CB992952A434EE100B6C6CF /* RUMViewEventsFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CB992942A434EE100B6C6CF /* RUMViewEventsFilterTests.swift */; }; + 3CB992962A434EE100B6C6CF /* RUMViewEventsFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CB992942A434EE100B6C6CF /* RUMViewEventsFilterTests.swift */; }; 490D5EC929C9E17E004F969C /* RUMStopSessionScenarioTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490D5EC829C9E17E004F969C /* RUMStopSessionScenarioTests.swift */; }; 490D5ECF29CA0745004F969C /* RUMStopSessionScenario.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 490D5ECB29C9E2D0004F969C /* RUMStopSessionScenario.storyboard */; }; 490D5ED029CA074A004F969C /* KioskViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490D5ECD29CA0738004F969C /* KioskViewController.swift */; }; @@ -1367,6 +1375,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 3C0839F02A431E930040A213 /* DataFormatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataFormatTests.swift; sourceTree = ""; }; + 3C6953522A45C02D00542049 /* Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = ""; }; + 3C9A37692A4595EF00414CD6 /* EventGeneratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventGeneratorTests.swift; sourceTree = ""; }; + 3CB992942A434EE100B6C6CF /* RUMViewEventsFilterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewEventsFilterTests.swift; sourceTree = ""; }; 490D5EC829C9E17E004F969C /* RUMStopSessionScenarioTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMStopSessionScenarioTests.swift; sourceTree = ""; }; 490D5ECB29C9E2D0004F969C /* RUMStopSessionScenario.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = RUMStopSessionScenario.storyboard; sourceTree = ""; }; 490D5ECD29CA0738004F969C /* KioskViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KioskViewController.swift; sourceTree = ""; }; @@ -2216,6 +2228,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 3C0839EF2A431E7D0040A213 /* Upload */ = { + isa = PBXGroup; + children = ( + 3C0839F02A431E930040A213 /* DataFormatTests.swift */, + ); + path = Upload; + sourceTree = ""; + }; 490D5ECA29C9E28F004F969C /* StopSessionScenario */ = { isa = PBXGroup; children = ( @@ -2643,6 +2663,7 @@ 619E16D42577C11B00B2516B /* Writing */, 619E16D52577C12100B2516B /* Reading */, 61133C2B2423990D00786299 /* Files */, + 3C9A37692A4595EF00414CD6 /* EventGeneratorTests.swift */, ); path = Persistence; sourceTree = ""; @@ -3853,6 +3874,7 @@ D236BE2A29521A7700676E67 /* Integrations */, 61786F7524FCDDE2009E6BAB /* Debugging */, 61411B0E24EC15940012EAB2 /* Utils */, + 3CB992942A434EE100B6C6CF /* RUMViewEventsFilterTests.swift */, ); path = RUM; sourceTree = ""; @@ -4419,6 +4441,7 @@ 61133BB42423979B00786299 /* URLRequestBuilder.swift */, 61AD4E3724531500006E34EA /* DataFormat.swift */, D24C27E9270C8BEE005DE596 /* DataCompression.swift */, + 3C6953522A45C02D00542049 /* Event.swift */, ); path = Upload; sourceTree = ""; @@ -4464,6 +4487,7 @@ D2956CAE2869D516007D5462 /* DatadogInternal */ = { isa = PBXGroup; children = ( + 3C0839EF2A431E7D0040A213 /* Upload */, A736BA3629D1B7AC00C00966 /* Extensions */, D2CBC25C294215BE00134409 /* Codable */, D2956CAF2869D520007D5462 /* Context */, @@ -5743,6 +5767,7 @@ 61D3E0D7277B23F1008BE766 /* KronosData+Bytes.swift in Sources */, 61E5332C24B75C51003D6C4E /* RUMFeature.swift in Sources */, 6156CB9D24E18600008CB2B2 /* TracingWithRUMIntegration.swift in Sources */, + 3C6953532A45C02D00542049 /* Event.swift in Sources */, 61C5A88624509A0C00DA608C /* TracingUUIDGenerator.swift in Sources */, 61133BD92423979B00786299 /* DataUploadDelay.swift in Sources */, 9EAF0CF8275A2FDC0044E8CA /* HostsSanitizer.swift in Sources */, @@ -5776,6 +5801,7 @@ D2A1EE3B287EECC000D28DFB /* CarrierInfoPublisherTests.swift in Sources */, 61410167251A661D00E3C2D9 /* UIApplicationSwizzlerTests.swift in Sources */, 61FF282824B8A31E000B3D9B /* RUMEventMatcher.swift in Sources */, + 3C9A376A2A4595EF00414CD6 /* EventGeneratorTests.swift in Sources */, D29294E3291D652C00F8EFF9 /* ApplicationVersionPublisherTests.swift in Sources */, 61C2C20924C0C75500C0321C /* RUMSessionScopeTests.swift in Sources */, 61E45ED12451A8730061DAC7 /* SpanMatcher.swift in Sources */, @@ -5845,6 +5871,7 @@ 61B03879252724AB00518F3C /* URLSessionInterceptorTests.swift in Sources */, 61C363802436164B00C4D4E6 /* ObjcExceptionHandlerTests.swift in Sources */, 6184751526EFCF1300C7C9C5 /* DatadogTestsObserver.swift in Sources */, + 3C0839F12A431E930040A213 /* DataFormatTests.swift in Sources */, 61133C602423990D00786299 /* RequestBuilderTests.swift in Sources */, 61133C572423990D00786299 /* FileReaderTests.swift in Sources */, D2A1EE38287EEB7400D28DFB /* NetworkConnectionInfoPublisherTests.swift in Sources */, @@ -5874,6 +5901,7 @@ D2956CB12869D54E007D5462 /* DeviceInfoTests.swift in Sources */, 61B558D42469CDD8001460D3 /* TracingUUIDGeneratorTests.swift in Sources */, 9E544A5124753DDE00E83072 /* MethodSwizzlerTests.swift in Sources */, + 3CB992952A434EE100B6C6CF /* RUMViewEventsFilterTests.swift in Sources */, 613F23E4252B062F006CD2D7 /* TaskInterceptionTests.swift in Sources */, 61FB2230244E1BE900902D19 /* LoggingFeatureTests.swift in Sources */, 61E5333124B75DFC003D6C4E /* RUMFeatureMocks.swift in Sources */, @@ -6460,6 +6488,7 @@ D2CB6EC027C50EAE00A62B57 /* RUMFeature.swift in Sources */, D2CB6EC127C50EAE00A62B57 /* TracingWithRUMIntegration.swift in Sources */, D2CB6EC327C50EAE00A62B57 /* TracingUUIDGenerator.swift in Sources */, + 3C6953542A45C02D00542049 /* Event.swift in Sources */, D2CB6EC427C50EAE00A62B57 /* DataUploadDelay.swift in Sources */, D2CB6EC527C50EAE00A62B57 /* HostsSanitizer.swift in Sources */, 61E945E42869BF3D00A946C4 /* CoreLogger.swift in Sources */, @@ -6519,6 +6548,7 @@ D2CB6EF527C520D400A62B57 /* TracerConfigurationTests.swift in Sources */, D2CB6EF627C520D400A62B57 /* DDSpanTests.swift in Sources */, D2CB6EF727C520D400A62B57 /* URLSessionAutoInstrumentationMocks.swift in Sources */, + 3CB992962A434EE100B6C6CF /* RUMViewEventsFilterTests.swift in Sources */, D2CB6EF927C520D400A62B57 /* WebViewEventReceiverTests.swift in Sources */, D2CB6EFA27C520D400A62B57 /* DirectoriesMock.swift in Sources */, D21C26EF28AFB65B005DD405 /* ErrorMessageReceiverTests.swift in Sources */, @@ -6554,6 +6584,7 @@ D2CB6F1427C520D400A62B57 /* UUID.swift in Sources */, D2CB6F1527C520D400A62B57 /* URLSessionRUMResourcesHandlerTests.swift in Sources */, A762BDE529351A250058D8E7 /* FirstPartyHostsTests.swift in Sources */, + 3C0839F22A431E9E0040A213 /* DataFormatTests.swift in Sources */, D2CB6F1627C520D400A62B57 /* URLSessionInterceptorTests.swift in Sources */, D2CB6F1727C520D400A62B57 /* ObjcExceptionHandlerTests.swift in Sources */, D2CB6F1827C520D400A62B57 /* DatadogTestsObserver.swift in Sources */, @@ -6652,6 +6683,7 @@ D2CB6F7127C520D400A62B57 /* URLSessionTracingHandlerTests.swift in Sources */, D2CB6F7227C520D400A62B57 /* ValuePublisherTests.swift in Sources */, D2CB6F7327C520D400A62B57 /* CoreTelephonyMocks.swift in Sources */, + 3C9A376B2A4595EF00414CD6 /* EventGeneratorTests.swift in Sources */, D20605B7287572640047275C /* DatadogContextProviderMock.swift in Sources */, D2CB6F7427C520D400A62B57 /* VitalCPUReaderTests.swift in Sources */, D2CB6F7527C520D400A62B57 /* UIKitExtensionsTests.swift in Sources */, diff --git a/DatadogSessionReplay/Sources/DatadogCoreIntegration/RequestBuilder/RequestBuilder.swift b/DatadogSessionReplay/Sources/DatadogCoreIntegration/RequestBuilder/RequestBuilder.swift index 90dab1f3e5..1469220808 100644 --- a/DatadogSessionReplay/Sources/DatadogCoreIntegration/RequestBuilder/RequestBuilder.swift +++ b/DatadogSessionReplay/Sources/DatadogCoreIntegration/RequestBuilder/RequestBuilder.swift @@ -13,13 +13,13 @@ internal struct RequestBuilder: FeatureRequestBuilder { /// Custom URL for uploading data to. let customUploadURL: URL? - func request(for events: [Data], with context: DatadogContext) throws -> URLRequest { + func request(for events: [Datadog.Event], with context: DatadogContext) throws -> URLRequest { let source = SRSegment.Source(rawValue: context.source) ?? .ios // TODO: RUMM-2410 Send telemetry on `?? .ios` let segmentBuilder = SegmentJSONBuilder(source: source) // If we can't decode `events: [Data]` there is no way to recover, so we throw an // error to let the core delete the batch: - let records = try events.map { try EnrichedRecordJSON(jsonObjectData: $0) } + let records = try events.map { try EnrichedRecordJSON(jsonObjectData: $0.data) } let segment = try segmentBuilder.createSegmentJSON(from: records) // If the SDK was configured with deprecated `set(*Endpoint:)` APIs we don't have `context.site`, so diff --git a/Sources/Datadog/DatadogCore/Storage/DataBlock.swift b/Sources/Datadog/DatadogCore/Storage/DataBlock.swift index b5fcccff95..edbf0fb1d1 100644 --- a/Sources/Datadog/DatadogCore/Storage/DataBlock.swift +++ b/Sources/Datadog/DatadogCore/Storage/DataBlock.swift @@ -14,7 +14,11 @@ private let MAX_DATA_LENGTH: UInt64 = 10 * 1_024 * 1_024 /// Block type supported in data stream internal enum BlockType: UInt16 { + /// Represents an event case event = 0x00 + /// Represents an event metadata associated with the previous event. + /// This block is optional and may be omitted. + case eventMetadata = 0x01 } /// Reported errors while manipulating data blocks. diff --git a/Sources/Datadog/DatadogCore/Storage/Reading/FileReader.swift b/Sources/Datadog/DatadogCore/Storage/Reading/FileReader.swift index a41e5b7876..b52262f181 100644 --- a/Sources/Datadog/DatadogCore/Storage/Reading/FileReader.swift +++ b/Sources/Datadog/DatadogCore/Storage/Reading/FileReader.swift @@ -31,8 +31,8 @@ internal final class FileReader: Reader { } do { - let events = try decode(stream: file.stream()) - return Batch(events: events, file: file) + let dataBlocks = try decode(stream: file.stream()) + return Batch(dataBlocks: dataBlocks, file: file) } catch { DD.telemetry.error("Failed to read data from file", error: error) return nil @@ -47,7 +47,7 @@ internal final class FileReader: Reader { /// /// - Parameter stream: The InputStream that provides data to decode. /// - Returns: The decoded and formatted data. - private func decode(stream: InputStream) throws -> [Data] { + private func decode(stream: InputStream) throws -> [DataBlock] { let reader = DataBlockReader( input: stream, maxBlockLength: orchestrator.performance.maxObjectSize @@ -62,14 +62,13 @@ internal final class FileReader: Reader { // get event blocks only .compactMap { switch $0.type { - case .event: - return $0.data + case .event, .eventMetadata: + return $0 } } - // decrypt data - report failure - .compactMap { (data: Data) in + .compactMap { dataBlock in do { - return try decrypt(data: data) + return try decrypt(dataBlock: dataBlock) } catch { failure = "🔥 Failed to decrypt data with error: \(error)" return nil @@ -77,6 +76,11 @@ internal final class FileReader: Reader { } } + private func decrypt(dataBlock: DataBlock) throws -> DataBlock { + let decrypted = try decrypt(data: dataBlock.data) + return DataBlock(type: dataBlock.type, data: decrypted) + } + /// Decrypts data if encryption is available. /// /// If no encryption, the data is returned. diff --git a/Sources/Datadog/DatadogCore/Storage/Reading/Reader.swift b/Sources/Datadog/DatadogCore/Storage/Reading/Reader.swift index 9669bfac51..ef22ee91a9 100644 --- a/Sources/Datadog/DatadogCore/Storage/Reading/Reader.swift +++ b/Sources/Datadog/DatadogCore/Storage/Reading/Reader.swift @@ -7,11 +7,20 @@ import Foundation internal struct Batch { - let events: [Data] + /// Data blocks in the batch. + let dataBlocks: [DataBlock] /// File from which `data` was read. let file: ReadableFile } +extension Batch { + /// Events contained in the batch. + var events: [Event] { + let generator = EventGenerator(dataBlocks: dataBlocks) + return generator.map { $0 } + } +} + /// A type, reading batched data. internal protocol Reader { func readNextBatch() -> Batch? diff --git a/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift b/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift index 27b3c7d155..700f2b10df 100644 --- a/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift +++ b/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift @@ -21,12 +21,25 @@ internal struct FileWriter: Writer { // MARK: - Writing data /// Encodes given value to JSON data and writes it to the file. - func write(value: T) { + func write(value: T, metadata: M?) { do { - let data = try encode(event: value) - let writeSize = UInt64(data.count) + let encodedValue = try encode(encodable: value, blockType: .event) + let encodedMetadata: Data? + if let metadata = metadata { + encodedMetadata = try encode(encodable: metadata, blockType: .eventMetadata) + } else { + encodedMetadata = nil + } + + // Make sure both event and event metadata are written to the same file. + // This is to avoid a situation where event is written to one file and event metadata to another. + // If this happens, the reader will not be able to match event with its metadata. + let writeSize = UInt64(encodedValue.count + (encodedMetadata?.count ?? 0)) let file = try forceNewFile ? orchestrator.getNewWritableFile(writeSize: writeSize) : orchestrator.getWritableFile(writeSize: writeSize) - try file.append(data: data) + try file.append(data: encodedValue) + if let encodedMetadata = encodedMetadata { + try file.append(data: encodedMetadata) + } } catch { DD.logger.error("Failed to write data", error: error) DD.telemetry.error("Failed to write data to file", error: error) @@ -46,10 +59,10 @@ internal struct FileWriter: Writer { /// /// - Parameter event: The value to encode. /// - Returns: Data representation of the value. - private func encode(event: T) throws -> Data { - let data = try jsonEncoder.encode(event) + private func encode(encodable: Encodable, blockType: BlockType) throws -> Data { + let data = try jsonEncoder.encode(encodable) return try DataBlock( - type: .event, + type: blockType, data: encrypt(data: data) ).serialize( maxLength: orchestrator.performance.maxObjectSize diff --git a/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift b/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift index 5004c11c25..3c64b8fd3a 100644 --- a/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift +++ b/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift @@ -8,7 +8,14 @@ import Foundation /// A type, writing data. public protocol Writer { - func write(value: T) + func write(value: T, metadata: M?) +} + +extension Writer { + func write(value: T) { + let metadata: Data? = nil + write(value: value, metadata: metadata) + } } /// Writer performing writes asynchronously on a given queue. @@ -21,11 +28,12 @@ internal struct AsyncWriter: Writer { self.queue = queue } - func write(value: T) where T: Encodable { - queue.async { writer.write(value: value) } + func write(value: T, metadata: M?) { + queue.async { writer.write(value: value, metadata: metadata) } } } internal struct NOPWriter: Writer { - func write(value: T) where T: Encodable {} + func write(value: T, metadata: M?) { + } } diff --git a/Sources/Datadog/DatadogCore/Upload/DataUploader.swift b/Sources/Datadog/DatadogCore/Upload/DataUploader.swift index 6a4c21f4e9..624d814703 100644 --- a/Sources/Datadog/DatadogCore/Upload/DataUploader.swift +++ b/Sources/Datadog/DatadogCore/Upload/DataUploader.swift @@ -8,7 +8,7 @@ import Foundation /// A type that performs data uploads. internal protocol DataUploaderType { - func upload(events: [Data], context: DatadogContext) throws -> DataUploadStatus + func upload(events: [Event], context: DatadogContext) throws -> DataUploadStatus } /// Synchronously uploads data to server using `HTTPClient`. @@ -26,7 +26,7 @@ internal final class DataUploader: DataUploaderType { /// Uploads data synchronously (will block current thread) and returns the upload status. /// Uses timeout configured for `HTTPClient`. - func upload(events: [Data], context: DatadogContext) throws -> DataUploadStatus { + func upload(events: [Event], context: DatadogContext) throws -> DataUploadStatus { let request = try requestBuilder.request(for: events, with: context) let requestID = request.value(forHTTPHeaderField: URLRequestBuilder.HTTPHeader.ddRequestIDHeaderField) diff --git a/Sources/Datadog/DatadogInternal/Upload/Event.swift b/Sources/Datadog/DatadogInternal/Upload/Event.swift new file mode 100644 index 0000000000..c80a87933e --- /dev/null +++ b/Sources/Datadog/DatadogInternal/Upload/Event.swift @@ -0,0 +1,93 @@ +/* + * 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 2019-Present Datadog, Inc. + */ + +import Foundation + +/// Interface that allows filtering of the events before they are sent +/// to the server. +public protocol EventsFilter { + /// Filters the events. + /// - Parameter events: The events to be filtered. + /// - Returns: The filtered events. + func filter(events: [Event]) -> [Event] +} + +/// Struct representing a single event. +public struct Event: Equatable { + /// Data representing the event. + public let data: Data + + /// Metadata associated with the event. + /// Metadata is optional and may be `nil` but of very small size. + /// This allows us to skip resource intensive operations in case such + /// as filtering of the events. + public let metadata: Data? + + public init(data: Data, metadata: Data?) { + self.data = data + self.metadata = metadata + } +} + +/// Event generator that generates events from the given data blocks. +internal struct EventGenerator: Sequence, IteratorProtocol { + private let dataBlocks: [DataBlock] + private var index: Int + + init(dataBlocks: [DataBlock], index: Int = 0) { + self.dataBlocks = dataBlocks + self.index = index + } + + /// Returns the next event. + /// - Returns: The next event or `nil` if there are no more events. + /// - Note: a `DataBlock` with `.event` type marks the beginning of the event. + /// It is either followed by another `DataBlock` with `.event` type or + /// by a `DataBlock` with `.metadata` type. + mutating func next() -> Event? { + guard index < dataBlocks.count else { + return nil + } + + let event = dataBlocks[index] + index += 1 + // if the first block is not event, then skip it + guard event.type == .event else { + return next() + } + + // if the next block is also event, then there is no metadata + guard index < dataBlocks.count, dataBlocks[index].type != .event else { + return Event(data: event.data, metadata: nil) + } + + // otherwise, the next block is metadata + let metadata = dataBlocks[index] + index += 1 + + return Event(data: event.data, metadata: metadata.data) + } +} + +extension RUMViewEvent { + /// Metadata associated with the `RUMViewEvent`. + /// It may be used to filter out the `RUMViewEvent` from the batch. + struct Metadata: Codable { + let id: String + let documentVersion: Int64 + + private enum CodingKeys: String, CodingKey { + case id = "id" + case documentVersion = "document_version" + } + } + + /// Creates `Metadata` from the given `RUMViewEvent`. + /// - Returns: The `Metadata` for the given `RUMViewEvent`. + func metadata() -> Metadata { + return Metadata(id: view.id, documentVersion: dd.documentVersion) + } +} diff --git a/Sources/Datadog/DatadogInternal/Upload/FeatureRequestBuilder.swift b/Sources/Datadog/DatadogInternal/Upload/FeatureRequestBuilder.swift index 87eb3059ac..80ac415d77 100644 --- a/Sources/Datadog/DatadogInternal/Upload/FeatureRequestBuilder.swift +++ b/Sources/Datadog/DatadogInternal/Upload/FeatureRequestBuilder.swift @@ -25,5 +25,5 @@ public protocol FeatureRequestBuilder { /// - context: The current core context. /// - events: The events data to be uploaded. /// - Returns: The URL request. - func request(for events: [Data], with context: DatadogContext) throws -> URLRequest + func request(for events: [Event], with context: DatadogContext) throws -> URLRequest } diff --git a/Sources/Datadog/Logging/LoggingV2Configuration.swift b/Sources/Datadog/Logging/LoggingV2Configuration.swift index e91f67b4ac..3addbbca62 100644 --- a/Sources/Datadog/Logging/LoggingV2Configuration.swift +++ b/Sources/Datadog/Logging/LoggingV2Configuration.swift @@ -36,7 +36,7 @@ internal struct LoggingRequestBuilder: FeatureRequestBuilder { /// The logs request body format. let format = DataFormat(prefix: "[", suffix: "]", separator: ",") - func request(for events: [Data], with context: DatadogContext) -> URLRequest { + func request(for events: [Event], with context: DatadogContext) -> URLRequest { let builder = URLRequestBuilder( url: intake, queryItems: [ @@ -56,7 +56,7 @@ internal struct LoggingRequestBuilder: FeatureRequestBuilder { ] ) - let data = format.format(events) + let data = format.format(events.map { $0.data }) return builder.uploadRequest(with: data) } } diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift index 864cde834b..7e57b8a84f 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift @@ -509,7 +509,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { if let event = dependencies.eventBuilder.build(from: viewEvent) { if viewUpdatesThrottler.accept(event: event) { - writer.write(value: event) + writer.write(value: event, metadata: event.metadata()) } else { // if event was dropped by sampler version -= 1 } diff --git a/Sources/Datadog/RUM/RUMV2Configuration.swift b/Sources/Datadog/RUM/RUMV2Configuration.swift index 9a40728fe1..201b365786 100644 --- a/Sources/Datadog/RUM/RUMV2Configuration.swift +++ b/Sources/Datadog/RUM/RUMV2Configuration.swift @@ -13,7 +13,10 @@ import Foundation internal func createRUMConfiguration(configuration: FeaturesConfiguration.RUM) -> DatadogFeatureConfiguration { return DatadogFeatureConfiguration( name: "rum", - requestBuilder: RUMRequestBuilder(intake: configuration.uploadURL), + requestBuilder: RUMRequestBuilder( + intake: configuration.uploadURL, + eventsFilter: RUMViewEventsFilter() + ), messageReceiver: CombinedFeatureMessageReceiver( ErrorMessageReceiver(), WebViewEventReceiver( @@ -30,6 +33,45 @@ internal func createRUMConfiguration(configuration: FeaturesConfiguration.RUM) - ) } +internal struct RUMViewEventsFilter: EventsFilter { + let decoder: JSONDecoder + + init(decoder: JSONDecoder = JSONDecoder()) { + self.decoder = decoder + } + + func filter(events: [Event]) -> [Event] { + var seen = Set() + var filtered = [Event]() + + // reversed is O(1) and no copy because it is view on the original array + for event in events.reversed() { + guard let metadata = event.metadata else { + // If there is no metadata, we can't filter it. + filtered.append(event) + continue + } + + guard let viewMetadata = try? decoder.decode(RUMViewEvent.Metadata.self, from: metadata) else { + // If we can't decode the metadata, we can't filter it. + filtered.append(event) + continue + } + + guard seen.contains(viewMetadata.id) == false else { + // If we've already seen this view, we can skip this + DD.logger.debug("Skipping RUMViewEvent with id: \(viewMetadata.id)") + continue + } + + filtered.append(event) + seen.insert(viewMetadata.id) + } + + return filtered.reversed() + } +} + /// The RUM URL Request Builder for formatting and configuring the `URLRequest` /// to upload RUM data. internal struct RUMRequestBuilder: FeatureRequestBuilder { @@ -39,7 +81,9 @@ internal struct RUMRequestBuilder: FeatureRequestBuilder { /// The RUM request body format. let format = DataFormat(prefix: "", suffix: "", separator: "\n") - func request(for events: [Data], with context: DatadogContext) -> URLRequest { + let eventsFilter: EventsFilter + + func request(for events: [Event], with context: DatadogContext) -> URLRequest { var tags = [ "service:\(context.service)", "version:\(context.version)", @@ -71,7 +115,8 @@ internal struct RUMRequestBuilder: FeatureRequestBuilder { ] ) - let data = format.format(events) + let filteredEvents = eventsFilter.filter(events: events) + let data = format.format(filteredEvents.map { $0.data }) return builder.uploadRequest(with: data) } } diff --git a/Sources/Datadog/Tracing/TracingV2Configuration.swift b/Sources/Datadog/Tracing/TracingV2Configuration.swift index be27569e2e..6864e7191c 100644 --- a/Sources/Datadog/Tracing/TracingV2Configuration.swift +++ b/Sources/Datadog/Tracing/TracingV2Configuration.swift @@ -27,7 +27,7 @@ internal struct TracingRequestBuilder: FeatureRequestBuilder { /// The tracing request body format. let format = DataFormat(prefix: "", suffix: "", separator: "\n") - func request(for events: [Data], with context: DatadogContext) -> URLRequest { + func request(for events: [Event], with context: DatadogContext) -> URLRequest { let builder = URLRequestBuilder( url: intake, queryItems: [], @@ -45,7 +45,7 @@ internal struct TracingRequestBuilder: FeatureRequestBuilder { ] ) - let data = format.format(events) + let data = format.format(events.map { $0.data }) return builder.uploadRequest(with: data) } } diff --git a/TestUtilities/Mocks/FileWriterMock.swift b/TestUtilities/Mocks/FileWriterMock.swift index 71704b94b5..11af7908d8 100644 --- a/TestUtilities/Mocks/FileWriterMock.swift +++ b/TestUtilities/Mocks/FileWriterMock.swift @@ -16,7 +16,7 @@ public class FileWriterMock: Writer { /// Adds an `Encodable` event to the events stack. /// /// - Parameter value: The event value to record. - public func write(value: T) where T: Encodable { + public func write(value: T, metadata: M) { events.append(value) } diff --git a/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift b/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift index fb24618f6e..6636d97e02 100644 --- a/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift +++ b/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift @@ -13,7 +13,7 @@ extension PerformancePreset { struct FeatureRequestBuilderMock: FeatureRequestBuilder { let dataFormat = DataFormat(prefix: "", suffix: "", separator: "\n") - func request(for events: [Data], with context: DatadogContext) -> URLRequest { + func request(for events: [Event], with context: DatadogContext) -> URLRequest { let builder = URLRequestBuilder( url: .mockAny(), queryItems: [.ddtags(tags: ["foo:bar"])], diff --git a/Tests/DatadogTests/Datadog/Core/FeatureTests.swift b/Tests/DatadogTests/Datadog/Core/FeatureTests.swift index fdc991f9d7..385e8ef02e 100644 --- a/Tests/DatadogTests/Datadog/Core/FeatureTests.swift +++ b/Tests/DatadogTests/Datadog/Core/FeatureTests.swift @@ -84,7 +84,7 @@ class FeatureStorageTests: XCTestCase { storage.setIgnoreFilesAgeWhenReading(to: true) let batch = try XCTUnwrap(storage.reader.readNextBatch()) - XCTAssertEqual(batch.events.map { $0.utf8String }, [#"{"event.consent":"granted"}"#]) + XCTAssertEqual(batch.events.map { $0.data.utf8String }, [#"{"event.consent":"granted"}"#]) storage.reader.markBatchAsRead(batch) XCTAssertNil(storage.reader.readNextBatch(), "There must be no other batches") @@ -103,11 +103,11 @@ class FeatureStorageTests: XCTestCase { storage.setIgnoreFilesAgeWhenReading(to: true) var batch = try XCTUnwrap(storage.reader.readNextBatch()) - XCTAssertEqual(batch.events.map { $0.utf8String }, [#"{"event.consent":"granted"}"#]) + XCTAssertEqual(batch.events.map { $0.data.utf8String }, [#"{"event.consent":"granted"}"#]) storage.reader.markBatchAsRead(batch) batch = try XCTUnwrap(storage.reader.readNextBatch()) - XCTAssertEqual(batch.events.map { $0.utf8String }, [#"{"event.consent":"pending"}"#]) + XCTAssertEqual(batch.events.map { $0.data.utf8String }, [#"{"event.consent":"pending"}"#]) storage.reader.markBatchAsRead(batch) XCTAssertNil(storage.reader.readNextBatch(), "There must be no other batches") @@ -126,7 +126,7 @@ class FeatureStorageTests: XCTestCase { storage.setIgnoreFilesAgeWhenReading(to: true) let batch = try XCTUnwrap(storage.reader.readNextBatch()) - XCTAssertEqual(batch.events.map { $0.utf8String }, [#"{"event.consent":"granted"}"#]) + XCTAssertEqual(batch.events.map { $0.data.utf8String }, [#"{"event.consent":"granted"}"#]) storage.reader.markBatchAsRead(batch) XCTAssertNil(storage.reader.readNextBatch(), "There must be no other batches") diff --git a/Tests/DatadogTests/Datadog/Core/Persistence/DataBlockTests.swift b/Tests/DatadogTests/Datadog/Core/Persistence/DataBlockTests.swift index e09b65ca5e..2a6b20e98a 100644 --- a/Tests/DatadogTests/Datadog/Core/Persistence/DataBlockTests.swift +++ b/Tests/DatadogTests/Datadog/Core/Persistence/DataBlockTests.swift @@ -8,6 +8,20 @@ import XCTest @testable import Datadog class DataBlockTests: XCTestCase { + func testSerializeEventBlock() throws { + XCTAssertEqual( + try DataBlock(type: .event, data: Data([0xFF])).serialize(), + Data([0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF]) + ) + } + + func testSerializeEventMetadataBlock() throws { + XCTAssertEqual( + try DataBlock(type: .eventMetadata, data: Data([0xFF])).serialize(), + Data([0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF]) + ) + } + func testSerializeDataBlock() throws { XCTAssertEqual( try DataBlock(type: .event, data: Data([0xFF])).serialize(), @@ -33,6 +47,22 @@ class DataBlockTests: XCTestCase { XCTAssertEqual(data.prefix(7), Data([0x00, 0x00, 0x80, 0x96, 0x98, 0x00, 0xFF])) } + func testDataBlockReader_withEventDataBlock() throws { + let data = Data([0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF]) + let reader = DataBlockReader(data: data) + let block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, Data([0xFF])) + } + + func testDataBlockReader_withEventMetadataBlock() throws { + let data = Data([0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF]) + let reader = DataBlockReader(data: data) + let block = try reader.next() + XCTAssertEqual(block?.type, .eventMetadata) + XCTAssertEqual(block?.data, Data([0xFF])) + } + func testDataBlockReader_withSingleBlock() throws { let data = Data([0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF]) let reader = DataBlockReader(data: data) diff --git a/Tests/DatadogTests/Datadog/Core/Persistence/EventGeneratorTests.swift b/Tests/DatadogTests/Datadog/Core/Persistence/EventGeneratorTests.swift new file mode 100644 index 0000000000..e5e46cfa43 --- /dev/null +++ b/Tests/DatadogTests/Datadog/Core/Persistence/EventGeneratorTests.swift @@ -0,0 +1,71 @@ +/* + * 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 2019-Present Datadog, Inc. + */ + +import XCTest +@testable import Datadog + +final class EventGeneratorTests: XCTestCase { + func testEmpty() throws { + let dataBlocks = [DataBlock]() + + let sut = EventGenerator(dataBlocks: dataBlocks) + let events = sut.map { $0 } + XCTAssertEqual(events.count, 0) + } + + func testWithoutEvent() throws { + let dataBlocks = [DataBlock(type: .eventMetadata, data: Data([0x01]))] + + let sut = EventGenerator(dataBlocks: dataBlocks) + let events = sut.map { $0 } + XCTAssertEqual(events.count, 0) + } + + func testEventWithoutMetadata() throws { + let dataBlocks = [DataBlock(type: .event, data: Data([0x01]))] + + let sut = EventGenerator(dataBlocks: dataBlocks) + let events = sut.map { $0 } + XCTAssertEqual(events.count, 1) + XCTAssertEqual(events[0].data, Data([0x01])) + XCTAssertNil(events[0].metadata) + } + + func testEventWithMetadata() throws { + let dataBlocks = [ + DataBlock(type: .event, data: Data([0x01])), + DataBlock(type: .eventMetadata, data: Data([0x02])) + ] + + let sut = EventGenerator(dataBlocks: dataBlocks) + let events = sut.map { $0 } + XCTAssertEqual(events.count, 1) + XCTAssertEqual(events[0].data, Data([0x01])) + XCTAssertEqual(events[0].metadata, Data([0x02])) + } + + func testEvents() { + let dataBlocks = [ + DataBlock(type: .event, data: Data([0x01])), + DataBlock(type: .eventMetadata, data: Data([0x02])), + DataBlock(type: .event, data: Data([0x03])), + DataBlock(type: .event, data: Data([0x05])) + ] + + let sut = EventGenerator(dataBlocks: dataBlocks) + let events = sut.map { $0 } + XCTAssertEqual(events.count, 3) + + XCTAssertEqual(events[0].data, Data([0x01])) + XCTAssertEqual(events[0].metadata, Data([0x02])) + + XCTAssertEqual(events[1].data, Data([0x03])) + XCTAssertNil(events[1].metadata) + + XCTAssertEqual(events[2].data, Data([0x05])) + XCTAssertNil(events[2].metadata) + } +} diff --git a/Tests/DatadogTests/Datadog/Core/Persistence/Reading/FileReaderTests.swift b/Tests/DatadogTests/Datadog/Core/Persistence/Reading/FileReaderTests.swift index 23f5d29234..4e6170268d 100644 --- a/Tests/DatadogTests/Datadog/Core/Persistence/Reading/FileReaderTests.swift +++ b/Tests/DatadogTests/Datadog/Core/Persistence/Reading/FileReaderTests.swift @@ -26,19 +26,37 @@ class FileReaderTests: XCTestCase { dateProvider: SystemDateProvider() ) ) + let dataBlocks = [ + DataBlock(type: .event, data: "ABCD".utf8Data), + DataBlock(type: .eventMetadata, data: "EFGH".utf8Data) + ] + let data = try dataBlocks + .map { try $0.serialize() } + .reduce(.init(), +) _ = try temporaryDirectory .createFile(named: Date.mockAny().toFileName) - .append(data: DataBlock(type: .event, data: "ABCD".utf8Data).serialize()) + .append(data: data) XCTAssertEqual(try temporaryDirectory.files().count, 1) let batch = reader.readNextBatch() - XCTAssertEqual(batch?.events, ["ABCD".utf8Data]) + + let expected = [ + Event(data: "ABCD".utf8Data, metadata: "EFGH".utf8Data) + ] + XCTAssertEqual(batch?.events, expected) } func testItReadsSingleEncryptedBatch() throws { // Given - let data = try Array(repeating: "foo".utf8Data, count: 3) - .map { try DataBlock(type: .event, data: $0).serialize() } + let dataBlocks = [ + DataBlock(type: .event, data: "foo".utf8Data), + DataBlock(type: .eventMetadata, data: "foo".utf8Data), + DataBlock(type: .event, data: "foo".utf8Data), + DataBlock(type: .event, data: "foo".utf8Data), + DataBlock(type: .eventMetadata, data: "foo".utf8Data) + ] + let data = try dataBlocks + .map { Data(try $0.serialize()) } .reduce(.init(), +) _ = try temporaryDirectory @@ -60,7 +78,12 @@ class FileReaderTests: XCTestCase { let batch = reader.readNextBatch() // Then - XCTAssertEqual(batch?.events, ["bar","bar","bar"].map { $0.utf8Data }) + let expected = [ + Event(data: "bar".utf8Data, metadata: "bar".utf8Data), + Event(data: "bar".utf8Data, metadata: nil), + Event(data: "bar".utf8Data, metadata: "bar".utf8Data) + ] + XCTAssertEqual(batch?.events, expected) } func testItMarksBatchesAsRead() throws { @@ -74,24 +97,32 @@ class FileReaderTests: XCTestCase { ) let file1 = try temporaryDirectory.createFile(named: dateProvider.now.toFileName) try file1.append(data: DataBlock(type: .event, data: "1".utf8Data).serialize()) + try file1.append(data: DataBlock(type: .eventMetadata, data: "2".utf8Data).serialize()) let file2 = try temporaryDirectory.createFile(named: dateProvider.now.toFileName) try file2.append(data: DataBlock(type: .event, data: "2".utf8Data).serialize()) let file3 = try temporaryDirectory.createFile(named: dateProvider.now.toFileName) try file3.append(data: DataBlock(type: .event, data: "3".utf8Data).serialize()) + try file3.append(data: DataBlock(type: .eventMetadata, data: "4".utf8Data).serialize()) + + let expected = [ + Event(data: "1".utf8Data, metadata: "2".utf8Data), + Event(data: "2".utf8Data, metadata: nil), + Event(data: "3".utf8Data, metadata: "4".utf8Data) + ] var batch: Batch batch = try reader.readNextBatch().unwrapOrThrow() - XCTAssertEqual(batch.events.first, "1".utf8Data) + XCTAssertEqual(batch.events.first, expected[0]) reader.markBatchAsRead(batch) batch = try reader.readNextBatch().unwrapOrThrow() - XCTAssertEqual(batch.events.first, "2".utf8Data) + XCTAssertEqual(batch.events.first, expected[1]) reader.markBatchAsRead(batch) batch = try reader.readNextBatch().unwrapOrThrow() - XCTAssertEqual(batch.events.first, "3".utf8Data) + XCTAssertEqual(batch.events.first, expected[2]) reader.markBatchAsRead(batch) XCTAssertNil(reader.readNextBatch()) diff --git a/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift b/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift index ae07db0a0b..2c1c365333 100644 --- a/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift +++ b/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift @@ -19,6 +19,42 @@ class FileWriterTests: XCTestCase { super.tearDown() } + func testItWritesDataWithMetadataToSingleFileInTLVFormat() throws { + let writer = FileWriter( + orchestrator: FilesOrchestrator( + directory: temporaryDirectory, + performance: PerformancePreset.mockAny(), + dateProvider: SystemDateProvider() + ), + encryption: nil, + forceNewFile: false + ) + + writer.write(value: ["key1": "value1"], metadata: ["meta1": "metaValue1"]) + writer.write(value: ["key2": "value2"]) // skipped metadata here + writer.write(value: ["key3": "value3"], metadata: ["meta3": "metaValue3"]) + + XCTAssertEqual(try temporaryDirectory.files().count, 1) + let stream = try temporaryDirectory.files()[0].stream() + + let reader = DataBlockReader(input: stream) + var block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, #"{"key1":"value1"}"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .eventMetadata) + XCTAssertEqual(block?.data, #"{"meta1":"metaValue1"}"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, #"{"key2":"value2"}"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, #"{"key3":"value3"}"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .eventMetadata) + XCTAssertEqual(block?.data, #"{"meta3":"metaValue3"}"#.utf8Data) + } + func testItWritesDataToSingleFileInTLVFormat() throws { let writer = FileWriter( orchestrator: FilesOrchestrator( @@ -219,7 +255,7 @@ class FileWriterTests: XCTestCase { } func testItWritesEncryptedDataToSingleFile() throws { - // Given + // Given let writer = FileWriter( orchestrator: FilesOrchestrator( directory: temporaryDirectory, @@ -233,23 +269,34 @@ class FileWriterTests: XCTestCase { ) // When - writer.write(value: ["key1": "value1"]) + writer.write(value: ["key1": "value1"], metadata: ["meta1": "metaValue1"]) writer.write(value: ["key2": "value3"]) - writer.write(value: ["key3": "value3"]) + writer.write(value: ["key3": "value3"], metadata: ["meta3": "metaValue3"]) // Then XCTAssertEqual(try temporaryDirectory.files().count, 1) let stream = try temporaryDirectory.files()[0].stream() let reader = DataBlockReader(input: stream) + var block = try reader.next() XCTAssertEqual(block?.type, .event) XCTAssertEqual(block?.data, "foo".utf8Data) + + block = try reader.next() + XCTAssertEqual(block?.type, .eventMetadata) + XCTAssertEqual(block?.data, "foo".utf8Data) + block = try reader.next() XCTAssertEqual(block?.type, .event) XCTAssertEqual(block?.data, "foo".utf8Data) + block = try reader.next() XCTAssertEqual(block?.type, .event) XCTAssertEqual(block?.data, "foo".utf8Data) + + block = try reader.next() + XCTAssertEqual(block?.type, .eventMetadata) + XCTAssertEqual(block?.data, "foo".utf8Data) } } diff --git a/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift b/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift index e12f11f042..f79c943fc0 100644 --- a/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift +++ b/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift @@ -72,7 +72,7 @@ class DatadogCoreTests: XCTestCase { let uploadedEvents = requestBuilderSpy.requestParameters .flatMap { $0.events } - .map { $0.utf8String } + .map { $0.data.utf8String } XCTAssertEqual(uploadedEvents, [#"{"event":"granted"}"#], "Only `.granted` events should be uploaded") XCTAssertEqual(requestBuilderSpy.requestParameters.count, 1, "It should send only one request") @@ -121,7 +121,7 @@ class DatadogCoreTests: XCTestCase { let uploadedEvents = requestBuilderSpy.requestParameters .flatMap { $0.events } - .map { $0.utf8String } + .map { $0.data.utf8String } XCTAssertEqual( uploadedEvents, @@ -175,7 +175,7 @@ class DatadogCoreTests: XCTestCase { let uploadedEvents = requestBuilderSpy.requestParameters .flatMap { $0.events } - .map { $0.utf8String } + .map { $0.data.utf8String } XCTAssertEqual( uploadedEvents, diff --git a/Tests/DatadogTests/Datadog/DatadogInternal/Upload/DataFormatTests.swift b/Tests/DatadogTests/Datadog/DatadogInternal/Upload/DataFormatTests.swift new file mode 100644 index 0000000000..e08396115b --- /dev/null +++ b/Tests/DatadogTests/Datadog/DatadogInternal/Upload/DataFormatTests.swift @@ -0,0 +1,28 @@ +/* + * 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 2019-Present Datadog, Inc. + */ + +import XCTest +@testable import Datadog + +final class DataFormatTests: XCTestCase { + func testFormat() throws { + let format = DataFormat(prefix: "prefix", suffix: "suffix", separator: "\n") + let events = [ + "abc".data(using: .utf8)!, + "def".data(using: .utf8)!, + "ghi".data(using: .utf8)! + ] + let formatted = format.format(events) + let actual = String(data: formatted, encoding: .utf8)! + let expected = + """ + prefixabc + def + ghisuffix + """ + XCTAssertEqual(actual, expected) + } +} diff --git a/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift b/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift index d8947f61ec..000eedce3b 100644 --- a/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift @@ -659,7 +659,7 @@ struct DataUploaderMock: DataUploaderType { var onUpload: (() throws -> Void)? = nil - func upload(events: [Data], context: DatadogContext) throws -> DataUploadStatus { + func upload(events: [Event], context: DatadogContext) throws -> DataUploadStatus { try onUpload?() return uploadStatus } diff --git a/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift b/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift index 4cc526dc0d..ee363e7ef5 100644 --- a/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift +++ b/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift @@ -149,8 +149,8 @@ private class FeatureScopeInterceptor { let actualWriter: Writer unowned var interception: FeatureScopeInterceptor? - func write(value: T) where T: Encodable { - actualWriter.write(value: value) + func write(value: T, metadata: M) { + actualWriter.write(value: value, metadata: metadata) let event = value let data = try! InterceptingWriter.jsonEncoder.encode(value) diff --git a/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/UploadMock.swift b/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/UploadMock.swift index 2e340fdc9b..cec3814e9e 100644 --- a/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/UploadMock.swift +++ b/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/UploadMock.swift @@ -26,18 +26,18 @@ internal struct FeatureRequestBuilderMock: FeatureRequestBuilder { self.format = format } - func request(for events: [Data], with context: DatadogContext) throws -> URLRequest { + func request(for events: [Event], with context: DatadogContext) throws -> URLRequest { let builder = URLRequestBuilder(url: url, queryItems: queryItems, headers: headers) - let data = format.format(events) + let data = format.format(events.map { $0.data }) return builder.uploadRequest(with: data) } } internal class FeatureRequestBuilderSpy: FeatureRequestBuilder { /// Records parameters passed to `requet(for:with:)` - var requestParameters: [(events: [Data], context: DatadogContext)] = [] + var requestParameters: [(events: [Event], context: DatadogContext)] = [] - func request(for events: [Data], with context: DatadogContext) throws -> URLRequest { + func request(for events: [Event], with context: DatadogContext) throws -> URLRequest { requestParameters.append((events: events, context: context)) return .mockAny() } @@ -46,7 +46,7 @@ internal class FeatureRequestBuilderSpy: FeatureRequestBuilder { internal struct FailingRequestBuilderMock: FeatureRequestBuilder { let error: Error - func request(for events: [Data], with context: DatadogContext) throws -> URLRequest { + func request(for events: [Event], with context: DatadogContext) throws -> URLRequest { throw error } } diff --git a/Tests/DatadogTests/Datadog/RUM/RUMFeatureTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMFeatureTests.swift index 6e2c4c9cdb..2442142475 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMFeatureTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMFeatureTests.swift @@ -210,22 +210,21 @@ class RUMFeatureTests: XCTestCase { core.register(feature: feature) let writer = feature.storage.writer(for: .granted, forceNewBatch: false) - writer.write(value: RUMDataModelMock(attribute: "1st event")) - writer.write(value: RUMDataModelMock(attribute: "2nd event")) - writer.write(value: RUMDataModelMock(attribute: "3rd event")) + writer.write(value: RUMDataModelMock(attribute: "1st event"), metadata: RUMViewEvent.Metadata(id: "1", documentVersion: 1)) + writer.write(value: RUMDataModelMock(attribute: "2nd event"), metadata: RUMViewEvent.Metadata(id: "2", documentVersion: 1)) + writer.write(value: RUMDataModelMock(attribute: "3rd event"), metadata: RUMViewEvent.Metadata(id: "1", documentVersion: 2)) let payload = try XCTUnwrap(server.waitAndReturnRequests(count: 1)[0].httpBody) // Expected payload format: + // event1JSON is skipped in favor of event3JSON which is same event with higher document revision // ``` - // event1JSON // event2JSON // event3JSON // ``` let eventMatchers = try RUMEventMatcher.fromNewlineSeparatedJSONObjectsData(payload) - XCTAssertEqual((try eventMatchers[0].model() as RUMDataModelMock).attribute, "1st event") - XCTAssertEqual((try eventMatchers[1].model() as RUMDataModelMock).attribute, "2nd event") - XCTAssertEqual((try eventMatchers[2].model() as RUMDataModelMock).attribute, "3rd event") + XCTAssertEqual((try eventMatchers[0].model() as RUMDataModelMock).attribute, "2nd event") + XCTAssertEqual((try eventMatchers[1].model() as RUMDataModelMock).attribute, "3rd event") } } diff --git a/Tests/DatadogTests/Datadog/RUM/RUMViewEventsFilterTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMViewEventsFilterTests.swift new file mode 100644 index 0000000000..4da40e901a --- /dev/null +++ b/Tests/DatadogTests/Datadog/RUM/RUMViewEventsFilterTests.swift @@ -0,0 +1,123 @@ +/* + * 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 2019-Present Datadog, Inc. + */ + +import XCTest +import TestUtilities +@testable import Datadog + +final class RUMViewEventsFilterTests: XCTestCase { + let sut = RUMViewEventsFilter() + + // MARK: - Base cases + + func testFilterWhenNoEvents() throws { + let events = [Event]() + + let actual = sut.filter(events: events) + let expected = [Event]() + + XCTAssertEqual(actual, expected) + } + + func testFilterWhenNoMetadata() throws { + let events = [ + try Event(data: "A.1", metadata: nil), + try Event(data: "A.2", metadata: nil), + try Event(data: "A.3", metadata: nil), + try Event(data: "A.4", metadata: nil) + ] + + let actual = sut.filter(events: events) + + XCTAssertEqual(actual, events) + } + + func testFilterWhenMixedMissingMetadata() throws { + let events = [ + try Event(data: "A.1", metadata: nil), + try Event(data: "A.2", metadata: nil), + try Event(data: "B.1", metadata: RUMViewEvent.Metadata(id: "B", documentVersion: 1)), + try Event(data: "B.2", metadata: RUMViewEvent.Metadata(id: "B", documentVersion: 2)), + try Event(data: "C.1", metadata: nil), + try Event(data: "B.3", metadata: RUMViewEvent.Metadata(id: "B", documentVersion: 3)), + try Event(data: "A.3", metadata: nil) + ] + + let actual = sut.filter(events: events) + let expected = [ + try Event(data: "A.1", metadata: nil), + try Event(data: "A.2", metadata: nil), + try Event(data: "C.1", metadata: nil), + try Event(data: "B.3", metadata: RUMViewEvent.Metadata(id: "B", documentVersion: 3)), + try Event(data: "A.3", metadata: nil) + ] + + XCTAssertEqual(actual, expected) + } + + // MARK: - Common filtering scenarios + + func testFilterWhenSameEvent() throws { + let events = [ + try Event(data: "A.1", metadata: RUMViewEvent.Metadata(id: "A", documentVersion: 1)), + try Event(data: "A.2", metadata: RUMViewEvent.Metadata(id: "A", documentVersion: 2)), + try Event(data: "A.3", metadata: RUMViewEvent.Metadata(id: "A", documentVersion: 3)), + try Event(data: "A.4", metadata: RUMViewEvent.Metadata(id: "A", documentVersion: 4)) + ] + + let actual = sut.filter(events: events) + let expected = [ + try Event(data: "A.4", metadata: RUMViewEvent.Metadata(id: "A", documentVersion: 4)) + ] + + XCTAssertEqual(actual, expected) + } + + func testFilterWhenMixedEvents() throws { + let events = [ + try Event(data: "B.1", metadata: RUMViewEvent.Metadata(id: "B", documentVersion: 1)), + try Event(data: "A.5", metadata: RUMViewEvent.Metadata(id: "A", documentVersion: 5)), + try Event(data: "B.2", metadata: RUMViewEvent.Metadata(id: "B", documentVersion: 2)), + ] + + let actual = sut.filter(events: events) + let expected = [ + try Event(data: "A.5", metadata: RUMViewEvent.Metadata(id: "A", documentVersion: 5)), + try Event(data: "B.2", metadata: RUMViewEvent.Metadata(id: "B", documentVersion: 2)), + ] + + XCTAssertEqual(actual, expected) + } + + func testFilterWhenSingleEvent() throws { + let events = [ + try Event(data: "B.3", metadata: RUMViewEvent.Metadata(id: "B", documentVersion: 3)), + ] + + let actual = sut.filter(events: events) + let expected = [ + try Event(data: "B.3", metadata: RUMViewEvent.Metadata(id: "B", documentVersion: 3)), + ] + + XCTAssertEqual(actual, expected) + } +} + +extension Event { + init(data: String, metadata: RUMViewEvent.Metadata?) throws { + self.init(data: data.utf8Data, metadata: try JSONEncoder().encode(metadata)) + } +} + +extension Event: AnyMockable { + public static func mockAny() -> Self { + return mockWith() + } + + public static func mockWith(data: Data = .init(), metadata: Data? = nil) -> Self { + return Event(data: data, metadata: metadata) + } +} From 3bed75c780ce4c5f57a5ca6c03ff9e93a0a97970 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Fri, 23 Jun 2023 17:03:48 +0200 Subject: [PATCH 02/87] RUMM-3151 remove namespace --- .../DatadogCoreIntegration/RequestBuilder/RequestBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DatadogSessionReplay/Sources/DatadogCoreIntegration/RequestBuilder/RequestBuilder.swift b/DatadogSessionReplay/Sources/DatadogCoreIntegration/RequestBuilder/RequestBuilder.swift index 1469220808..e15459a1a4 100644 --- a/DatadogSessionReplay/Sources/DatadogCoreIntegration/RequestBuilder/RequestBuilder.swift +++ b/DatadogSessionReplay/Sources/DatadogCoreIntegration/RequestBuilder/RequestBuilder.swift @@ -13,7 +13,7 @@ internal struct RequestBuilder: FeatureRequestBuilder { /// Custom URL for uploading data to. let customUploadURL: URL? - func request(for events: [Datadog.Event], with context: DatadogContext) throws -> URLRequest { + func request(for events: [Event], with context: DatadogContext) throws -> URLRequest { let source = SRSegment.Source(rawValue: context.source) ?? .ios // TODO: RUMM-2410 Send telemetry on `?? .ios` let segmentBuilder = SegmentJSONBuilder(source: source) From 8ccf78d1500a87eae061f613674c4186eca71cd5 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Fri, 23 Jun 2023 17:37:33 +0200 Subject: [PATCH 03/87] RUMM-3151 make write(value:) public --- Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift b/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift index 3c64b8fd3a..670429b809 100644 --- a/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift +++ b/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift @@ -12,7 +12,7 @@ public protocol Writer { } extension Writer { - func write(value: T) { + public func write(value: T) { let metadata: Data? = nil write(value: value, metadata: metadata) } From 5889552b7bee362ecfeabd9554e4adbc3f70c5a9 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Mon, 26 Jun 2023 13:59:24 +0200 Subject: [PATCH 04/87] RUMM-3151 convert for to compactMap --- Sources/Datadog/RUM/RUMV2Configuration.swift | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Sources/Datadog/RUM/RUMV2Configuration.swift b/Sources/Datadog/RUM/RUMV2Configuration.swift index 201b365786..29d25f1d11 100644 --- a/Sources/Datadog/RUM/RUMV2Configuration.swift +++ b/Sources/Datadog/RUM/RUMV2Configuration.swift @@ -42,30 +42,27 @@ internal struct RUMViewEventsFilter: EventsFilter { func filter(events: [Event]) -> [Event] { var seen = Set() - var filtered = [Event]() // reversed is O(1) and no copy because it is view on the original array - for event in events.reversed() { + let filtered = events.reversed().compactMap { event in guard let metadata = event.metadata else { // If there is no metadata, we can't filter it. - filtered.append(event) - continue + return event } guard let viewMetadata = try? decoder.decode(RUMViewEvent.Metadata.self, from: metadata) else { // If we can't decode the metadata, we can't filter it. - filtered.append(event) - continue + return event } guard seen.contains(viewMetadata.id) == false else { // If we've already seen this view, we can skip this DD.logger.debug("Skipping RUMViewEvent with id: \(viewMetadata.id)") - continue + return nil } - filtered.append(event) seen.insert(viewMetadata.id) + return event } return filtered.reversed() From 84beb875f14bfd5b0d29779a08e44ddffc8f299a Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Mon, 26 Jun 2023 14:05:51 +0200 Subject: [PATCH 05/87] RUMM-3151 docs updates --- .../Datadog/DatadogCore/Storage/Writing/FileWriter.swift | 6 +++++- Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift b/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift index 700f2b10df..520ccc4a57 100644 --- a/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift +++ b/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift @@ -20,7 +20,11 @@ internal struct FileWriter: Writer { // MARK: - Writing data - /// Encodes given value to JSON data and writes it to the file. + /// Encodes given encodable value and metadata, and writes it to the file. + /// If encryption is available, the data is encrypted before writing. + /// - Parameters: + /// - value: Encodable value to write. + /// - metadata: Encodable metadata to write. func write(value: T, metadata: M?) { do { let encodedValue = try encode(encodable: value, blockType: .event) diff --git a/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift b/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift index 670429b809..46be94373d 100644 --- a/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift +++ b/Sources/Datadog/DatadogCore/Storage/Writing/Writer.swift @@ -8,10 +8,16 @@ import Foundation /// A type, writing data. public protocol Writer { + /// Encodes given encodable value and metadata, and writes to the destination. + /// - Parameter value: Encodable value to write. + /// - Parameter metadata: Encodable metadata to write. func write(value: T, metadata: M?) } extension Writer { + /// Encodes given encodable value and writes to the destination. + /// Uses `write(value:metadata:)` with `nil` metadata. + /// - Parameter value: Encodable value to write. public func write(value: T) { let metadata: Data? = nil write(value: value, metadata: metadata) From df3ea1b2be0bb5c3f8f2384e9c2ec82d8d8ad6ef Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Mon, 26 Jun 2023 14:16:02 +0200 Subject: [PATCH 06/87] RUMM-3151 update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2dcbd4ce0..2de8648f9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- [IMPROVEMENT] Reduce number of view updates by filtering events from payload. See [#1328][] + # 1.20.0 / 01-06-2023 - [BUGFIX] Use targetTimestamp as reference to calculate FPS for variable refresh rate displays. See [#1272][] @@ -464,6 +466,7 @@ [#1259]: https://github.com/DataDog/dd-sdk-ios/pull/1259 [#1264]: https://github.com/DataDog/dd-sdk-ios/pull/1264 [#1272]: https://github.com/DataDog/dd-sdk-ios/pull/1272 +[#1328]: https://github.com/DataDog/dd-sdk-ios/pull/1328 [@00fa9a]: https://github.com/00FA9A [@britton-earnin]: https://github.com/Britton-Earnin [@hengyu]: https://github.com/Hengyu From 0c0db424579ff2ecc754a323398c4360604e076f Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Mon, 26 Jun 2023 15:47:12 +0200 Subject: [PATCH 07/87] RUMM-3151 guard against some invalid block --- Sources/Datadog/DatadogInternal/Upload/Event.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/Datadog/DatadogInternal/Upload/Event.swift b/Sources/Datadog/DatadogInternal/Upload/Event.swift index c80a87933e..64d5ba32fe 100644 --- a/Sources/Datadog/DatadogInternal/Upload/Event.swift +++ b/Sources/Datadog/DatadogInternal/Upload/Event.swift @@ -64,8 +64,11 @@ internal struct EventGenerator: Sequence, IteratorProtocol { return Event(data: event.data, metadata: nil) } - // otherwise, the next block is metadata + // otherwise, the next block can be metadata let metadata = dataBlocks[index] + guard metadata.type == .eventMetadata else { + return Event(data: event.data, metadata: nil) + } index += 1 return Event(data: event.data, metadata: metadata.data) From 0a77e34b0e02c9a972778b774a5ed602e777b736 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Mon, 26 Jun 2023 16:20:10 +0200 Subject: [PATCH 08/87] RUMM-3151 fix compilation issues for benchmark target --- Sources/Datadog/DatadogInternal/Upload/Event.swift | 2 +- Tests/DatadogBenchmarkTests/BenchmarkMocks.swift | 2 +- .../DataUpload/DataUploaderBenchmarkTests.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Datadog/DatadogInternal/Upload/Event.swift b/Sources/Datadog/DatadogInternal/Upload/Event.swift index 64d5ba32fe..bd7c51be43 100644 --- a/Sources/Datadog/DatadogInternal/Upload/Event.swift +++ b/Sources/Datadog/DatadogInternal/Upload/Event.swift @@ -26,7 +26,7 @@ public struct Event: Equatable { /// as filtering of the events. public let metadata: Data? - public init(data: Data, metadata: Data?) { + public init(data: Data, metadata: Data? = nil) { self.data = data self.metadata = metadata } diff --git a/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift b/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift index 6636d97e02..b968cf3386 100644 --- a/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift +++ b/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift @@ -20,7 +20,7 @@ struct FeatureRequestBuilderMock: FeatureRequestBuilder { headers: [] ) - let data = dataFormat.format(events) + let data = dataFormat.format(events.map { $0.data } ) return builder.uploadRequest(with: data) } } diff --git a/Tests/DatadogBenchmarkTests/DataUpload/DataUploaderBenchmarkTests.swift b/Tests/DatadogBenchmarkTests/DataUpload/DataUploaderBenchmarkTests.swift index 97d600a81f..35f34d1b44 100644 --- a/Tests/DatadogBenchmarkTests/DataUpload/DataUploaderBenchmarkTests.swift +++ b/Tests/DatadogBenchmarkTests/DataUpload/DataUploaderBenchmarkTests.swift @@ -35,7 +35,7 @@ class DataUploaderBenchmarkTests: BenchmarkTests { measure(metrics: [XCTMemoryMetric()]) { // in each, 10 requests are done: try? (0..<10).forEach { _ in - let events = [Data(repeating: 0x41, count: 10 * 1_024 * 1_024)] + let events = [Event(data: Data(repeating: 0x41, count: 10 * 1_024 * 1_024))] _ = try dataUploader.upload(events: events, context: context) } // After all, the baseline asserts `0kB` or less grow in Physical Memory. From ce7d6e4a1700fe593ccffc1eeb0fe2f72eb909ca Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Mon, 26 Jun 2023 17:22:28 +0200 Subject: [PATCH 09/87] RUMM-3151 fix linter --- Tests/DatadogBenchmarkTests/BenchmarkMocks.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift b/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift index b968cf3386..9f106352d5 100644 --- a/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift +++ b/Tests/DatadogBenchmarkTests/BenchmarkMocks.swift @@ -20,7 +20,7 @@ struct FeatureRequestBuilderMock: FeatureRequestBuilder { headers: [] ) - let data = dataFormat.format(events.map { $0.data } ) + let data = dataFormat.format(events.map { $0.data }) return builder.uploadRequest(with: data) } } From f8d53b7a3665baba9790c7fe7aa31893a251cc80 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Tue, 27 Jun 2023 11:34:53 +0200 Subject: [PATCH 10/87] RUMM-3151 remove compactMap --- .../Datadog/DatadogCore/Storage/Reading/FileReader.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Sources/Datadog/DatadogCore/Storage/Reading/FileReader.swift b/Sources/Datadog/DatadogCore/Storage/Reading/FileReader.swift index b52262f181..1025bddf4a 100644 --- a/Sources/Datadog/DatadogCore/Storage/Reading/FileReader.swift +++ b/Sources/Datadog/DatadogCore/Storage/Reading/FileReader.swift @@ -59,13 +59,6 @@ internal final class FileReader: Reader { } return try reader.all() - // get event blocks only - .compactMap { - switch $0.type { - case .event, .eventMetadata: - return $0 - } - } .compactMap { dataBlock in do { return try decrypt(dataBlock: dataBlock) From bfa773de8efa4ff9e8faa878ebff3305c204065e Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Tue, 27 Jun 2023 11:35:11 +0200 Subject: [PATCH 11/87] RUMM-3151 move code around to RUM module --- .../DatadogInternal/Upload/Event.swift | 20 ------------------- .../RUM/DataModels/RUMDataModelsMapping.swift | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Sources/Datadog/DatadogInternal/Upload/Event.swift b/Sources/Datadog/DatadogInternal/Upload/Event.swift index bd7c51be43..87d53c5197 100644 --- a/Sources/Datadog/DatadogInternal/Upload/Event.swift +++ b/Sources/Datadog/DatadogInternal/Upload/Event.swift @@ -74,23 +74,3 @@ internal struct EventGenerator: Sequence, IteratorProtocol { return Event(data: event.data, metadata: metadata.data) } } - -extension RUMViewEvent { - /// Metadata associated with the `RUMViewEvent`. - /// It may be used to filter out the `RUMViewEvent` from the batch. - struct Metadata: Codable { - let id: String - let documentVersion: Int64 - - private enum CodingKeys: String, CodingKey { - case id = "id" - case documentVersion = "document_version" - } - } - - /// Creates `Metadata` from the given `RUMViewEvent`. - /// - Returns: The `Metadata` for the given `RUMViewEvent`. - func metadata() -> Metadata { - return Metadata(id: view.id, documentVersion: dd.documentVersion) - } -} diff --git a/Sources/Datadog/RUM/DataModels/RUMDataModelsMapping.swift b/Sources/Datadog/RUM/DataModels/RUMDataModelsMapping.swift index 8cc79b5b66..e40fe2034c 100644 --- a/Sources/Datadog/RUM/DataModels/RUMDataModelsMapping.swift +++ b/Sources/Datadog/RUM/DataModels/RUMDataModelsMapping.swift @@ -57,3 +57,23 @@ internal extension RUMViewEvent.Source { } } } + +internal extension RUMViewEvent { + /// Metadata associated with the `RUMViewEvent`. + /// It may be used to filter out the `RUMViewEvent` from the batch. + struct Metadata: Codable { + let id: String + let documentVersion: Int64 + + private enum CodingKeys: String, CodingKey { + case id = "id" + case documentVersion = "document_version" + } + } + + /// Creates `Metadata` from the given `RUMViewEvent`. + /// - Returns: The `Metadata` for the given `RUMViewEvent`. + func metadata() -> Metadata { + return Metadata(id: view.id, documentVersion: dd.documentVersion) + } +} From 743e7ef09f4c6f5a13e7e777874288b2870222c5 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Tue, 27 Jun 2023 15:21:49 +0200 Subject: [PATCH 12/87] RUMM-3151 atomic writes --- .../DatadogCore/Storage/Writing/FileWriter.swift | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift b/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift index 520ccc4a57..e7c9c617f1 100644 --- a/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift +++ b/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift @@ -27,23 +27,18 @@ internal struct FileWriter: Writer { /// - metadata: Encodable metadata to write. func write(value: T, metadata: M?) { do { - let encodedValue = try encode(encodable: value, blockType: .event) - let encodedMetadata: Data? + var encoded = try encode(encodable: value, blockType: .event) if let metadata = metadata { - encodedMetadata = try encode(encodable: metadata, blockType: .eventMetadata) - } else { - encodedMetadata = nil + let encodedMetadata = try encode(encodable: metadata, blockType: .eventMetadata) + encoded.append(encodedMetadata) } // Make sure both event and event metadata are written to the same file. // This is to avoid a situation where event is written to one file and event metadata to another. // If this happens, the reader will not be able to match event with its metadata. - let writeSize = UInt64(encodedValue.count + (encodedMetadata?.count ?? 0)) + let writeSize = UInt64(encoded.count) let file = try forceNewFile ? orchestrator.getNewWritableFile(writeSize: writeSize) : orchestrator.getWritableFile(writeSize: writeSize) - try file.append(data: encodedValue) - if let encodedMetadata = encodedMetadata { - try file.append(data: encodedMetadata) - } + try file.append(data: encoded) } catch { DD.logger.error("Failed to write data", error: error) DD.telemetry.error("Failed to write data to file", error: error) From 769db023d72375668cafd37af77cfc9699de0d02 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Tue, 27 Jun 2023 15:22:11 +0200 Subject: [PATCH 13/87] RUMM-3151 remove EventFilter protocol --- Sources/Datadog/DatadogInternal/Upload/Event.swift | 9 --------- Sources/Datadog/RUM/RUMV2Configuration.swift | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/Sources/Datadog/DatadogInternal/Upload/Event.swift b/Sources/Datadog/DatadogInternal/Upload/Event.swift index 87d53c5197..b239c46002 100644 --- a/Sources/Datadog/DatadogInternal/Upload/Event.swift +++ b/Sources/Datadog/DatadogInternal/Upload/Event.swift @@ -6,15 +6,6 @@ import Foundation -/// Interface that allows filtering of the events before they are sent -/// to the server. -public protocol EventsFilter { - /// Filters the events. - /// - Parameter events: The events to be filtered. - /// - Returns: The filtered events. - func filter(events: [Event]) -> [Event] -} - /// Struct representing a single event. public struct Event: Equatable { /// Data representing the event. diff --git a/Sources/Datadog/RUM/RUMV2Configuration.swift b/Sources/Datadog/RUM/RUMV2Configuration.swift index 29d25f1d11..184231f1e4 100644 --- a/Sources/Datadog/RUM/RUMV2Configuration.swift +++ b/Sources/Datadog/RUM/RUMV2Configuration.swift @@ -33,7 +33,7 @@ internal func createRUMConfiguration(configuration: FeaturesConfiguration.RUM) - ) } -internal struct RUMViewEventsFilter: EventsFilter { +internal struct RUMViewEventsFilter { let decoder: JSONDecoder init(decoder: JSONDecoder = JSONDecoder()) { @@ -78,7 +78,7 @@ internal struct RUMRequestBuilder: FeatureRequestBuilder { /// The RUM request body format. let format = DataFormat(prefix: "", suffix: "", separator: "\n") - let eventsFilter: EventsFilter + let eventsFilter: RUMViewEventsFilter func request(for events: [Event], with context: DatadogContext) -> URLRequest { var tags = [ From 5faf9a984db6f7a760baf2c66c7e5cb91eb8590b Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Tue, 27 Jun 2023 15:41:03 +0200 Subject: [PATCH 14/87] RUMM-3151 encryption test case --- .../Persistence/Writing/FileWriterTests.swift | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift b/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift index 2c1c365333..e331aebe20 100644 --- a/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift +++ b/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift @@ -55,6 +55,46 @@ class FileWriterTests: XCTestCase { XCTAssertEqual(block?.data, #"{"meta3":"metaValue3"}"#.utf8Data) } + func testItWritesEncryptedDataWithMetadataToSingleFileInTLVFormat() throws { + let writer = FileWriter( + orchestrator: FilesOrchestrator( + directory: temporaryDirectory, + performance: PerformancePreset.mockAny(), + dateProvider: SystemDateProvider() + ), + encryption: DataEncryptionMock( + encrypt: { data in + "encrypted".utf8Data + data + "encrypted".utf8Data + } + ), + forceNewFile: false + ) + + writer.write(value: ["key1": "value1"], metadata: ["meta1": "metaValue1"]) + writer.write(value: ["key2": "value2"]) // skipped metadata here + writer.write(value: ["key3": "value3"], metadata: ["meta3": "metaValue3"]) + + XCTAssertEqual(try temporaryDirectory.files().count, 1) + let stream = try temporaryDirectory.files()[0].stream() + + let reader = DataBlockReader(input: stream) + var block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, #"encrypted{"key1":"value1"}encrypted"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .eventMetadata) + XCTAssertEqual(block?.data, #"encrypted{"meta1":"metaValue1"}encrypted"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, #"encrypted{"key2":"value2"}encrypted"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, #"encrypted{"key3":"value3"}encrypted"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .eventMetadata) + XCTAssertEqual(block?.data, #"encrypted{"meta3":"metaValue3"}encrypted"#.utf8Data) + } + func testItWritesDataToSingleFileInTLVFormat() throws { let writer = FileWriter( orchestrator: FilesOrchestrator( From 1847044af975f7578c8b05472501757f4d39c963 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Wed, 28 Jun 2023 13:01:05 +0200 Subject: [PATCH 15/87] RUMM-3151 one log per event --- Sources/Datadog/RUM/RUMV2Configuration.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/Datadog/RUM/RUMV2Configuration.swift b/Sources/Datadog/RUM/RUMV2Configuration.swift index 184231f1e4..27a77e7091 100644 --- a/Sources/Datadog/RUM/RUMV2Configuration.swift +++ b/Sources/Datadog/RUM/RUMV2Configuration.swift @@ -42,6 +42,7 @@ internal struct RUMViewEventsFilter { func filter(events: [Event]) -> [Event] { var seen = Set() + var skipped: [String: [Int64]] = [:] // reversed is O(1) and no copy because it is view on the original array let filtered = events.reversed().compactMap { event in @@ -57,7 +58,7 @@ internal struct RUMViewEventsFilter { guard seen.contains(viewMetadata.id) == false else { // If we've already seen this view, we can skip this - DD.logger.debug("Skipping RUMViewEvent with id: \(viewMetadata.id)") + skipped[viewMetadata.id]?.append(viewMetadata.documentVersion) return nil } @@ -65,6 +66,10 @@ internal struct RUMViewEventsFilter { return event } + for (id, versions) in skipped { + DD.logger.debug("Skipping RUMViewEvent with id: \(id) and versions: \(versions)") + } + return filtered.reversed() } } From 502fd11a500c739f6cd0ed033f222bb8147b5319 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Wed, 28 Jun 2023 13:40:12 +0200 Subject: [PATCH 16/87] RUMM-3151 adapt test to consider data and metadata --- .../Persistence/Writing/FileWriterTests.swift | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift b/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift index e331aebe20..1a027f924f 100644 --- a/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift +++ b/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift @@ -268,13 +268,20 @@ class FileWriterTests: XCTestCase { ioInterruptionQueue.async { try? file?.makeReadWrite() } } - struct Foo: Codable { + struct Foo: Codable, Equatable { var foo = "bar" } + struct Metadata: Codable, Equatable { + var meta = "data" + } + + let foo = Foo() + let metadata = Metadata() + // Write 300 of `Foo`s and interrupt writes randomly (0..<300).forEach { _ in - writer.write(value: Foo()) + writer.write(value: foo, metadata: metadata) randomlyInterruptIO(for: try? temporaryDirectory.files().first) } @@ -287,11 +294,20 @@ class FileWriterTests: XCTestCase { // Assert that data written is not malformed let jsonDecoder = JSONDecoder() - let events = try blocks.map { try jsonDecoder.decode(Foo.self, from: $0.data) } + let eventGenerator = try EventGenerator(dataBlocks: blocks) + let events = eventGenerator.map { $0 } // Assert that some (including all) `Foo`s were written XCTAssertGreaterThan(events.count, 0) XCTAssertLessThanOrEqual(events.count, 300) + for event in events { + let actualFoo = try jsonDecoder.decode(Foo.self, from: event.data) + XCTAssertEqual(actualFoo, foo) + + XCTAssertNotNil(event.metadata) + let actualMetadata = try jsonDecoder.decode(Metadata.self, from: event.metadata!) + XCTAssertEqual(actualMetadata, metadata) + } } func testItWritesEncryptedDataToSingleFile() throws { From 7bdf31df1a8c5cdedc2244a890a80db44e5548f5 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Wed, 28 Jun 2023 14:18:11 +0200 Subject: [PATCH 17/87] RUMM-3151 fix logging --- Sources/Datadog/RUM/RUMV2Configuration.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/Datadog/RUM/RUMV2Configuration.swift b/Sources/Datadog/RUM/RUMV2Configuration.swift index 27a77e7091..0aa20e4517 100644 --- a/Sources/Datadog/RUM/RUMV2Configuration.swift +++ b/Sources/Datadog/RUM/RUMV2Configuration.swift @@ -58,6 +58,9 @@ internal struct RUMViewEventsFilter { guard seen.contains(viewMetadata.id) == false else { // If we've already seen this view, we can skip this + if skipped[viewMetadata.id] == nil { + skipped[viewMetadata.id] = [] + } skipped[viewMetadata.id]?.append(viewMetadata.documentVersion) return nil } @@ -67,7 +70,7 @@ internal struct RUMViewEventsFilter { } for (id, versions) in skipped { - DD.logger.debug("Skipping RUMViewEvent with id: \(id) and versions: \(versions)") + DD.logger.debug("Skipping RUMViewEvent with id: \(id) and versions: \(versions.reversed().map(String.init).joined(separator: ", "))") } return filtered.reversed() From 3efffcdca8ca10149947afd0619f3a2318135119 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Wed, 28 Jun 2023 16:57:56 +0200 Subject: [PATCH 18/87] docs: add spi configuration --- .spi.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .spi.yml diff --git a/.spi.yml b/.spi.yml new file mode 100644 index 0000000000..f59b5814df --- /dev/null +++ b/.spi.yml @@ -0,0 +1,5 @@ +version: 1 +builder: + configs: + - platform: ios + documentation_targets: ["Datadog", "DatadogObjc", "DatadogCrashReporting"] \ No newline at end of file From 4e85aeef9d4dd977943408867e98382203cfe9c1 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Wed, 28 Jun 2023 17:13:19 +0100 Subject: [PATCH 19/87] Regenerate rum model --- .../RUM/DataModels/RUMDataModels.swift | 300 +++++++++++++++--- .../Integrations/CrashReportReceiver.swift | 9 +- .../RUM/RUMEvent/RUMOperatingSystemInfo.swift | 1 + .../RUM/RUMMonitor/Scopes/RUMViewScope.swift | 6 +- .../DatadogObjc/RUM/RUMDataModels+objc.swift | 262 +++++++++++++-- .../CodeDecoration/RUMCodeDecorator.swift | 1 - .../CodeGeneration/Generate/JSONSchema.swift | 26 ++ .../JSONSchemaToJSONTypeTransformer.swift | 10 +- ...JSONSchemaToJSONTypeTransformerTests.swift | 4 + 9 files changed, 534 insertions(+), 85 deletions(-) diff --git a/Sources/Datadog/RUM/DataModels/RUMDataModels.swift b/Sources/Datadog/RUM/DataModels/RUMDataModels.swift index db44f7b0ca..494dcff394 100644 --- a/Sources/Datadog/RUM/DataModels/RUMDataModels.swift +++ b/Sources/Datadog/RUM/DataModels/RUMDataModels.swift @@ -154,14 +154,14 @@ public struct RUMActionEvent: RUMDataModel { /// Session-related internal properties public struct Session: Codable { - /// Session plan: 1 is the plan without replay, 2 is the plan with replay - public let plan: Plan + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) + public let plan: Plan? enum CodingKeys: String, CodingKey { case plan = "plan" } - /// Session plan: 1 is the plan without replay, 2 is the plan with replay + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) public enum Plan: Int, Codable { case plan1 = 1 case plan2 = 2 @@ -300,6 +300,30 @@ public struct RUMActionEvent: RUMDataModel { } } + /// Display properties + public struct RUMDisplay: Codable { + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public let viewport: Viewport? + + enum CodingKeys: String, CodingKey { + case viewport = "viewport" + } + + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public struct Viewport: Codable { + /// Height of the viewport (in pixels) + public let height: Double + + /// Width of the viewport (in pixels) + public let width: Double + + enum CodingKeys: String, CodingKey { + case height = "height" + case width = "width" + } + } + } + /// Session properties public struct Session: Codable { /// Whether this session has a replay @@ -484,14 +508,14 @@ public struct RUMErrorEvent: RUMDataModel { /// Session-related internal properties public struct Session: Codable { - /// Session plan: 1 is the plan without replay, 2 is the plan with replay - public let plan: Plan + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) + public let plan: Plan? enum CodingKeys: String, CodingKey { case plan = "plan" } - /// Session plan: 1 is the plan without replay, 2 is the plan with replay + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) public enum Plan: Int, Codable { case plan1 = 1 case plan2 = 2 @@ -519,11 +543,38 @@ public struct RUMErrorEvent: RUMDataModel { } } + /// Display properties + public struct RUMDisplay: Codable { + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public let viewport: Viewport? + + enum CodingKeys: String, CodingKey { + case viewport = "viewport" + } + + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public struct Viewport: Codable { + /// Height of the viewport (in pixels) + public let height: Double + + /// Width of the viewport (in pixels) + public let width: Double + + enum CodingKeys: String, CodingKey { + case height = "height" + case width = "width" + } + } + } + /// Error properties public struct Error: Codable { /// Causes of the error public var causes: [Causes]? + /// Fingerprint used for Error Tracking custom grouping + public var fingerprint: String? + /// Whether the error has been handled manually in the source code or not public let handling: Handling? @@ -556,6 +607,7 @@ public struct RUMErrorEvent: RUMDataModel { enum CodingKeys: String, CodingKey { case causes = "causes" + case fingerprint = "fingerprint" case handling = "handling" case handlingStack = "handling_stack" case id = "id" @@ -902,14 +954,14 @@ public struct RUMLongTaskEvent: RUMDataModel { /// Session-related internal properties public struct Session: Codable { - /// Session plan: 1 is the plan without replay, 2 is the plan with replay - public let plan: Plan + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) + public let plan: Plan? enum CodingKeys: String, CodingKey { case plan = "plan" } - /// Session plan: 1 is the plan without replay, 2 is the plan with replay + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) public enum Plan: Int, Codable { case plan1 = 1 case plan2 = 2 @@ -937,6 +989,30 @@ public struct RUMLongTaskEvent: RUMDataModel { } } + /// Display properties + public struct RUMDisplay: Codable { + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public let viewport: Viewport? + + enum CodingKeys: String, CodingKey { + case viewport = "viewport" + } + + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public struct Viewport: Codable { + /// Height of the viewport (in pixels) + public let height: Double + + /// Width of the viewport (in pixels) + public let width: Double + + enum CodingKeys: String, CodingKey { + case height = "height" + case width = "width" + } + } + } + /// Long Task properties public struct LongTask: Codable { /// Duration in ns of the long task @@ -1147,14 +1223,14 @@ public struct RUMResourceEvent: RUMDataModel { /// Session-related internal properties public struct Session: Codable { - /// Session plan: 1 is the plan without replay, 2 is the plan with replay - public let plan: Plan + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) + public let plan: Plan? enum CodingKeys: String, CodingKey { case plan = "plan" } - /// Session plan: 1 is the plan without replay, 2 is the plan with replay + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) public enum Plan: Int, Codable { case plan1 = 1 case plan2 = 2 @@ -1182,6 +1258,30 @@ public struct RUMResourceEvent: RUMDataModel { } } + /// Display properties + public struct RUMDisplay: Codable { + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public let viewport: Viewport? + + enum CodingKeys: String, CodingKey { + case viewport = "viewport" + } + + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public struct Viewport: Codable { + /// Height of the viewport (in pixels) + public let height: Double + + /// Width of the viewport (in pixels) + public let width: Double + + enum CodingKeys: String, CodingKey { + case height = "height" + case width = "width" + } + } + } + /// Resource properties public struct Resource: Codable { /// Connect phase properties @@ -1194,7 +1294,7 @@ public struct RUMResourceEvent: RUMDataModel { public let download: Download? /// Duration of the resource - public let duration: Int64 + public let duration: Int64? /// First Byte phase properties public let firstByte: FirstByte? @@ -1487,6 +1587,9 @@ public struct RUMViewEvent: RUMDataModel { /// Operating system properties public let os: RUMOperatingSystem? + /// Privacy properties + public let privacy: Privacy? + /// The service name for this application public let service: String? @@ -1522,6 +1625,7 @@ public struct RUMViewEvent: RUMDataModel { case display = "display" case featureFlags = "feature_flags" case os = "os" + case privacy = "privacy" case service = "service" case session = "session" case source = "source" @@ -1543,6 +1647,12 @@ public struct RUMViewEvent: RUMDataModel { /// Version of the RUM event format public let formatVersion: Int64 = 2 + /// List of the page states during the view + public let pageStates: [PageStates]? + + /// Debug metadata for Replay Sessions + public let replayStats: ReplayStats? + /// Session-related internal properties public let session: Session? @@ -1550,19 +1660,62 @@ public struct RUMViewEvent: RUMDataModel { case browserSdkVersion = "browser_sdk_version" case documentVersion = "document_version" case formatVersion = "format_version" + case pageStates = "page_states" + case replayStats = "replay_stats" case session = "session" } + /// Properties of the page state + public struct PageStates: Codable { + /// Duration in ns between start of the view and start of the page state + public let start: Int64 + + /// Page state name + public let state: State + + enum CodingKeys: String, CodingKey { + case start = "start" + case state = "state" + } + + /// Page state name + public enum State: String, Codable { + case active = "active" + case passive = "passive" + case hidden = "hidden" + case frozen = "frozen" + case terminated = "terminated" + } + } + + /// Debug metadata for Replay Sessions + public struct ReplayStats: Codable { + /// The number of records produced during this view lifetime + public let recordsCount: Int64? + + /// The number of segments sent during this view lifetime + public let segmentsCount: Int64? + + /// The total size in bytes of the segments sent during this view lifetime + public let segmentsTotalRawSize: Int64? + + enum CodingKeys: String, CodingKey { + case recordsCount = "records_count" + case segmentsCount = "segments_count" + case segmentsTotalRawSize = "segments_total_raw_size" + } + } + /// Session-related internal properties public struct Session: Codable { - /// Session plan: 1 is the plan without replay, 2 is the plan with replay - public let plan: Plan + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) + public let plan: Plan? enum CodingKeys: String, CodingKey { case plan = "plan" } - /// Session plan: 1 is the plan without replay, 2 is the plan with replay + /// Session plan: 1 is the plan without replay, 2 is the plan with replay (deprecated) public enum Plan: Int, Codable { case plan1 = 1 case plan2 = 2 @@ -1580,11 +1733,78 @@ public struct RUMViewEvent: RUMDataModel { } } + /// Display properties + public struct RUMDisplay: Codable { + /// Scroll properties + public let scroll: Scroll? + + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public let viewport: Viewport? + + enum CodingKeys: String, CodingKey { + case scroll = "scroll" + case viewport = "viewport" + } + + /// Scroll properties + public struct Scroll: Codable { + /// Distance between the top and the lowest point reached on this view (in pixels) + public let maxDepth: Double + + /// Page scroll height (total height) when the maximum scroll depth was reached for this view (in pixels) + public let maxDepthScrollHeight: Double + + /// Page scroll top (scrolled distance) when the maximum scroll depth was reached for this view (in pixels) + public let maxDepthScrollTop: Double + + /// Duration between the view start and the scroll event that reached the maximum scroll depth for this view (in nanoseconds) + public let maxDepthTime: Double + + enum CodingKeys: String, CodingKey { + case maxDepth = "max_depth" + case maxDepthScrollHeight = "max_depth_scroll_height" + case maxDepthScrollTop = "max_depth_scroll_top" + case maxDepthTime = "max_depth_time" + } + } + + /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. + public struct Viewport: Codable { + /// Height of the viewport (in pixels) + public let height: Double + + /// Width of the viewport (in pixels) + public let width: Double + + enum CodingKeys: String, CodingKey { + case height = "height" + case width = "width" + } + } + } + /// Feature flags properties public struct FeatureFlags: Codable { public internal(set) var featureFlagsInfo: [String: Encodable] } + /// Privacy properties + public struct Privacy: Codable { + /// The replay privacy level + public let replayLevel: ReplayLevel + + enum CodingKeys: String, CodingKey { + case replayLevel = "replay_level" + } + + /// The replay privacy level + public enum ReplayLevel: String, Codable { + case allow = "allow" + case mask = "mask" + case maskUserInput = "mask-user-input" + } + } + /// Session properties public struct Session: Codable { /// Whether this session has a replay @@ -1596,8 +1816,11 @@ public struct RUMViewEvent: RUMDataModel { /// Whether this session is currently active. Set to false to manually stop a session public let isActive: Bool? + /// Whether this session has been sampled for replay + public let sampledForReplay: Bool? + /// The precondition that led to the creation of the session - public let startReason: StartReason? + public let startPrecondition: StartPrecondition? /// Type of the session public let type: SessionType @@ -1606,16 +1829,17 @@ public struct RUMViewEvent: RUMDataModel { case hasReplay = "has_replay" case id = "id" case isActive = "is_active" - case startReason = "start_reason" + case sampledForReplay = "sampled_for_replay" + case startPrecondition = "start_precondition" case type = "type" } /// The precondition that led to the creation of the session - public enum StartReason: String, Codable { - case appStart = "app_start" + public enum StartPrecondition: String, Codable { + case appLaunch = "app_launch" case inactivityTimeout = "inactivity_timeout" case maxDuration = "max_duration" - case stopApi = "stop_api" + case explicitStop = "explicit_stop" case backgroundEvent = "background_event" } @@ -2447,6 +2671,9 @@ public struct TelemetryConfigurationEvent: RUMDataModel { /// Whether initialization fails silently if the SDK is already initialized public let silentMultipleInit: Bool? + /// Whether the session replay start is handled manually + public var startSessionReplayRecordingManually: Bool? + /// The percentage of telemetry configuration events sent after being sampled by telemetry_sample_rate public let telemetryConfigurationSampleRate: Int64? @@ -2553,6 +2780,7 @@ public struct TelemetryConfigurationEvent: RUMDataModel { case sessionReplaySampleRate = "session_replay_sample_rate" case sessionSampleRate = "session_sample_rate" case silentMultipleInit = "silent_multiple_init" + case startSessionReplayRecordingManually = "start_session_replay_recording_manually" case telemetryConfigurationSampleRate = "telemetry_configuration_sample_rate" case telemetrySampleRate = "telemetry_sample_rate" case traceSampleRate = "trace_sample_rate" @@ -2823,32 +3051,11 @@ public struct RUMDevice: Codable { } } -/// Display properties -public struct RUMDisplay: Codable { - /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. - public let viewport: Viewport? - - enum CodingKeys: String, CodingKey { - case viewport = "viewport" - } - - /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. - public struct Viewport: Codable { - /// Height of the viewport (in pixels) - public let height: Double - - /// Width of the viewport (in pixels) - public let width: Double - - enum CodingKeys: String, CodingKey { - case height = "height" - case width = "width" - } - } -} - /// Operating system properties public struct RUMOperatingSystem: Codable { + /// Operating system build number, e.g. 15D21 + public let build: String? + /// Operating system name, e.g. Android, iOS public let name: String @@ -2859,6 +3066,7 @@ public struct RUMOperatingSystem: Codable { public let versionMajor: String enum CodingKeys: String, CodingKey { + case build = "build" case name = "name" case version = "version" case versionMajor = "version_major" @@ -2974,4 +3182,4 @@ public enum RUMMethod: String, Codable { case patch = "PATCH" } -// Generated from https://github.com/DataDog/rum-events-format/tree/a45fbc913eb36f3bf0cc37aa1bdbee126104972b +// Generated from https://github.com/DataDog/rum-events-format/tree/dcb6897cf883fb8938e7aa0f69ed9a035df98c2c diff --git a/Sources/Datadog/RUM/Integrations/CrashReportReceiver.swift b/Sources/Datadog/RUM/Integrations/CrashReportReceiver.swift index 2272569653..1907baf083 100644 --- a/Sources/Datadog/RUM/Integrations/CrashReportReceiver.swift +++ b/Sources/Datadog/RUM/Integrations/CrashReportReceiver.swift @@ -373,6 +373,8 @@ internal struct CrashReportReceiver: FeatureMessageReceiver { dd: .init( browserSdkVersion: nil, documentVersion: original.dd.documentVersion + 1, + pageStates: nil, + replayStats: nil, session: .init(plan: .plan1) ), application: original.application, @@ -383,6 +385,7 @@ internal struct CrashReportReceiver: FeatureMessageReceiver { device: original.device, display: nil, os: original.os, + privacy: nil, service: original.service, session: original.session, source: original.source ?? .ios, @@ -446,6 +449,8 @@ internal struct CrashReportReceiver: FeatureMessageReceiver { dd: .init( browserSdkVersion: nil, documentVersion: 1, + pageStates: nil, + replayStats: nil, session: .init(plan: .plan1) ), application: .init( @@ -465,12 +470,14 @@ internal struct CrashReportReceiver: FeatureMessageReceiver { // before restarting the app after crash. To solve this, the OS information would have to be // persisted in `crashContext` the same way as we do for other dynamic information. os: .init(device: context.device), + privacy: nil, service: context.service, session: .init( hasReplay: hasReplay, id: sessionUUID.toRUMDataFormat, isActive: true, - startReason: nil, + sampledForReplay: nil, + startPrecondition: nil, type: CITestIntegration.active != nil ? .ciTest : .user ), source: .init(rawValue: context.source) ?? .ios, diff --git a/Sources/Datadog/RUM/RUMEvent/RUMOperatingSystemInfo.swift b/Sources/Datadog/RUM/RUMEvent/RUMOperatingSystemInfo.swift index 59bed57c28..0d9503f8de 100644 --- a/Sources/Datadog/RUM/RUMEvent/RUMOperatingSystemInfo.swift +++ b/Sources/Datadog/RUM/RUMEvent/RUMOperatingSystemInfo.swift @@ -15,5 +15,6 @@ extension RUMOperatingSystem { self.name = device.osName self.version = device.osVersion self.versionMajor = device.osVersion.split(separator: ".").first.map { String($0) } ?? device.osVersion + self.build = nil } } diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift index 864cde834b..0326b40d6f 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift @@ -441,6 +441,8 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { dd: .init( browserSdkVersion: nil, documentVersion: version.toInt64, + pageStates: nil, + replayStats: nil, session: .init(plan: .plan1) ), application: .init(id: self.context.rumApplicationID), @@ -452,12 +454,14 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { display: nil, featureFlags: .init(featureFlagsInfo: featureFlags), os: .init(context: context), + privacy: nil, service: context.service, session: .init( hasReplay: context.srBaggage?.isReplayBeingRecorded, id: self.context.sessionID.toRUMDataFormat, isActive: self.context.isSessionActive, - startReason: nil, + sampledForReplay: nil, + startPrecondition: nil, type: dependencies.ciTest != nil ? .ciTest : .user ), source: .init(rawValue: context.source) ?? .ios, diff --git a/Sources/DatadogObjc/RUM/RUMDataModels+objc.swift b/Sources/DatadogObjc/RUM/RUMDataModels+objc.swift index 1b41e5bee6..045afe08cf 100644 --- a/Sources/DatadogObjc/RUM/RUMDataModels+objc.swift +++ b/Sources/DatadogObjc/RUM/RUMDataModels+objc.swift @@ -188,20 +188,23 @@ public class DDRUMActionEventDDSession: NSObject { @objc public enum DDRUMActionEventDDSessionPlan: Int { - internal init(swift: RUMActionEvent.DD.Session.Plan) { + internal init(swift: RUMActionEvent.DD.Session.Plan?) { switch swift { - case .plan1: self = .plan1 - case .plan2: self = .plan2 + case nil: self = .none + case .plan1?: self = .plan1 + case .plan2?: self = .plan2 } } - internal var toSwift: RUMActionEvent.DD.Session.Plan { + internal var toSwift: RUMActionEvent.DD.Session.Plan? { switch self { + case .none: return nil case .plan1: return .plan1 case .plan2: return .plan2 } } + case none case plan1 case plan2 } @@ -637,6 +640,10 @@ public class DDRUMActionEventRUMOperatingSystem: NSObject { self.root = root } + @objc public var build: String? { + root.swiftModel.os!.build + } + @objc public var name: String { root.swiftModel.os!.name } @@ -933,20 +940,23 @@ public class DDRUMErrorEventDDSession: NSObject { @objc public enum DDRUMErrorEventDDSessionPlan: Int { - internal init(swift: RUMErrorEvent.DD.Session.Plan) { + internal init(swift: RUMErrorEvent.DD.Session.Plan?) { switch swift { - case .plan1: self = .plan1 - case .plan2: self = .plan2 + case nil: self = .none + case .plan1?: self = .plan1 + case .plan2?: self = .plan2 } } - internal var toSwift: RUMErrorEvent.DD.Session.Plan { + internal var toSwift: RUMErrorEvent.DD.Session.Plan? { switch self { + case .none: return nil case .plan1: return .plan1 case .plan2: return .plan2 } } + case none case plan1 case plan2 } @@ -1235,6 +1245,11 @@ public class DDRUMErrorEventError: NSObject { get { root.swiftModel.error.causes?.map { DDRUMErrorEventErrorCauses(swiftModel: $0) } } } + @objc public var fingerprint: String? { + set { root.swiftModel.error.fingerprint = newValue } + get { root.swiftModel.error.fingerprint } + } + @objc public var handling: DDRUMErrorEventErrorHandling { .init(swift: root.swiftModel.error.handling) } @@ -1599,6 +1614,10 @@ public class DDRUMErrorEventRUMOperatingSystem: NSObject { self.root = root } + @objc public var build: String? { + root.swiftModel.os!.build + } + @objc public var name: String { root.swiftModel.os!.name } @@ -1895,20 +1914,23 @@ public class DDRUMLongTaskEventDDSession: NSObject { @objc public enum DDRUMLongTaskEventDDSessionPlan: Int { - internal init(swift: RUMLongTaskEvent.DD.Session.Plan) { + internal init(swift: RUMLongTaskEvent.DD.Session.Plan?) { switch swift { - case .plan1: self = .plan1 - case .plan2: self = .plan2 + case nil: self = .none + case .plan1?: self = .plan1 + case .plan2?: self = .plan2 } } - internal var toSwift: RUMLongTaskEvent.DD.Session.Plan { + internal var toSwift: RUMLongTaskEvent.DD.Session.Plan? { switch self { + case .none: return nil case .plan1: return .plan1 case .plan2: return .plan2 } } + case none case plan1 case plan2 } @@ -2213,6 +2235,10 @@ public class DDRUMLongTaskEventRUMOperatingSystem: NSObject { self.root = root } + @objc public var build: String? { + root.swiftModel.os!.build + } + @objc public var name: String { root.swiftModel.os!.name } @@ -2517,20 +2543,23 @@ public class DDRUMResourceEventDDSession: NSObject { @objc public enum DDRUMResourceEventDDSessionPlan: Int { - internal init(swift: RUMResourceEvent.DD.Session.Plan) { + internal init(swift: RUMResourceEvent.DD.Session.Plan?) { switch swift { - case .plan1: self = .plan1 - case .plan2: self = .plan2 + case nil: self = .none + case .plan1?: self = .plan1 + case .plan2?: self = .plan2 } } - internal var toSwift: RUMResourceEvent.DD.Session.Plan { + internal var toSwift: RUMResourceEvent.DD.Session.Plan? { switch self { + case .none: return nil case .plan1: return .plan1 case .plan2: return .plan2 } } + case none case plan1 case plan2 } @@ -2814,6 +2843,10 @@ public class DDRUMResourceEventRUMOperatingSystem: NSObject { self.root = root } + @objc public var build: String? { + root.swiftModel.os!.build + } + @objc public var name: String { root.swiftModel.os!.name } @@ -2847,8 +2880,8 @@ public class DDRUMResourceEventResource: NSObject { root.swiftModel.resource.download != nil ? DDRUMResourceEventResourceDownload(root: root) : nil } - @objc public var duration: NSNumber { - root.swiftModel.resource.duration as NSNumber + @objc public var duration: NSNumber? { + root.swiftModel.resource.duration as NSNumber? } @objc public var firstByte: DDRUMResourceEventResourceFirstByte? { @@ -3359,6 +3392,10 @@ public class DDRUMViewEvent: NSObject { root.swiftModel.os != nil ? DDRUMViewEventRUMOperatingSystem(root: root) : nil } + @objc public var privacy: DDRUMViewEventPrivacy? { + root.swiftModel.privacy != nil ? DDRUMViewEventPrivacy(root: root) : nil + } + @objc public var service: String? { root.swiftModel.service } @@ -3412,11 +3449,87 @@ public class DDRUMViewEventDD: NSObject { root.swiftModel.dd.formatVersion as NSNumber } + @objc public var pageStates: [DDRUMViewEventDDPageStates]? { + root.swiftModel.dd.pageStates?.map { DDRUMViewEventDDPageStates(swiftModel: $0) } + } + + @objc public var replayStats: DDRUMViewEventDDReplayStats? { + root.swiftModel.dd.replayStats != nil ? DDRUMViewEventDDReplayStats(root: root) : nil + } + @objc public var session: DDRUMViewEventDDSession? { root.swiftModel.dd.session != nil ? DDRUMViewEventDDSession(root: root) : nil } } +@objc +public class DDRUMViewEventDDPageStates: NSObject { + internal var swiftModel: RUMViewEvent.DD.PageStates + internal var root: DDRUMViewEventDDPageStates { self } + + internal init(swiftModel: RUMViewEvent.DD.PageStates) { + self.swiftModel = swiftModel + } + + @objc public var start: NSNumber { + root.swiftModel.start as NSNumber + } + + @objc public var state: DDRUMViewEventDDPageStatesState { + .init(swift: root.swiftModel.state) + } +} + +@objc +public enum DDRUMViewEventDDPageStatesState: Int { + internal init(swift: RUMViewEvent.DD.PageStates.State) { + switch swift { + case .active: self = .active + case .passive: self = .passive + case .hidden: self = .hidden + case .frozen: self = .frozen + case .terminated: self = .terminated + } + } + + internal var toSwift: RUMViewEvent.DD.PageStates.State { + switch self { + case .active: return .active + case .passive: return .passive + case .hidden: return .hidden + case .frozen: return .frozen + case .terminated: return .terminated + } + } + + case active + case passive + case hidden + case frozen + case terminated +} + +@objc +public class DDRUMViewEventDDReplayStats: NSObject { + internal let root: DDRUMViewEvent + + internal init(root: DDRUMViewEvent) { + self.root = root + } + + @objc public var recordsCount: NSNumber? { + root.swiftModel.dd.replayStats!.recordsCount as NSNumber? + } + + @objc public var segmentsCount: NSNumber? { + root.swiftModel.dd.replayStats!.segmentsCount as NSNumber? + } + + @objc public var segmentsTotalRawSize: NSNumber? { + root.swiftModel.dd.replayStats!.segmentsTotalRawSize as NSNumber? + } +} + @objc public class DDRUMViewEventDDSession: NSObject { internal let root: DDRUMViewEvent @@ -3432,20 +3545,23 @@ public class DDRUMViewEventDDSession: NSObject { @objc public enum DDRUMViewEventDDSessionPlan: Int { - internal init(swift: RUMViewEvent.DD.Session.Plan) { + internal init(swift: RUMViewEvent.DD.Session.Plan?) { switch swift { - case .plan1: self = .plan1 - case .plan2: self = .plan2 + case nil: self = .none + case .plan1?: self = .plan1 + case .plan2?: self = .plan2 } } - internal var toSwift: RUMViewEvent.DD.Session.Plan { + internal var toSwift: RUMViewEvent.DD.Session.Plan? { switch self { + case .none: return nil case .plan1: return .plan1 case .plan2: return .plan2 } } + case none case plan1 case plan2 } @@ -3663,11 +3779,40 @@ public class DDRUMViewEventRUMDisplay: NSObject { self.root = root } + @objc public var scroll: DDRUMViewEventRUMDisplayScroll? { + root.swiftModel.display!.scroll != nil ? DDRUMViewEventRUMDisplayScroll(root: root) : nil + } + @objc public var viewport: DDRUMViewEventRUMDisplayViewport? { root.swiftModel.display!.viewport != nil ? DDRUMViewEventRUMDisplayViewport(root: root) : nil } } +@objc +public class DDRUMViewEventRUMDisplayScroll: NSObject { + internal let root: DDRUMViewEvent + + internal init(root: DDRUMViewEvent) { + self.root = root + } + + @objc public var maxDepth: NSNumber { + root.swiftModel.display!.scroll!.maxDepth as NSNumber + } + + @objc public var maxDepthScrollHeight: NSNumber { + root.swiftModel.display!.scroll!.maxDepthScrollHeight as NSNumber + } + + @objc public var maxDepthScrollTop: NSNumber { + root.swiftModel.display!.scroll!.maxDepthScrollTop as NSNumber + } + + @objc public var maxDepthTime: NSNumber { + root.swiftModel.display!.scroll!.maxDepthTime as NSNumber + } +} + @objc public class DDRUMViewEventRUMDisplayViewport: NSObject { internal let root: DDRUMViewEvent @@ -3706,6 +3851,10 @@ public class DDRUMViewEventRUMOperatingSystem: NSObject { self.root = root } + @objc public var build: String? { + root.swiftModel.os!.build + } + @objc public var name: String { root.swiftModel.os!.name } @@ -3719,6 +3868,42 @@ public class DDRUMViewEventRUMOperatingSystem: NSObject { } } +@objc +public class DDRUMViewEventPrivacy: NSObject { + internal let root: DDRUMViewEvent + + internal init(root: DDRUMViewEvent) { + self.root = root + } + + @objc public var replayLevel: DDRUMViewEventPrivacyReplayLevel { + .init(swift: root.swiftModel.privacy!.replayLevel) + } +} + +@objc +public enum DDRUMViewEventPrivacyReplayLevel: Int { + internal init(swift: RUMViewEvent.Privacy.ReplayLevel) { + switch swift { + case .allow: self = .allow + case .mask: self = .mask + case .maskUserInput: self = .maskUserInput + } + } + + internal var toSwift: RUMViewEvent.Privacy.ReplayLevel { + switch self { + case .allow: return .allow + case .mask: return .mask + case .maskUserInput: return .maskUserInput + } + } + + case allow + case mask + case maskUserInput +} + @objc public class DDRUMViewEventSession: NSObject { internal let root: DDRUMViewEvent @@ -3739,8 +3924,12 @@ public class DDRUMViewEventSession: NSObject { root.swiftModel.session.isActive as NSNumber? } - @objc public var startReason: DDRUMViewEventSessionStartReason { - .init(swift: root.swiftModel.session.startReason) + @objc public var sampledForReplay: NSNumber? { + root.swiftModel.session.sampledForReplay as NSNumber? + } + + @objc public var startPrecondition: DDRUMViewEventSessionStartPrecondition { + .init(swift: root.swiftModel.session.startPrecondition) } @objc public var type: DDRUMViewEventSessionSessionType { @@ -3749,34 +3938,34 @@ public class DDRUMViewEventSession: NSObject { } @objc -public enum DDRUMViewEventSessionStartReason: Int { - internal init(swift: RUMViewEvent.Session.StartReason?) { +public enum DDRUMViewEventSessionStartPrecondition: Int { + internal init(swift: RUMViewEvent.Session.StartPrecondition?) { switch swift { case nil: self = .none - case .appStart?: self = .appStart + case .appLaunch?: self = .appLaunch case .inactivityTimeout?: self = .inactivityTimeout case .maxDuration?: self = .maxDuration - case .stopApi?: self = .stopApi + case .explicitStop?: self = .explicitStop case .backgroundEvent?: self = .backgroundEvent } } - internal var toSwift: RUMViewEvent.Session.StartReason? { + internal var toSwift: RUMViewEvent.Session.StartPrecondition? { switch self { case .none: return nil - case .appStart: return .appStart + case .appLaunch: return .appLaunch case .inactivityTimeout: return .inactivityTimeout case .maxDuration: return .maxDuration - case .stopApi: return .stopApi + case .explicitStop: return .explicitStop case .backgroundEvent: return .backgroundEvent } } case none - case appStart + case appLaunch case inactivityTimeout case maxDuration - case stopApi + case explicitStop case backgroundEvent } @@ -4879,6 +5068,11 @@ public class DDTelemetryConfigurationEventTelemetryConfiguration: NSObject { root.swiftModel.telemetry.configuration.silentMultipleInit as NSNumber? } + @objc public var startSessionReplayRecordingManually: NSNumber? { + set { root.swiftModel.telemetry.configuration.startSessionReplayRecordingManually = newValue?.boolValue } + get { root.swiftModel.telemetry.configuration.startSessionReplayRecordingManually as NSNumber? } + } + @objc public var telemetryConfigurationSampleRate: NSNumber? { root.swiftModel.telemetry.configuration.telemetryConfigurationSampleRate as NSNumber? } @@ -5131,4 +5325,4 @@ public class DDTelemetryConfigurationEventView: NSObject { // swiftlint:enable force_unwrapping -// Generated from https://github.com/DataDog/rum-events-format/tree/a45fbc913eb36f3bf0cc37aa1bdbee126104972b +// Generated from https://github.com/DataDog/rum-events-format/tree/dcb6897cf883fb8938e7aa0f69ed9a035df98c2c diff --git a/tools/rum-models-generator/Sources/CodeDecoration/RUMCodeDecorator.swift b/tools/rum-models-generator/Sources/CodeDecoration/RUMCodeDecorator.swift index 381610826b..43f13ac021 100644 --- a/tools/rum-models-generator/Sources/CodeDecoration/RUMCodeDecorator.swift +++ b/tools/rum-models-generator/Sources/CodeDecoration/RUMCodeDecorator.swift @@ -22,7 +22,6 @@ public class RUMCodeDecorator: SwiftCodeDecorator { "RUMCITest", "RUMDevice", "RUMOperatingSystem", - "RUMDisplay", "RUMActionID", ] ) diff --git a/tools/rum-models-generator/Sources/CodeGeneration/Generate/JSONSchema.swift b/tools/rum-models-generator/Sources/CodeGeneration/Generate/JSONSchema.swift index e589d9848c..efddd5b759 100644 --- a/tools/rum-models-generator/Sources/CodeGeneration/Generate/JSONSchema.swift +++ b/tools/rum-models-generator/Sources/CodeGeneration/Generate/JSONSchema.swift @@ -288,3 +288,29 @@ internal class JSONSchema: Decodable { } } } + +extension Array where Element == JSONSchema.EnumValue { + func inferrSchemaType() -> JSONSchema.SchemaType? { + let hasOnlyStrings = allSatisfy { element in + if case .string = element { + return true + } + return false + } + if hasOnlyStrings { + return .string + } + + let hasOnlyIntegers = allSatisfy { element in + if case .integer = element { + return true + } + return false + } + if hasOnlyIntegers { + return .number + } + + return nil + } +} diff --git a/tools/rum-models-generator/Sources/CodeGeneration/Generate/Transformers/JSON/JSONSchemaToJSONTypeTransformer.swift b/tools/rum-models-generator/Sources/CodeGeneration/Generate/Transformers/JSON/JSONSchemaToJSONTypeTransformer.swift index e03be2f3f5..e248acfd82 100644 --- a/tools/rum-models-generator/Sources/CodeGeneration/Generate/Transformers/JSON/JSONSchemaToJSONTypeTransformer.swift +++ b/tools/rum-models-generator/Sources/CodeGeneration/Generate/Transformers/JSON/JSONSchemaToJSONTypeTransformer.swift @@ -35,8 +35,14 @@ internal class JSONSchemaToJSONTypeTransformer { return try transformSchemaToObject(schema, named: name) } - let schemaType = try schema.type - .unwrapOrThrow(.inconsistency("`JSONSchema` must define `type`: \(schema).")) + let schemaType: JSONSchema.SchemaType + if let enumarations = schema.enum, schema.type == nil { + schemaType = try enumarations.inferrSchemaType() + .unwrapOrThrow(.inconsistency("Heteregenous enum is not supported: \(enumarations).")) + } else { + schemaType = try schema.type + .unwrapOrThrow(.inconsistency("`JSONSchema` must define `type`: \(schema).")) + } switch schemaType { case .object: diff --git a/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift b/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift index 96e2b9825f..80a38f3ac6 100644 --- a/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift +++ b/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift @@ -215,4 +215,8 @@ final class JSONSchemaToJSONTypeTransformerTests: XCTestCase { let actual = try JSONSchemaToJSONTypeTransformer().transform(jsonSchema: jsonSchema) XCTAssertEqual(expected, actual as? JSONUnionType) } + + func test_enumTypeInferring() { + + } } From fabc19d78df3e89aca399f3942554b642708439e Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Thu, 29 Jun 2023 12:57:51 +0100 Subject: [PATCH 20/87] Add test --- .../fixture-schema-with-typeless-enum.json | 16 +++++++ ...JSONSchemaToJSONTypeTransformerTests.swift | 42 ++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 tools/rum-models-generator/Tests/CodeGenerationTests/Fixtures/fixture-schema-with-typeless-enum.json diff --git a/tools/rum-models-generator/Tests/CodeGenerationTests/Fixtures/fixture-schema-with-typeless-enum.json b/tools/rum-models-generator/Tests/CodeGenerationTests/Fixtures/fixture-schema-with-typeless-enum.json new file mode 100644 index 0000000000..0413fa6a7a --- /dev/null +++ b/tools/rum-models-generator/Tests/CodeGenerationTests/Fixtures/fixture-schema-with-typeless-enum.json @@ -0,0 +1,16 @@ +{ + "$id": "Schema ID", + "type": "object", + "title": "Schema title", + "description": "Schema description.", + "properties": { + "stringEnumProperty": { + "description": "Description of `stringEnumProperty` without explicit type.", + "enum": ["case1", "case2", "case3", "case4"] + }, + "integerEnumProperty": { + "description": "Description of `integerEnumProperty` without explicit type.", + "enum": [1, 2, 3, 4] + } + } +} diff --git a/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift b/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift index 80a38f3ac6..8c3028cce1 100644 --- a/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift +++ b/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift @@ -216,7 +216,45 @@ final class JSONSchemaToJSONTypeTransformerTests: XCTestCase { XCTAssertEqual(expected, actual as? JSONUnionType) } - func test_enumTypeInferring() { - + func testTransformingJSONSchemaWithNoExplicitEnumTypeIntoJSONObject() throws { + let expected = JSONObject( + name: "Schema title", + comment: "Schema description.", + properties: [ + JSONObject.Property( + name: "stringEnumProperty", + comment: "Description of `stringEnumProperty` without explicit type.", + type: JSONEnumeration( + name: "stringEnumProperty", + comment: "Description of `stringEnumProperty` without explicit type.", + values: [.string(value: "case1"), .string(value: "case2"), .string(value: "case3"), .string(value: "case4")] + ), + defaultValue: nil, + isRequired: false, + isReadOnly: true + ), + JSONObject.Property( + name: "integerEnumProperty", + comment: "Description of `integerEnumProperty` without explicit type.", + type: JSONEnumeration( + name: "integerEnumProperty", + comment: "Description of `integerEnumProperty` without explicit type.", + values: [.integer(value: 1), .integer(value: 2), .integer(value: 3), .integer(value: 4)] + ), + defaultValue: nil, + isRequired: false, + isReadOnly: true + ) + ] + ) + + let file = Bundle.module.url(forResource: "Fixtures/fixture-schema-with-typeless-enum", withExtension: "json")! + + let jsonSchema = try JSONSchemaReader().read(file) + + let actual = try JSONSchemaToJSONTypeTransformer().transform(jsonSchema: jsonSchema) + XCTAssertEqual(expected, actual as? JSONObject) } } + + From 7120dc84e74d913d1a91830a8fc869cadd2302ff Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Thu, 29 Jun 2023 13:04:14 +0100 Subject: [PATCH 21/87] Update mock --- Tests/DatadogTests/Datadog/Mocks/RUMDataModelMocks.swift | 7 ++++++- .../JSONSchemaToJSONTypeTransformerTests.swift | 2 -- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Tests/DatadogTests/Datadog/Mocks/RUMDataModelMocks.swift b/Tests/DatadogTests/Datadog/Mocks/RUMDataModelMocks.swift index 3a7ffc3136..08be91cc36 100644 --- a/Tests/DatadogTests/Datadog/Mocks/RUMDataModelMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/RUMDataModelMocks.swift @@ -85,6 +85,7 @@ extension RUMDevice.RUMDeviceType: RandomMockable { extension RUMOperatingSystem: RandomMockable { public static func mockRandom() -> RUMOperatingSystem { return .init( + build: nil, name: .mockRandom(length: 5), version: .mockRandom(among: .decimalDigits, length: 2), versionMajor: .mockRandom(among: .decimalDigits, length: 1) @@ -107,6 +108,8 @@ extension RUMViewEvent: RandomMockable { dd: .init( browserSdkVersion: nil, documentVersion: .mockRandom(), + pageStates: nil, + replayStats: nil, session: .init(plan: .plan1) ), application: .init(id: .mockRandom()), @@ -117,12 +120,14 @@ extension RUMViewEvent: RandomMockable { device: .mockRandom(), display: nil, os: .mockRandom(), + privacy: nil, service: .mockRandom(), session: .init( hasReplay: nil, id: .mockRandom(), isActive: true, - startReason: .appStart, + sampledForReplay: nil, + startPrecondition: .appLaunch, type: .user ), source: .ios, diff --git a/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift b/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift index 8c3028cce1..db9b384e57 100644 --- a/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift +++ b/tools/rum-models-generator/Tests/CodeGenerationTests/Generate/Transformers/JSONSchemaToJSONTypeTransformerTests.swift @@ -256,5 +256,3 @@ final class JSONSchemaToJSONTypeTransformerTests: XCTestCase { XCTAssertEqual(expected, actual as? JSONObject) } } - - From 847cd96cc45fc3488983a383ec94f4b675ba4f78 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Thu, 29 Jun 2023 15:52:07 +0200 Subject: [PATCH 22/87] RUMM-3151 re-align the blocks - [metadata value] --- .../Storage/Writing/FileWriter.swift | 5 ++- .../DatadogInternal/Upload/Event.swift | 35 ++++++++++++------- .../Persistence/EventGeneratorTests.swift | 20 +++++++++-- .../Persistence/Writing/FileWriterTests.swift | 30 ++++++++-------- 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift b/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift index e7c9c617f1..f317f04f73 100644 --- a/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift +++ b/Sources/Datadog/DatadogCore/Storage/Writing/FileWriter.swift @@ -27,12 +27,15 @@ internal struct FileWriter: Writer { /// - metadata: Encodable metadata to write. func write(value: T, metadata: M?) { do { - var encoded = try encode(encodable: value, blockType: .event) + var encoded: Data = .init() if let metadata = metadata { let encodedMetadata = try encode(encodable: metadata, blockType: .eventMetadata) encoded.append(encodedMetadata) } + let encodedValue = try encode(encodable: value, blockType: .event) + encoded.append(encodedValue) + // Make sure both event and event metadata are written to the same file. // This is to avoid a situation where event is written to one file and event metadata to another. // If this happens, the reader will not be able to match event with its metadata. diff --git a/Sources/Datadog/DatadogInternal/Upload/Event.swift b/Sources/Datadog/DatadogInternal/Upload/Event.swift index b239c46002..c36ed24fc6 100644 --- a/Sources/Datadog/DatadogInternal/Upload/Event.swift +++ b/Sources/Datadog/DatadogInternal/Upload/Event.swift @@ -34,6 +34,12 @@ internal struct EventGenerator: Sequence, IteratorProtocol { } /// Returns the next event. + /// + /// Data format + /// ``` + /// [EVENT 1 METADATA] [EVENT 1] [EVENT 2 METADATA] [EVENT 2] [EVENT 3] + /// ``` + /// /// - Returns: The next event or `nil` if there are no more events. /// - Note: a `DataBlock` with `.event` type marks the beginning of the event. /// It is either followed by another `DataBlock` with `.event` type or @@ -43,25 +49,28 @@ internal struct EventGenerator: Sequence, IteratorProtocol { return nil } - let event = dataBlocks[index] - index += 1 - // if the first block is not event, then skip it - guard event.type == .event else { - return next() + var metadata: DataBlock? = nil + // If the next block is an event metadata, read it. + if dataBlocks[index].type == .eventMetadata { + metadata = dataBlocks[index] + index += 1 } - // if the next block is also event, then there is no metadata - guard index < dataBlocks.count, dataBlocks[index].type != .event else { - return Event(data: event.data, metadata: nil) + // If this is the last block, return nil. + // there cannot be a metadata block without an event block. + guard index < dataBlocks.count else { + return nil } - // otherwise, the next block can be metadata - let metadata = dataBlocks[index] - guard metadata.type == .eventMetadata else { - return Event(data: event.data, metadata: nil) + // If the next block is an event, read it. + guard dataBlocks[index].type == .event else { + // this is safeguard against corrupted data. + // if there was a metadata block, it will be skipped. + return next() } + let event = dataBlocks[index] index += 1 - return Event(data: event.data, metadata: metadata.data) + return Event(data: event.data, metadata: metadata?.data) } } diff --git a/Tests/DatadogTests/Datadog/Core/Persistence/EventGeneratorTests.swift b/Tests/DatadogTests/Datadog/Core/Persistence/EventGeneratorTests.swift index e5e46cfa43..451150543a 100644 --- a/Tests/DatadogTests/Datadog/Core/Persistence/EventGeneratorTests.swift +++ b/Tests/DatadogTests/Datadog/Core/Persistence/EventGeneratorTests.swift @@ -36,21 +36,35 @@ final class EventGeneratorTests: XCTestCase { func testEventWithMetadata() throws { let dataBlocks = [ - DataBlock(type: .event, data: Data([0x01])), - DataBlock(type: .eventMetadata, data: Data([0x02])) + DataBlock(type: .eventMetadata, data: Data([0x02])), + DataBlock(type: .event, data: Data([0x01])) ] let sut = EventGenerator(dataBlocks: dataBlocks) let events = sut.map { $0 } XCTAssertEqual(events.count, 1) + XCTAssertEqual(events[0].metadata, Data([0x02])) XCTAssertEqual(events[0].data, Data([0x01])) + } + + func testEventWithCurruptedMetadata() throws { + let dataBlocks = [ + DataBlock(type: .eventMetadata, data: Data([0x03])), // skipped from reading + DataBlock(type: .eventMetadata, data: Data([0x02])), + DataBlock(type: .event, data: Data([0x01])) + ] + + let sut = EventGenerator(dataBlocks: dataBlocks) + let events = sut.map { $0 } + XCTAssertEqual(events.count, 1) XCTAssertEqual(events[0].metadata, Data([0x02])) + XCTAssertEqual(events[0].data, Data([0x01])) } func testEvents() { let dataBlocks = [ - DataBlock(type: .event, data: Data([0x01])), DataBlock(type: .eventMetadata, data: Data([0x02])), + DataBlock(type: .event, data: Data([0x01])), DataBlock(type: .event, data: Data([0x03])), DataBlock(type: .event, data: Data([0x05])) ] diff --git a/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift b/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift index 1a027f924f..fda0d37ed8 100644 --- a/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift +++ b/Tests/DatadogTests/Datadog/Core/Persistence/Writing/FileWriterTests.swift @@ -39,20 +39,20 @@ class FileWriterTests: XCTestCase { let reader = DataBlockReader(input: stream) var block = try reader.next() - XCTAssertEqual(block?.type, .event) - XCTAssertEqual(block?.data, #"{"key1":"value1"}"#.utf8Data) - block = try reader.next() XCTAssertEqual(block?.type, .eventMetadata) XCTAssertEqual(block?.data, #"{"meta1":"metaValue1"}"#.utf8Data) block = try reader.next() XCTAssertEqual(block?.type, .event) - XCTAssertEqual(block?.data, #"{"key2":"value2"}"#.utf8Data) + XCTAssertEqual(block?.data, #"{"key1":"value1"}"#.utf8Data) block = try reader.next() XCTAssertEqual(block?.type, .event) - XCTAssertEqual(block?.data, #"{"key3":"value3"}"#.utf8Data) + XCTAssertEqual(block?.data, #"{"key2":"value2"}"#.utf8Data) block = try reader.next() XCTAssertEqual(block?.type, .eventMetadata) XCTAssertEqual(block?.data, #"{"meta3":"metaValue3"}"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, #"{"key3":"value3"}"#.utf8Data) } func testItWritesEncryptedDataWithMetadataToSingleFileInTLVFormat() throws { @@ -79,20 +79,20 @@ class FileWriterTests: XCTestCase { let reader = DataBlockReader(input: stream) var block = try reader.next() - XCTAssertEqual(block?.type, .event) - XCTAssertEqual(block?.data, #"encrypted{"key1":"value1"}encrypted"#.utf8Data) - block = try reader.next() XCTAssertEqual(block?.type, .eventMetadata) XCTAssertEqual(block?.data, #"encrypted{"meta1":"metaValue1"}encrypted"#.utf8Data) block = try reader.next() XCTAssertEqual(block?.type, .event) - XCTAssertEqual(block?.data, #"encrypted{"key2":"value2"}encrypted"#.utf8Data) + XCTAssertEqual(block?.data, #"encrypted{"key1":"value1"}encrypted"#.utf8Data) block = try reader.next() XCTAssertEqual(block?.type, .event) - XCTAssertEqual(block?.data, #"encrypted{"key3":"value3"}encrypted"#.utf8Data) + XCTAssertEqual(block?.data, #"encrypted{"key2":"value2"}encrypted"#.utf8Data) block = try reader.next() XCTAssertEqual(block?.type, .eventMetadata) XCTAssertEqual(block?.data, #"encrypted{"meta3":"metaValue3"}encrypted"#.utf8Data) + block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, #"encrypted{"key3":"value3"}encrypted"#.utf8Data) } func testItWritesDataToSingleFileInTLVFormat() throws { @@ -294,7 +294,7 @@ class FileWriterTests: XCTestCase { // Assert that data written is not malformed let jsonDecoder = JSONDecoder() - let eventGenerator = try EventGenerator(dataBlocks: blocks) + let eventGenerator = EventGenerator(dataBlocks: blocks) let events = eventGenerator.map { $0 } // Assert that some (including all) `Foo`s were written @@ -336,10 +336,6 @@ class FileWriterTests: XCTestCase { let reader = DataBlockReader(input: stream) var block = try reader.next() - XCTAssertEqual(block?.type, .event) - XCTAssertEqual(block?.data, "foo".utf8Data) - - block = try reader.next() XCTAssertEqual(block?.type, .eventMetadata) XCTAssertEqual(block?.data, "foo".utf8Data) @@ -354,5 +350,9 @@ class FileWriterTests: XCTestCase { block = try reader.next() XCTAssertEqual(block?.type, .eventMetadata) XCTAssertEqual(block?.data, "foo".utf8Data) + + block = try reader.next() + XCTAssertEqual(block?.type, .event) + XCTAssertEqual(block?.data, "foo".utf8Data) } } From 6fb6e8063c0812297e782a29bc32ce255b7b27ee Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Thu, 29 Jun 2023 15:45:06 +0100 Subject: [PATCH 23/87] PR fixes --- .../RUM/DataModels/RUMDataModels.swift | 22 +++--- .../DatadogObjc/RUM/RUMDataModels+objc.swift | 68 +++++++++---------- .../CodeDecoration/RUMCodeDecorator.swift | 4 -- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/Sources/Datadog/RUM/DataModels/RUMDataModels.swift b/Sources/Datadog/RUM/DataModels/RUMDataModels.swift index 494dcff394..75a59d0022 100644 --- a/Sources/Datadog/RUM/DataModels/RUMDataModels.swift +++ b/Sources/Datadog/RUM/DataModels/RUMDataModels.swift @@ -35,7 +35,7 @@ public struct RUMActionEvent: RUMDataModel { public let device: RUMDevice? /// Display properties - public let display: RUMDisplay? + public let display: Display? /// Operating system properties public let os: RUMOperatingSystem? @@ -301,7 +301,7 @@ public struct RUMActionEvent: RUMDataModel { } /// Display properties - public struct RUMDisplay: Codable { + public struct Display: Codable { /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. public let viewport: Viewport? @@ -431,7 +431,7 @@ public struct RUMErrorEvent: RUMDataModel { public let device: RUMDevice? /// Display properties - public let display: RUMDisplay? + public let display: Display? /// Error properties public var error: Error @@ -544,7 +544,7 @@ public struct RUMErrorEvent: RUMDataModel { } /// Display properties - public struct RUMDisplay: Codable { + public struct Display: Codable { /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. public let viewport: Viewport? @@ -877,7 +877,7 @@ public struct RUMLongTaskEvent: RUMDataModel { public let device: RUMDevice? /// Display properties - public let display: RUMDisplay? + public let display: Display? /// Long Task properties public let longTask: LongTask @@ -990,7 +990,7 @@ public struct RUMLongTaskEvent: RUMDataModel { } /// Display properties - public struct RUMDisplay: Codable { + public struct Display: Codable { /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. public let viewport: Viewport? @@ -1134,7 +1134,7 @@ public struct RUMResourceEvent: RUMDataModel { public let device: RUMDevice? /// Display properties - public let display: RUMDisplay? + public let display: Display? /// Operating system properties public let os: RUMOperatingSystem? @@ -1259,7 +1259,7 @@ public struct RUMResourceEvent: RUMDataModel { } /// Display properties - public struct RUMDisplay: Codable { + public struct Display: Codable { /// The viewport represents the rectangular area that is currently being viewed. Content outside the viewport is not visible onscreen until scrolled into view. public let viewport: Viewport? @@ -1579,7 +1579,7 @@ public struct RUMViewEvent: RUMDataModel { public let device: RUMDevice? /// Display properties - public let display: RUMDisplay? + public let display: Display? /// Feature flags properties public internal(set) var featureFlags: FeatureFlags? @@ -1734,7 +1734,7 @@ public struct RUMViewEvent: RUMDataModel { } /// Display properties - public struct RUMDisplay: Codable { + public struct Display: Codable { /// Scroll properties public let scroll: Scroll? @@ -3182,4 +3182,4 @@ public enum RUMMethod: String, Codable { case patch = "PATCH" } -// Generated from https://github.com/DataDog/rum-events-format/tree/dcb6897cf883fb8938e7aa0f69ed9a035df98c2c +// Generated from https://github.com/DataDog/rum-events-format/tree/1c5eaa897c065e5f790a5f8aaf6fc8782d706051 diff --git a/Sources/DatadogObjc/RUM/RUMDataModels+objc.swift b/Sources/DatadogObjc/RUM/RUMDataModels+objc.swift index 045afe08cf..d43b1355ab 100644 --- a/Sources/DatadogObjc/RUM/RUMDataModels+objc.swift +++ b/Sources/DatadogObjc/RUM/RUMDataModels+objc.swift @@ -52,8 +52,8 @@ public class DDRUMActionEvent: NSObject { root.swiftModel.device != nil ? DDRUMActionEventRUMDevice(root: root) : nil } - @objc public var display: DDRUMActionEventRUMDisplay? { - root.swiftModel.display != nil ? DDRUMActionEventRUMDisplay(root: root) : nil + @objc public var display: DDRUMActionEventDisplay? { + root.swiftModel.display != nil ? DDRUMActionEventDisplay(root: root) : nil } @objc public var os: DDRUMActionEventRUMOperatingSystem? { @@ -603,20 +603,20 @@ public enum DDRUMActionEventRUMDeviceRUMDeviceType: Int { } @objc -public class DDRUMActionEventRUMDisplay: NSObject { +public class DDRUMActionEventDisplay: NSObject { internal let root: DDRUMActionEvent internal init(root: DDRUMActionEvent) { self.root = root } - @objc public var viewport: DDRUMActionEventRUMDisplayViewport? { - root.swiftModel.display!.viewport != nil ? DDRUMActionEventRUMDisplayViewport(root: root) : nil + @objc public var viewport: DDRUMActionEventDisplayViewport? { + root.swiftModel.display!.viewport != nil ? DDRUMActionEventDisplayViewport(root: root) : nil } } @objc -public class DDRUMActionEventRUMDisplayViewport: NSObject { +public class DDRUMActionEventDisplayViewport: NSObject { internal let root: DDRUMActionEvent internal init(root: DDRUMActionEvent) { @@ -855,8 +855,8 @@ public class DDRUMErrorEvent: NSObject { root.swiftModel.device != nil ? DDRUMErrorEventRUMDevice(root: root) : nil } - @objc public var display: DDRUMErrorEventRUMDisplay? { - root.swiftModel.display != nil ? DDRUMErrorEventRUMDisplay(root: root) : nil + @objc public var display: DDRUMErrorEventDisplay? { + root.swiftModel.display != nil ? DDRUMErrorEventDisplay(root: root) : nil } @objc public var error: DDRUMErrorEventError { @@ -1203,20 +1203,20 @@ public enum DDRUMErrorEventRUMDeviceRUMDeviceType: Int { } @objc -public class DDRUMErrorEventRUMDisplay: NSObject { +public class DDRUMErrorEventDisplay: NSObject { internal let root: DDRUMErrorEvent internal init(root: DDRUMErrorEvent) { self.root = root } - @objc public var viewport: DDRUMErrorEventRUMDisplayViewport? { - root.swiftModel.display!.viewport != nil ? DDRUMErrorEventRUMDisplayViewport(root: root) : nil + @objc public var viewport: DDRUMErrorEventDisplayViewport? { + root.swiftModel.display!.viewport != nil ? DDRUMErrorEventDisplayViewport(root: root) : nil } } @objc -public class DDRUMErrorEventRUMDisplayViewport: NSObject { +public class DDRUMErrorEventDisplayViewport: NSObject { internal let root: DDRUMErrorEvent internal init(root: DDRUMErrorEvent) { @@ -1829,8 +1829,8 @@ public class DDRUMLongTaskEvent: NSObject { root.swiftModel.device != nil ? DDRUMLongTaskEventRUMDevice(root: root) : nil } - @objc public var display: DDRUMLongTaskEventRUMDisplay? { - root.swiftModel.display != nil ? DDRUMLongTaskEventRUMDisplay(root: root) : nil + @objc public var display: DDRUMLongTaskEventDisplay? { + root.swiftModel.display != nil ? DDRUMLongTaskEventDisplay(root: root) : nil } @objc public var longTask: DDRUMLongTaskEventLongTask { @@ -2177,20 +2177,20 @@ public enum DDRUMLongTaskEventRUMDeviceRUMDeviceType: Int { } @objc -public class DDRUMLongTaskEventRUMDisplay: NSObject { +public class DDRUMLongTaskEventDisplay: NSObject { internal let root: DDRUMLongTaskEvent internal init(root: DDRUMLongTaskEvent) { self.root = root } - @objc public var viewport: DDRUMLongTaskEventRUMDisplayViewport? { - root.swiftModel.display!.viewport != nil ? DDRUMLongTaskEventRUMDisplayViewport(root: root) : nil + @objc public var viewport: DDRUMLongTaskEventDisplayViewport? { + root.swiftModel.display!.viewport != nil ? DDRUMLongTaskEventDisplayViewport(root: root) : nil } } @objc -public class DDRUMLongTaskEventRUMDisplayViewport: NSObject { +public class DDRUMLongTaskEventDisplayViewport: NSObject { internal let root: DDRUMLongTaskEvent internal init(root: DDRUMLongTaskEvent) { @@ -2446,8 +2446,8 @@ public class DDRUMResourceEvent: NSObject { root.swiftModel.device != nil ? DDRUMResourceEventRUMDevice(root: root) : nil } - @objc public var display: DDRUMResourceEventRUMDisplay? { - root.swiftModel.display != nil ? DDRUMResourceEventRUMDisplay(root: root) : nil + @objc public var display: DDRUMResourceEventDisplay? { + root.swiftModel.display != nil ? DDRUMResourceEventDisplay(root: root) : nil } @objc public var os: DDRUMResourceEventRUMOperatingSystem? { @@ -2806,20 +2806,20 @@ public enum DDRUMResourceEventRUMDeviceRUMDeviceType: Int { } @objc -public class DDRUMResourceEventRUMDisplay: NSObject { +public class DDRUMResourceEventDisplay: NSObject { internal let root: DDRUMResourceEvent internal init(root: DDRUMResourceEvent) { self.root = root } - @objc public var viewport: DDRUMResourceEventRUMDisplayViewport? { - root.swiftModel.display!.viewport != nil ? DDRUMResourceEventRUMDisplayViewport(root: root) : nil + @objc public var viewport: DDRUMResourceEventDisplayViewport? { + root.swiftModel.display!.viewport != nil ? DDRUMResourceEventDisplayViewport(root: root) : nil } } @objc -public class DDRUMResourceEventRUMDisplayViewport: NSObject { +public class DDRUMResourceEventDisplayViewport: NSObject { internal let root: DDRUMResourceEvent internal init(root: DDRUMResourceEvent) { @@ -3380,8 +3380,8 @@ public class DDRUMViewEvent: NSObject { root.swiftModel.device != nil ? DDRUMViewEventRUMDevice(root: root) : nil } - @objc public var display: DDRUMViewEventRUMDisplay? { - root.swiftModel.display != nil ? DDRUMViewEventRUMDisplay(root: root) : nil + @objc public var display: DDRUMViewEventDisplay? { + root.swiftModel.display != nil ? DDRUMViewEventDisplay(root: root) : nil } @objc public var featureFlags: DDRUMViewEventFeatureFlags? { @@ -3772,24 +3772,24 @@ public enum DDRUMViewEventRUMDeviceRUMDeviceType: Int { } @objc -public class DDRUMViewEventRUMDisplay: NSObject { +public class DDRUMViewEventDisplay: NSObject { internal let root: DDRUMViewEvent internal init(root: DDRUMViewEvent) { self.root = root } - @objc public var scroll: DDRUMViewEventRUMDisplayScroll? { - root.swiftModel.display!.scroll != nil ? DDRUMViewEventRUMDisplayScroll(root: root) : nil + @objc public var scroll: DDRUMViewEventDisplayScroll? { + root.swiftModel.display!.scroll != nil ? DDRUMViewEventDisplayScroll(root: root) : nil } - @objc public var viewport: DDRUMViewEventRUMDisplayViewport? { - root.swiftModel.display!.viewport != nil ? DDRUMViewEventRUMDisplayViewport(root: root) : nil + @objc public var viewport: DDRUMViewEventDisplayViewport? { + root.swiftModel.display!.viewport != nil ? DDRUMViewEventDisplayViewport(root: root) : nil } } @objc -public class DDRUMViewEventRUMDisplayScroll: NSObject { +public class DDRUMViewEventDisplayScroll: NSObject { internal let root: DDRUMViewEvent internal init(root: DDRUMViewEvent) { @@ -3814,7 +3814,7 @@ public class DDRUMViewEventRUMDisplayScroll: NSObject { } @objc -public class DDRUMViewEventRUMDisplayViewport: NSObject { +public class DDRUMViewEventDisplayViewport: NSObject { internal let root: DDRUMViewEvent internal init(root: DDRUMViewEvent) { @@ -5325,4 +5325,4 @@ public class DDTelemetryConfigurationEventView: NSObject { // swiftlint:enable force_unwrapping -// Generated from https://github.com/DataDog/rum-events-format/tree/dcb6897cf883fb8938e7aa0f69ed9a035df98c2c +// Generated from https://github.com/DataDog/rum-events-format/tree/1c5eaa897c065e5f790a5f8aaf6fc8782d706051 diff --git a/tools/rum-models-generator/Sources/CodeDecoration/RUMCodeDecorator.swift b/tools/rum-models-generator/Sources/CodeDecoration/RUMCodeDecorator.swift index 43f13ac021..def1aaff88 100644 --- a/tools/rum-models-generator/Sources/CodeDecoration/RUMCodeDecorator.swift +++ b/tools/rum-models-generator/Sources/CodeDecoration/RUMCodeDecorator.swift @@ -100,10 +100,6 @@ public class RUMCodeDecorator: SwiftCodeDecorator { fixedName = "RUMOperatingSystem" } - if fixedName == "Display" { - fixedName = "RUMDisplay" - } - // Since https://github.com/DataDog/rum-events-format/pull/57 `action.id` can be either // single `String` or an array of `[String]`. This is handled by generating Swift enum with // two cases and different associated types. To not duplicate generated code in each nested From aabebe5721d5c1391a90c791f5f62dd8089184b3 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Thu, 29 Jun 2023 18:08:22 +0200 Subject: [PATCH 24/87] RUMM-3151 fix test cases --- .../Core/Persistence/Reading/FileReaderTests.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/DatadogTests/Datadog/Core/Persistence/Reading/FileReaderTests.swift b/Tests/DatadogTests/Datadog/Core/Persistence/Reading/FileReaderTests.swift index 4e6170268d..dd0b92b787 100644 --- a/Tests/DatadogTests/Datadog/Core/Persistence/Reading/FileReaderTests.swift +++ b/Tests/DatadogTests/Datadog/Core/Persistence/Reading/FileReaderTests.swift @@ -27,8 +27,8 @@ class FileReaderTests: XCTestCase { ) ) let dataBlocks = [ - DataBlock(type: .event, data: "ABCD".utf8Data), - DataBlock(type: .eventMetadata, data: "EFGH".utf8Data) + DataBlock(type: .eventMetadata, data: "EFGH".utf8Data), + DataBlock(type: .event, data: "ABCD".utf8Data) ] let data = try dataBlocks .map { try $0.serialize() } @@ -49,11 +49,11 @@ class FileReaderTests: XCTestCase { func testItReadsSingleEncryptedBatch() throws { // Given let dataBlocks = [ - DataBlock(type: .event, data: "foo".utf8Data), DataBlock(type: .eventMetadata, data: "foo".utf8Data), DataBlock(type: .event, data: "foo".utf8Data), DataBlock(type: .event, data: "foo".utf8Data), - DataBlock(type: .eventMetadata, data: "foo".utf8Data) + DataBlock(type: .eventMetadata, data: "foo".utf8Data), + DataBlock(type: .event, data: "foo".utf8Data) ] let data = try dataBlocks .map { Data(try $0.serialize()) } @@ -96,15 +96,15 @@ class FileReaderTests: XCTestCase { ) ) let file1 = try temporaryDirectory.createFile(named: dateProvider.now.toFileName) - try file1.append(data: DataBlock(type: .event, data: "1".utf8Data).serialize()) try file1.append(data: DataBlock(type: .eventMetadata, data: "2".utf8Data).serialize()) + try file1.append(data: DataBlock(type: .event, data: "1".utf8Data).serialize()) let file2 = try temporaryDirectory.createFile(named: dateProvider.now.toFileName) try file2.append(data: DataBlock(type: .event, data: "2".utf8Data).serialize()) let file3 = try temporaryDirectory.createFile(named: dateProvider.now.toFileName) - try file3.append(data: DataBlock(type: .event, data: "3".utf8Data).serialize()) try file3.append(data: DataBlock(type: .eventMetadata, data: "4".utf8Data).serialize()) + try file3.append(data: DataBlock(type: .event, data: "3".utf8Data).serialize()) let expected = [ Event(data: "1".utf8Data, metadata: "2".utf8Data), From fee181380acaead1783732c68360450ae02db677 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Fri, 30 Jun 2023 11:35:40 +0200 Subject: [PATCH 25/87] RUMM-2387 Update CocoaPods specs --- DatadogCrashReporting.podspec | 2 +- DatadogInternal.podspec | 2 +- DatadogLogs.podspec | 2 +- DatadogRUM.podspec | 2 +- DatadogSDK.podspec | 14 ++++++++------ DatadogSDKCrashReporting.podspec | 2 +- DatadogSessionReplay.podspec | 2 +- DatadogTrace.podspec | 2 +- DatadogWebViewTracking.podspec | 2 +- IntegrationTests/Podfile | 5 ++--- dependency-manager-tests/cocoapods/Podfile.src | 5 +++-- 11 files changed, 21 insertions(+), 19 deletions(-) diff --git a/DatadogCrashReporting.podspec b/DatadogCrashReporting.podspec index 2e1a27b780..1e0e1b70db 100644 --- a/DatadogCrashReporting.podspec +++ b/DatadogCrashReporting.podspec @@ -14,7 +14,7 @@ Pod::Spec.new do |s| "Ganesh Jangir" => "ganesh.jangir@datadoghq.com" } - s.swift_version = '5.1' + s.swift_version = '5.5' s.ios.deployment_target = '11.0' s.tvos.deployment_target = '11.0' diff --git a/DatadogInternal.podspec b/DatadogInternal.podspec index 4b1a7661f7..532be94dc6 100644 --- a/DatadogInternal.podspec +++ b/DatadogInternal.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| "Maxime Epain" => "maxime.epain@datadoghq.com" } - s.swift_version = '5.1' + s.swift_version = '5.5' s.ios.deployment_target = '11.0' s.tvos.deployment_target = '11.0' diff --git a/DatadogLogs.podspec b/DatadogLogs.podspec index ae228e98da..ee0760e1f6 100644 --- a/DatadogLogs.podspec +++ b/DatadogLogs.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| "Maxime Epain" => "maxime.epain@datadoghq.com" } - s.swift_version = '5.1' + s.swift_version = '5.5' s.ios.deployment_target = '11.0' s.tvos.deployment_target = '11.0' diff --git a/DatadogRUM.podspec b/DatadogRUM.podspec index 0e138824af..1d0ef07f7a 100644 --- a/DatadogRUM.podspec +++ b/DatadogRUM.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| "Maxime Epain" => "maxime.epain@datadoghq.com" } - s.swift_version = '5.1' + s.swift_version = '5.5' s.ios.deployment_target = '11.0' s.tvos.deployment_target = '11.0' diff --git a/DatadogSDK.podspec b/DatadogSDK.podspec index 069caedad0..2d56211d57 100644 --- a/DatadogSDK.podspec +++ b/DatadogSDK.podspec @@ -1,6 +1,5 @@ Pod::Spec.new do |s| s.name = "DatadogSDK" - s.module_name = "Datadog" s.version = "2.0.0-alpha1" s.summary = "Official Datadog Swift SDK for iOS." @@ -20,11 +19,14 @@ Pod::Spec.new do |s| s.tvos.deployment_target = '11.0' s.source = { :git => "https://github.com/DataDog/dd-sdk-ios.git", :tag => s.version.to_s } - - s.default_subspec = 'Core' - s.subspec 'Core' do |ss| - ss.dependency 'DatadogCore', s.version.to_s - end + s.deprecated_in_favor_of = + 'DatadogCore, DatadogLogs, DatadogRUM, DatadogTrace, and DatadogWebViewTracking' + + s.dependency 'DatadogCore', s.version.to_s + s.dependency 'DatadogLogs', s.version.to_s + s.dependency 'DatadogRUM', s.version.to_s + s.dependency 'DatadogTrace', s.version.to_s + s.dependency 'DatadogWebViewTracking', s.version.to_s end diff --git a/DatadogSDKCrashReporting.podspec b/DatadogSDKCrashReporting.podspec index 795fd28b1a..91ca5c5852 100644 --- a/DatadogSDKCrashReporting.podspec +++ b/DatadogSDKCrashReporting.podspec @@ -15,7 +15,7 @@ Pod::Spec.new do |s| "Ganesh Jangir" => "ganesh.jangir@datadoghq.com" } - s.swift_version = '5.1' + s.swift_version = '5.5' s.ios.deployment_target = '11.0' s.tvos.deployment_target = '11.0' diff --git a/DatadogSessionReplay.podspec b/DatadogSessionReplay.podspec index 2d680d2747..85ced3a750 100644 --- a/DatadogSessionReplay.podspec +++ b/DatadogSessionReplay.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| "Maxime Epain" => "maxime.epain@datadoghq.com" } - s.swift_version = '5.1' + s.swift_version = '5.5' s.ios.deployment_target = '11.0' s.source = { :git => "https://github.com/DataDog/dd-sdk-ios.git", :tag => s.version.to_s } diff --git a/DatadogTrace.podspec b/DatadogTrace.podspec index 3b887ac515..f561a16379 100644 --- a/DatadogTrace.podspec +++ b/DatadogTrace.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| "Maxime Epain" => "maxime.epain@datadoghq.com" } - s.swift_version = '5.1' + s.swift_version = '5.5' s.ios.deployment_target = '11.0' s.tvos.deployment_target = '11.0' diff --git a/DatadogWebViewTracking.podspec b/DatadogWebViewTracking.podspec index 37c6f22c6d..0c3a2c2900 100644 --- a/DatadogWebViewTracking.podspec +++ b/DatadogWebViewTracking.podspec @@ -14,7 +14,7 @@ Pod::Spec.new do |s| "Ganesh Jangir" => "ganesh.jangir@datadoghq.com" } - s.swift_version = '5.1' + s.swift_version = '5.5' s.ios.deployment_target = '11.0' s.tvos.deployment_target = '11.0' diff --git a/IntegrationTests/Podfile b/IntegrationTests/Podfile index bc576867b9..d7f2b1cb87 100644 --- a/IntegrationTests/Podfile +++ b/IntegrationTests/Podfile @@ -2,14 +2,13 @@ target 'Runner iOS' do platform :ios, '11.0' pod 'DatadogCore', :path => '..' - pod 'DatadogSDKObjc', :path => '..' - pod 'DatadogSDKCrashReporting', :path => '..' - pod 'DatadogLogs', :path => '..' pod 'DatadogTrace', :path => '..' pod 'DatadogRUM', :path => '..' + pod 'DatadogCrashReporting', :path => '..' pod 'DatadogSessionReplay', :path => '..' pod 'DatadogWebViewTracking', :path => '..' + pod 'DatadogObjc', :path => '..' target 'IntegrationScenarios' do pod 'DatadogInternal', :path => '..' diff --git a/dependency-manager-tests/cocoapods/Podfile.src b/dependency-manager-tests/cocoapods/Podfile.src index b54d2779ef..aba2e10715 100644 --- a/dependency-manager-tests/cocoapods/Podfile.src +++ b/dependency-manager-tests/cocoapods/Podfile.src @@ -1,11 +1,12 @@ abstract_target 'Common' do pod 'DatadogInternal', :git => 'GIT_REMOTE', :GIT_REFERENCE + pod 'DatadogCore', :git => 'GIT_REMOTE', :GIT_REFERENCE pod 'DatadogLogs', :git => 'GIT_REMOTE', :GIT_REFERENCE pod 'DatadogTrace', :git => 'GIT_REMOTE', :GIT_REFERENCE pod 'DatadogRUM', :git => 'GIT_REMOTE', :GIT_REFERENCE pod 'DatadogCore', :git => 'GIT_REMOTE', :GIT_REFERENCE - pod 'DatadogSDKAlamofireExtension', :git => 'GIT_REMOTE', :GIT_REFERENCE - pod 'DatadogSDKCrashReporting', :git => 'GIT_REMOTE', :GIT_REFERENCE + pod 'DatadogAlamofireExtension', :git => 'GIT_REMOTE', :GIT_REFERENCE + pod 'DatadogCrashReporting', :git => 'GIT_REMOTE', :GIT_REFERENCE pod 'DatadogWebViewTracking', :git => 'GIT_REMOTE', :GIT_REFERENCE pod 'Alamofire' From 357318e1ff41c82f2b013775293ffc8dcfc24028 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 23 Jun 2023 10:56:53 +0100 Subject: [PATCH 26/87] REPLAY-1805 Update model generation script --- tools/rum-models-generator/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/rum-models-generator/run.py b/tools/rum-models-generator/run.py index 5fe6c3926c..fb4514c6dd 100755 --- a/tools/rum-models-generator/run.py +++ b/tools/rum-models-generator/run.py @@ -24,7 +24,7 @@ # Generated file paths (relative to repository root) RUM_SWIFT_GENERATED_FILE_PATH = '/Sources/Datadog/RUM/DataModels/RUMDataModels.swift' RUM_OBJC_GENERATED_FILE_PATH = '/Sources/DatadogObjc/RUM/RUMDataModels+objc.swift' -SR_SWIFT_GENERATED_FILE_PATH = '/DatadogSessionReplay/Sources/DatadogSessionReplay/Writer/Models/SRDataModels.swift' +SR_SWIFT_GENERATED_FILE_PATH = '/DatadogSessionReplay/Sources/Writer/Models/SRDataModels.swift' @dataclass From 1e60bb9bacde70528c64debe04babde6a38f6f49 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 23 Jun 2023 11:24:28 +0100 Subject: [PATCH 27/87] REPLAY-1805 Regenerate SR model --- .../Processor/Diffing/Diff+SRWireframes.swift | 28 ++++++ .../WireframesBuilder.swift | 21 +++++ .../Sources/Writer/Models/SRDataModels.swift | 92 ++++++++++++++++++- tools/rum-models-generator/README.md | 6 +- .../CodeDecoration/SRCodeDecorator.swift | 1 + 5 files changed, 144 insertions(+), 4 deletions(-) diff --git a/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift b/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift index 7f9e2fa070..033fa27031 100644 --- a/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift +++ b/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift @@ -17,6 +17,8 @@ extension SRWireframe: Diffable { return wireframe.id case .textWireframe(let wireframe): return wireframe.id + case .placeholderWireframe(let wireframe): + return wireframe.id } } @@ -28,6 +30,8 @@ extension SRWireframe: Diffable { return this.hashValue != other.hashValue case let (.imageWireframe(this), .imageWireframe(other)): return this.hashValue != other.hashValue + case let (.placeholderWireframe(this), .placeholderWireframe(other)): + return this.hashValue != other.hashValue default: return true } @@ -64,6 +68,8 @@ extension SRWireframe: MutableWireframe { return try this.mutations(from: otherWireframe) case .textWireframe(let this): return try this.mutations(from: otherWireframe) + case .placeholderWireframe(let this): + return try this.mutations(from: otherWireframe) } } } @@ -92,6 +98,28 @@ extension SRShapeWireframe: MutableWireframe { } } +extension SRPlaceholderWireframe: MutableWireframe { + func mutations(from otherWireframe: SRWireframe) throws -> WireframeMutation { + guard case .imageWireframe(let other) = otherWireframe else { + throw WireframeMutationError.typeMismatch + } + guard other.id == id else { + throw WireframeMutationError.idMismatch + } + + return .placeholderWireframeUpdate( + value: .init( + clip: use(clip, ifDifferentThan: other.clip), + height: use(height, ifDifferentThan: other.height), + id: id, + width: use(width, ifDifferentThan: other.width), + x: use(x, ifDifferentThan: other.x), + y: use(y, ifDifferentThan: other.y) + ) + ) + } +} + extension SRImageWireframe: MutableWireframe { func mutations(from otherWireframe: SRWireframe) throws -> WireframeMutation { guard case .imageWireframe(let other) = otherWireframe else { diff --git a/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift b/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift index 43bc520729..b8b7e66560 100644 --- a/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift +++ b/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift @@ -146,6 +146,27 @@ internal class WireframesBuilder { return .textWireframe(value: wireframe) } + func createPlaceholderWireframe( + clip: SRContentClip? = nil, + height: Int64, + id: Int64, + label: String, + width: Int64, + x: Int64, + y: Int64 + ) -> SRWireframe { + let wireframe = SRPlaceholderWireframe( + clip: clip, + height: height, + id: id, + label: label, + width: width, + x: x, + y: y + ) + return .placeholderWireframe(value: wireframe) + } + // MARK: - Private private func createShapeBorder(borderColor: CGColor?, borderWidth: CGFloat?) -> SRShapeBorder? { diff --git a/DatadogSessionReplay/Sources/Writer/Models/SRDataModels.swift b/DatadogSessionReplay/Sources/Writer/Models/SRDataModels.swift index ff0448ea3c..68b2625e76 100644 --- a/DatadogSessionReplay/Sources/Writer/Models/SRDataModels.swift +++ b/DatadogSessionReplay/Sources/Writer/Models/SRDataModels.swift @@ -374,11 +374,50 @@ internal struct SRImageWireframe: Codable, Hashable { } } +/// Schema of all properties of a PlaceholderWireframe. +internal struct SRPlaceholderWireframe: Codable, Hashable { + /// Schema of clipping information for a Wireframe. + internal let clip: SRContentClip? + + /// The height in pixels of the UI element, normalized based on the device pixels per inch density (DPI). Example: if a device has a DPI = 2, the height of all UI elements is divided by 2 to get a normalized height. + internal let height: Int64 + + /// Defines the unique ID of the wireframe. This is persistent throughout the view lifetime. + internal let id: Int64 + + /// Label of the placeholder + internal var label: String? + + /// The type of the wireframe. + internal let type: String = "placeholder" + + /// The width in pixels of the UI element, normalized based on the device pixels per inch density (DPI). Example: if a device has a DPI = 2, the width of all UI elements is divided by 2 to get a normalized width. + internal let width: Int64 + + /// The position in pixels on X axis of the UI element in absolute coordinates. The anchor point is always the top-left corner of the wireframe. + internal let x: Int64 + + /// The position in pixels on Y axis of the UI element in absolute coordinates. The anchor point is always the top-left corner of the wireframe. + internal let y: Int64 + + enum CodingKeys: String, CodingKey { + case clip = "clip" + case height = "height" + case id = "id" + case label = "label" + case type = "type" + case width = "width" + case x = "x" + case y = "y" + } +} + /// Schema of a Wireframe type. internal enum SRWireframe: Codable { case shapeWireframe(value: SRShapeWireframe) case textWireframe(value: SRTextWireframe) case imageWireframe(value: SRImageWireframe) + case placeholderWireframe(value: SRPlaceholderWireframe) // MARK: - Codable @@ -393,6 +432,8 @@ internal enum SRWireframe: Codable { try container.encode(value) case .imageWireframe(let value): try container.encode(value) + case .placeholderWireframe(let value): + try container.encode(value) } } @@ -412,6 +453,10 @@ internal enum SRWireframe: Codable { self = .imageWireframe(value: value) return } + if let value = try? container.decode(SRPlaceholderWireframe.self) { + self = .placeholderWireframe(value: value) + return + } let error = DecodingError.Context( codingPath: container.codingPath, debugDescription: """ @@ -569,6 +614,7 @@ internal struct SRIncrementalSnapshotRecord: Codable { case textWireframeUpdate(value: TextWireframeUpdate) case shapeWireframeUpdate(value: ShapeWireframeUpdate) case imageWireframeUpdate(value: ImageWireframeUpdate) + case placeholderWireframeUpdate(value: PlaceholderWireframeUpdate) // MARK: - Codable @@ -583,6 +629,8 @@ internal struct SRIncrementalSnapshotRecord: Codable { try container.encode(value) case .imageWireframeUpdate(let value): try container.encode(value) + case .placeholderWireframeUpdate(let value): + try container.encode(value) } } @@ -602,6 +650,10 @@ internal struct SRIncrementalSnapshotRecord: Codable { self = .imageWireframeUpdate(value: value) return } + if let value = try? container.decode(PlaceholderWireframeUpdate.self) { + self = .placeholderWireframeUpdate(value: value) + return + } let error = DecodingError.Context( codingPath: container.codingPath, debugDescription: """ @@ -761,6 +813,44 @@ internal struct SRIncrementalSnapshotRecord: Codable { case y = "y" } } + + /// Schema of all properties of a PlaceholderWireframe. + internal struct PlaceholderWireframeUpdate: Codable { + /// Schema of clipping information for a Wireframe. + internal let clip: SRContentClip? + + /// The height in pixels of the UI element, normalized based on the device pixels per inch density (DPI). Example: if a device has a DPI = 2, the height of all UI elements is divided by 2 to get a normalized height. + internal let height: Int64? + + /// Defines the unique ID of the wireframe. This is persistent throughout the view lifetime. + internal let id: Int64 + + /// Label of the placeholder + internal var label: String? + + /// The type of the wireframe. + internal let type: String = "placeholder" + + /// The width in pixels of the UI element, normalized based on the device pixels per inch density (DPI). Example: if a device has a DPI = 2, the width of all UI elements is divided by 2 to get a normalized width. + internal let width: Int64? + + /// The position in pixels on X axis of the UI element in absolute coordinates. The anchor point is always the top-left corner of the wireframe. + internal let x: Int64? + + /// The position in pixels on Y axis of the UI element in absolute coordinates. The anchor point is always the top-left corner of the wireframe. + internal let y: Int64? + + enum CodingKeys: String, CodingKey { + case clip = "clip" + case height = "height" + case id = "id" + case label = "label" + case type = "type" + case width = "width" + case x = "x" + case y = "y" + } + } } } @@ -1052,4 +1142,4 @@ internal enum SRRecord: Codable { } } -// Generated from https://github.com/DataDog/rum-events-format/tree/067bca66899474c390afe43377e4c31155290cf2 +// Generated from https://github.com/DataDog/rum-events-format/tree/e3d941c30622ff8624051604584ebd3f9fff2b25 diff --git a/tools/rum-models-generator/README.md b/tools/rum-models-generator/README.md index 457e5b40c4..37b86535a0 100644 --- a/tools/rum-models-generator/README.md +++ b/tools/rum-models-generator/README.md @@ -4,10 +4,10 @@ ## Usage -To update the data models to the latest version: - +To update the data models to the latest version, call this in the root directory of the `dd-sdk-ios`. ``` -# make rum-models-generator +# make rum-models-generate +# make sr-models-generate ``` ## License diff --git a/tools/rum-models-generator/Sources/CodeDecoration/SRCodeDecorator.swift b/tools/rum-models-generator/Sources/CodeDecoration/SRCodeDecorator.swift index b5c7eafd31..2b60dff8c6 100644 --- a/tools/rum-models-generator/Sources/CodeDecoration/SRCodeDecorator.swift +++ b/tools/rum-models-generator/Sources/CodeDecoration/SRCodeDecorator.swift @@ -21,6 +21,7 @@ public class SRCodeDecorator: SwiftCodeDecorator { "SRShapeWireframe", "SRTextWireframe", "SRImageWireframe", + "SRPlaceholderWireframe", // For convenience, make fat `*Record` structures to be root types: "SRFullSnapshotRecord", "SRIncrementalSnapshotRecord", From 12912a3f5600c4cab49deca1167eab5e4e57b3a5 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 23 Jun 2023 11:37:13 +0100 Subject: [PATCH 28/87] REPLAY-1805 Use new placeholder --- .../WireframesBuilder.swift | 19 ++++++------- .../NodeRecorders/UIImageViewRecorder.swift | 27 +++++++++++++------ .../UnsupportedViewRecorder.swift | 11 ++------ 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift b/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift index b8b7e66560..025e8508a7 100644 --- a/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift +++ b/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift @@ -58,7 +58,7 @@ internal class WireframesBuilder { } func createImageWireframe( - base64: String?, + base64: String, id: WireframeID, frame: CGRect, mimeType: String = "png", @@ -75,7 +75,7 @@ internal class WireframesBuilder { clip: clip, height: Int64(withNoOverflow: frame.height), id: id, - isEmpty: base64?.isEmpty == true ? true : nil, + isEmpty: false, mimeType: mimeType, shapeStyle: createShapeStyle(backgroundColor: backgroundColor, cornerRadius: cornerRadius, opacity: opacity), width: Int64(withNoOverflow: frame.width), @@ -147,22 +147,19 @@ internal class WireframesBuilder { } func createPlaceholderWireframe( - clip: SRContentClip? = nil, - height: Int64, id: Int64, + frame: CGRect, label: String, - width: Int64, - x: Int64, - y: Int64 + clip: SRContentClip? = nil ) -> SRWireframe { let wireframe = SRPlaceholderWireframe( clip: clip, - height: height, + height: Int64(withNoOverflow: frame.size.height), id: id, label: label, - width: width, - x: x, - y: y + width: Int64(withNoOverflow: frame.size.width), + x: Int64(withNoOverflow: frame.minX), + y: Int64(withNoOverflow: frame.minY) ) return .placeholderWireframe(value: wireframe) } diff --git a/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift b/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift index fdca087905..f9f934107a 100644 --- a/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift +++ b/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift @@ -133,7 +133,7 @@ internal struct UIImageViewWireframesBuilder: NodeWireframesBuilder { opacity: attributes.alpha ) ] - var base64: String = "" + var base64: String? if shouldRecordImage { base64 = imageDataProvider.contentBase64String( of: image, @@ -141,14 +141,25 @@ internal struct UIImageViewWireframesBuilder: NodeWireframesBuilder { ) } if let contentFrame = contentFrame { - wireframes.append( - builder.createImageWireframe( - base64: base64, - id: imageWireframeID, - frame: contentFrame, - clip: clipsToBounds ? clip : nil + if let base64 = base64 { + wireframes.append( + builder.createImageWireframe( + base64: base64, + id: imageWireframeID, + frame: contentFrame, + clip: clipsToBounds ? clip : nil + ) ) - ) + } else { + wireframes.append( + builder.createPlaceholderWireframe( + id: imageWireframeID, + frame: contentFrame, + label: "Content Image", + clip: clipsToBounds ? clip : nil + ) + ) + } } return wireframes } diff --git a/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UnsupportedViewRecorder.swift b/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UnsupportedViewRecorder.swift index bb24bbbdfb..10990652d7 100644 --- a/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UnsupportedViewRecorder.swift +++ b/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UnsupportedViewRecorder.swift @@ -47,17 +47,10 @@ internal struct UnsupportedViewWireframesBuilder: NodeWireframesBuilder { func buildWireframes(with builder: WireframesBuilder) -> [SRWireframe] { return [ - builder.createTextWireframe( + builder.createPlaceholderWireframe( id: wireframeID, frame: attributes.frame, - text: unsupportedClassName, - textFrame: attributes.frame, - textAlignment: .init(horizontal: .center, vertical: .center), - textColor: UIColor.red.cgColor, - borderColor: UIColor.lightGray.cgColor, - borderWidth: 1, - backgroundColor: UIColor(white: 0.95, alpha: 1).cgColor, - cornerRadius: 4 + label: unsupportedClassName ) ] } From ea49f26d58fbd304097178a8883fce4888bd8d29 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 23 Jun 2023 11:41:48 +0100 Subject: [PATCH 29/87] REPLAY-1805 Add deprecated comment --- .../Processor/SRDataModelsBuilder/WireframesBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift b/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift index 025e8508a7..eaa637792b 100644 --- a/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift +++ b/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift @@ -75,7 +75,7 @@ internal class WireframesBuilder { clip: clip, height: Int64(withNoOverflow: frame.height), id: id, - isEmpty: false, + isEmpty: false, // field deprecated - we should use placeholder wireframe instead mimeType: mimeType, shapeStyle: createShapeStyle(backgroundColor: backgroundColor, cornerRadius: cornerRadius, opacity: opacity), width: Int64(withNoOverflow: frame.width), From f115f4fc3f754afd0c574d509c46cbe4bd623309 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Wed, 28 Jun 2023 12:19:27 +0100 Subject: [PATCH 30/87] REPLAY-1805 Fix snapshot tests --- .../Utils/ImageRendering.swift | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift b/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift index 8ed0358eb0..5933eb91d8 100644 --- a/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift +++ b/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift @@ -42,6 +42,8 @@ private extension SRWireframe { return text.toFrame() case .imageWireframe(value: let image): return image.toFrame() + case .placeholderWireframe(value: let placeholder): + return placeholder.toFrame() } } } @@ -85,6 +87,34 @@ private extension SRImageWireframe { } } +private extension SRPlaceholderWireframe { + func toFrame() -> BlueprintFrame { + BlueprintFrame( + x: CGFloat(x), + y: CGFloat(y), + width: CGFloat(width), + height: CGFloat(height), + style: frameStyle( + border: .init(color: "#000000FF", width: 2), + style: .init( + backgroundColor: "#A9A9A9FF", + cornerRadius: 0, + opacity: 1 + ) + ), + content: frameContent( + text: label ?? "Placeholder", + textStyle: .init(color: "#FF000000", family: UIFont.systemFont(ofSize: 12).fontName, size: 12), + textPosition: .init( + alignment: .init(horizontal: .center, vertical: .center), + padding: .init(bottom: 0, left: 0, right: 0, top: 0) + ) + ) + ) + } +} + + private func frameStyle(border: SRShapeBorder?, style: SRShapeStyle?) -> BlueprintFrame.Style { var fs = BlueprintFrame.Style( lineWidth: 0, From 822a8839d1d9a7e6754ef36d2b6b2d79f523ecbb Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Wed, 28 Jun 2023 13:48:07 +0100 Subject: [PATCH 31/87] REPLAY-1805 Remove clipping in favour of relative rect --- .../Utils/ImageRendering.swift | 2 +- .../NodeRecorders/UIImageViewRecorder.swift | 26 +++---------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift b/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift index 5933eb91d8..d10f526a1d 100644 --- a/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift +++ b/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift @@ -104,7 +104,7 @@ private extension SRPlaceholderWireframe { ), content: frameContent( text: label ?? "Placeholder", - textStyle: .init(color: "#FF000000", family: UIFont.systemFont(ofSize: 12).fontName, size: 12), + textStyle: .init(color: "#FF000000", family: "Verdana", size: 12), textPosition: .init( alignment: .init(horizontal: .center, vertical: .center), padding: .init(bottom: 0, left: 0, right: 0, top: 0) diff --git a/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift b/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift index f9f934107a..4af5744511 100644 --- a/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift +++ b/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift @@ -98,26 +98,10 @@ internal struct UIImageViewWireframesBuilder: NodeWireframesBuilder { let shouldRecordImage: Bool - private var clip: SRContentClip? { + private var relativeIntersectedRect: CGRect? { guard let contentFrame = contentFrame else { return nil } - let top = max(relativeIntersectedRect.origin.y - contentFrame.origin.y, 0) - let left = max(relativeIntersectedRect.origin.x - contentFrame.origin.x, 0) - let bottom = max(contentFrame.height - (relativeIntersectedRect.height + top), 0) - let right = max(contentFrame.width - (relativeIntersectedRect.width + left), 0) - return SRContentClip( - bottom: Int64(withNoOverflow: bottom), - left: Int64(withNoOverflow: left), - right: Int64(withNoOverflow: right), - top: Int64(withNoOverflow: top) - ) - } - - private var relativeIntersectedRect: CGRect { - guard let contentFrame = contentFrame else { - return .zero - } return attributes.frame.intersection(contentFrame) } @@ -140,14 +124,13 @@ internal struct UIImageViewWireframesBuilder: NodeWireframesBuilder { tintColor: tintColor ) } - if let contentFrame = contentFrame { + if let contentFrame = clipsToBounds ? relativeIntersectedRect : contentFrame { if let base64 = base64 { wireframes.append( builder.createImageWireframe( base64: base64, id: imageWireframeID, - frame: contentFrame, - clip: clipsToBounds ? clip : nil + frame: contentFrame ) ) } else { @@ -155,8 +138,7 @@ internal struct UIImageViewWireframesBuilder: NodeWireframesBuilder { builder.createPlaceholderWireframe( id: imageWireframeID, frame: contentFrame, - label: "Content Image", - clip: clipsToBounds ? clip : nil + label: "Content Image" ) ) } From 7c088873fecd217fb2a8aa4684cf68702f45b47d Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 30 Jun 2023 12:10:30 +0100 Subject: [PATCH 32/87] REPLAY-1805 Update tests --- .../UIImageViewWireframesBuilderTests.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/DatadogSessionReplay/Tests/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewWireframesBuilderTests.swift b/DatadogSessionReplay/Tests/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewWireframesBuilderTests.swift index 6388b5acfb..9adefbd958 100644 --- a/DatadogSessionReplay/Tests/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewWireframesBuilderTests.swift +++ b/DatadogSessionReplay/Tests/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewWireframesBuilderTests.swift @@ -50,10 +50,10 @@ class UIImageViewWireframesBuilderTests: XCTestCase { func test_BuildCorrectWireframes_whenContentImageIsIgnored() { let wireframeID = WireframeID.mockRandom() - let imageWireframeID = WireframeID.mockRandom() + let placeholderWireframeID = WireframeID.mockRandom() let builder = UIImageViewWireframesBuilder( wireframeID: wireframeID, - imageWireframeID: imageWireframeID, + imageWireframeID: placeholderWireframeID, attributes: ViewAttributes.mock(fixture: .visible(.someAppearance)), contentFrame: CGRect(x: 10, y: 10, width: 200, height: 200), clipsToBounds: true, @@ -73,9 +73,9 @@ class UIImageViewWireframesBuilderTests: XCTestCase { XCTFail("First wireframe needs to be shapeWireframe case") } - if case let .imageWireframe(imageWireframe) = wireframes[1] { - XCTAssertEqual(imageWireframe.id, imageWireframeID) - XCTAssertEqual(imageWireframe.base64, "") + if case let .placeholderWireframe(placeholderWireframe) = wireframes[1] { + XCTAssertEqual(placeholderWireframe.id, placeholderWireframeID) + XCTAssertEqual(placeholderWireframe.label, "Content Image") } else { XCTFail("Second wireframe needs to be imageWireframe case") } From abca88e4bac3c1d571f41bf20884835fc24d9151 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Fri, 30 Jun 2023 13:12:55 +0200 Subject: [PATCH 33/87] fix: broken IntegrationTests target --- .../RUM/RUMManualInstrumentationScenarioTests.swift | 5 +++-- .../Scenarios/RUM/RUMResourcesScenarioTests.swift | 12 ++++++++---- .../Scenarios/RUM/RUMStopSessionScenarioTests.swift | 10 ++++++---- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMManualInstrumentationScenarioTests.swift b/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMManualInstrumentationScenarioTests.swift index 5abe02ec2a..5fc6501114 100644 --- a/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMManualInstrumentationScenarioTests.swift +++ b/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMManualInstrumentationScenarioTests.swift @@ -79,8 +79,9 @@ class RUMManualInstrumentationScenarioTests: IntegrationTests, RUMCommonAsserts XCTAssertEqual(view1.resourceEvents[0].resource.url, "https://foo.com/resource/1") XCTAssertEqual(view1.resourceEvents[0].resource.statusCode, 200) XCTAssertEqual(view1.resourceEvents[0].resource.type, .image) - XCTAssertGreaterThan(view1.resourceEvents[0].resource.duration, 100_000_000 - 1) // ~0.1s - XCTAssertLessThan(view1.resourceEvents[0].resource.duration, 1_000_000_000 * 30) // less than 30s (big enough to balance NTP sync) + XCTAssertNotNil(view1.resourceEvents[0].resource.duration) // ~0.1s + XCTAssertGreaterThan(view1.resourceEvents[0].resource.duration!, 100_000_000 - 1) // ~0.1s + XCTAssertLessThan(view1.resourceEvents[0].resource.duration!, 1_000_000_000 * 30) // less than 30s (big enough to balance NTP sync) XCTAssertEqual(view1.errorEvents[0].error.type, "NSURLErrorDomain - -1011") XCTAssertEqual(view1.errorEvents[0].error.message, "Bad response.") XCTAssertEqual( diff --git a/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMResourcesScenarioTests.swift b/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMResourcesScenarioTests.swift index 488c68c8e3..b39966be65 100644 --- a/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMResourcesScenarioTests.swift +++ b/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMResourcesScenarioTests.swift @@ -130,7 +130,8 @@ class RUMResourcesScenarioTests: IntegrationTests, RUMCommonAsserts { "RUM Resource should be send for `firstPartyGETResourceURL`" ) XCTAssertEqual(firstPartyResource1.resource.method, .get) - XCTAssertGreaterThan(firstPartyResource1.resource.duration, 0) + XCTAssertNotNil(firstPartyResource1.resource.duration) + XCTAssertGreaterThan(firstPartyResource1.resource.duration!, 0) XCTAssertNil(firstPartyResource1.dd.traceId, "`firstPartyGETResourceURL` should not be traced") XCTAssertNil(firstPartyResource1.dd.spanId, "`firstPartyGETResourceURL` should not be traced") @@ -141,7 +142,8 @@ class RUMResourcesScenarioTests: IntegrationTests, RUMCommonAsserts { "RUM Resource should be send for `firstPartyPOSTResourceURL`" ) XCTAssertEqual(firstPartyResource2.resource.method, .post) - XCTAssertGreaterThan(firstPartyResource2.resource.duration, 0) + XCTAssertNotNil(firstPartyResource2.resource.duration) + XCTAssertGreaterThan(firstPartyResource2.resource.duration!, 0) XCTAssertEqual( firstPartyResource2.dd.traceId, firstPartyPOSTRequestTraceID, @@ -172,7 +174,8 @@ class RUMResourcesScenarioTests: IntegrationTests, RUMCommonAsserts { "RUM Resource should be send for `thirdPartyGETResourceURL`" ) XCTAssertEqual(thirdPartyResource1.resource.method, .get) - XCTAssertGreaterThan(thirdPartyResource1.resource.duration, 0) + XCTAssertNotNil(thirdPartyResource1.resource.duration) + XCTAssertGreaterThan(thirdPartyResource1.resource.duration!, 0) XCTAssertNil(thirdPartyResource1.dd.traceId, "3rd party RUM Resources should not be traced") XCTAssertNil(thirdPartyResource1.dd.spanId, "3rd party RUM Resources should not be traced") XCTAssertNil(thirdPartyResource1.dd.rulePsr, "Not traced resource should not send sample rate") @@ -182,7 +185,8 @@ class RUMResourcesScenarioTests: IntegrationTests, RUMCommonAsserts { "RUM Resource should be send for `thirdPartyPOSTResourceURL`" ) XCTAssertEqual(thirdPartyResource2.resource.method, .post) - XCTAssertGreaterThan(thirdPartyResource2.resource.duration, 0) + XCTAssertNotNil(thirdPartyResource2.resource.duration) + XCTAssertGreaterThan(thirdPartyResource2.resource.duration!, 0) XCTAssertNil(thirdPartyResource2.dd.traceId, "3rd party RUM Resources should not be traced") XCTAssertNil(thirdPartyResource2.dd.spanId, "3rd party RUM Resources should not be traced") XCTAssertNil(thirdPartyResource2.dd.rulePsr, "Not traced resource should not send sample rate") diff --git a/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMStopSessionScenarioTests.swift b/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMStopSessionScenarioTests.swift index ff83cffeb3..0b06a10800 100644 --- a/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMStopSessionScenarioTests.swift +++ b/Tests/DatadogIntegrationTests/Scenarios/RUM/RUMStopSessionScenarioTests.swift @@ -100,8 +100,9 @@ class RUMStopSessionScenarioTests: IntegrationTests, RUMCommonAsserts { XCTAssertEqual(view1.resourceEvents[0].resource.url, "https://foo.com/resource/1") XCTAssertEqual(view1.resourceEvents[0].resource.statusCode, 200) XCTAssertEqual(view1.resourceEvents[0].resource.type, .image) - XCTAssertGreaterThan(view1.resourceEvents[0].resource.duration, 100_000_000 - 1) // ~0.1s - XCTAssertLessThan(view1.resourceEvents[0].resource.duration, 1_000_000_000 * 30) // less than 30s (big enough to balance NTP sync) + XCTAssertNotNil(view1.resourceEvents[0].resource.duration) + XCTAssertGreaterThan(view1.resourceEvents[0].resource.duration!, 100_000_000 - 1) // ~0.1s + XCTAssertLessThan(view1.resourceEvents[0].resource.duration!, 1_000_000_000 * 30) // less than 30s (big enough to balance NTP sync) RUMSessionMatcher.assertViewWasEventuallyInactive(view1) let view2 = normalSession.viewVisits[1] @@ -123,8 +124,9 @@ class RUMStopSessionScenarioTests: IntegrationTests, RUMCommonAsserts { XCTAssertEqual(view1.resourceEvents[0].resource.url, "https://foo.com/resource/1") XCTAssertEqual(view1.resourceEvents[0].resource.statusCode, 200) XCTAssertEqual(view1.resourceEvents[0].resource.type, .image) - XCTAssertGreaterThan(view1.resourceEvents[0].resource.duration, 100_000_000 - 1) // ~0.1s - XCTAssertLessThan(view1.resourceEvents[0].resource.duration, 1_000_000_000 * 30) // less than 30s (big enough to balance NTP sync) + XCTAssertNotNil(view1.resourceEvents[0].resource.duration) + XCTAssertGreaterThan(view1.resourceEvents[0].resource.duration!, 100_000_000 - 1) // ~0.1s + XCTAssertLessThan(view1.resourceEvents[0].resource.duration!, 1_000_000_000 * 30) // less than 30s (big enough to balance NTP sync) RUMSessionMatcher.assertViewWasEventuallyInactive(view1) let view2 = interruptedSession.viewVisits[1] From f368c8fbbfd7a2750c8c23b00f9d65fcc42fa892 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 30 Jun 2023 12:23:42 +0100 Subject: [PATCH 34/87] REPLAY-1805 Fix snapshot appearance --- .../SRSnapshotTests/Utils/ImageRendering.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift b/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift index d10f526a1d..9ddbaba4a8 100644 --- a/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift +++ b/DatadogSessionReplay/SRSnapshotTests/SRSnapshotTests/Utils/ImageRendering.swift @@ -95,7 +95,7 @@ private extension SRPlaceholderWireframe { width: CGFloat(width), height: CGFloat(height), style: frameStyle( - border: .init(color: "#000000FF", width: 2), + border: .init(color: "#000000FF", width: 4), style: .init( backgroundColor: "#A9A9A9FF", cornerRadius: 0, @@ -104,7 +104,7 @@ private extension SRPlaceholderWireframe { ), content: frameContent( text: label ?? "Placeholder", - textStyle: .init(color: "#FF000000", family: "Verdana", size: 12), + textStyle: .init(color: "#000000FF", family: "-apple-system", size: 24), textPosition: .init( alignment: .init(horizontal: .center, vertical: .center), padding: .init(bottom: 0, left: 0, right: 0, top: 0) From 16d9c4ca3aedc49313a2f49d5d61c283a4506d45 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 30 Jun 2023 12:24:23 +0100 Subject: [PATCH 35/87] REPLAY-1805 Fix lint --- .../Processor/SRDataModelsBuilder/WireframesBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift b/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift index eaa637792b..ef917115b5 100644 --- a/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift +++ b/DatadogSessionReplay/Sources/Processor/SRDataModelsBuilder/WireframesBuilder.swift @@ -152,7 +152,7 @@ internal class WireframesBuilder { label: String, clip: SRContentClip? = nil ) -> SRWireframe { - let wireframe = SRPlaceholderWireframe( + let wireframe = SRPlaceholderWireframe( clip: clip, height: Int64(withNoOverflow: frame.size.height), id: id, From 54ed9f6e193e689ce3505a86a68ec1461818a603 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 30 Jun 2023 12:57:31 +0100 Subject: [PATCH 36/87] REPLAY-1805 Fix regression and add tests --- .../Processor/Diffing/Diff+SRWireframes.swift | 2 +- .../Tests/Mocks/SRDataModelsMocks.swift | 131 ++++++++++++++++++ .../Diffing/Diff+SRWireframesTests.swift | 64 ++++++++- 3 files changed, 195 insertions(+), 2 deletions(-) diff --git a/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift b/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift index 033fa27031..292e476910 100644 --- a/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift +++ b/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift @@ -100,7 +100,7 @@ extension SRShapeWireframe: MutableWireframe { extension SRPlaceholderWireframe: MutableWireframe { func mutations(from otherWireframe: SRWireframe) throws -> WireframeMutation { - guard case .imageWireframe(let other) = otherWireframe else { + guard case .placeholderWireframe(let other) = otherWireframe else { throw WireframeMutationError.typeMismatch } guard other.id == id else { diff --git a/DatadogSessionReplay/Tests/Mocks/SRDataModelsMocks.swift b/DatadogSessionReplay/Tests/Mocks/SRDataModelsMocks.swift index c6965f7ccf..c14af8a896 100644 --- a/DatadogSessionReplay/Tests/Mocks/SRDataModelsMocks.swift +++ b/DatadogSessionReplay/Tests/Mocks/SRDataModelsMocks.swift @@ -309,6 +309,137 @@ extension SRContentClip: AnyMockable, RandomMockable { } } +extension SRPlaceholderWireframe: AnyMockable, RandomMockable { + public static func mockAny() -> SRPlaceholderWireframe { + return SRPlaceholderWireframe( + clip: .mockAny(), + height: .mockAny(), + id: .mockAny(), + width: .mockAny(), + x: .mockAny(), + y: .mockAny() + ) + } + + public static func mockRandom() -> SRPlaceholderWireframe { + return SRPlaceholderWireframe( + clip: .mockRandom(), + height: .mockRandom(), + id: .mockRandom(), + width: .mockRandom(), + x: .mockRandom(), + y: .mockRandom() + ) + } + + static func mockWith( + clip: SRContentClip? = .mockAny(), + height: Int64 = .mockAny(), + id: Int64 = .mockAny(), + width: Int64 = .mockAny(), + x: Int64 = .mockAny(), + y: Int64 = .mockAny() + ) -> SRPlaceholderWireframe { + return SRPlaceholderWireframe( + clip: clip, + height: height, + id: id, + width: width, + x: x, + y: y + ) + } + + static func mockRandomWith(id: WireframeID) -> SRPlaceholderWireframe { + return SRPlaceholderWireframe( + clip: .mockRandom(), + height: .mockRandom(), + id: id, + width: .mockRandom(), + x: .mockRandom(), + y: .mockRandom() + ) + } +} + +extension SRImageWireframe: AnyMockable, RandomMockable { + public static func mockAny() -> SRImageWireframe { + return SRImageWireframe( + base64: .mockAny(), + border: .mockAny(), + clip: .mockAny(), + height: .mockAny(), + id: .mockAny(), + isEmpty: .mockAny(), + mimeType: .mockAny(), + shapeStyle: .mockAny(), + width: .mockAny(), + x: .mockAny(), + y: .mockAny() + ) + } + + public static func mockRandom() -> SRImageWireframe { + return SRImageWireframe( + base64: .mockRandom(), + border: .mockRandom(), + clip: .mockRandom(), + height: .mockRandom(), + id: .mockRandom(), + isEmpty: .mockRandom(), + mimeType: .mockRandom(), + shapeStyle: .mockRandom(), + width: .mockRandom(), + x: .mockRandom(), + y: .mockRandom() + ) + } + + static func mockWith( + base64: String? = .mockAny(), + border: SRShapeBorder? = .mockAny(), + clip: SRContentClip? = .mockAny(), + height: Int64 = .mockAny(), + id: Int64 = .mockAny(), + isEmpty: Bool = .mockAny(), + mimeType: String? = .mockAny(), + shapeStyle: SRShapeStyle? = .mockAny(), + width: Int64 = .mockAny(), + x: Int64 = .mockAny(), + y: Int64 = .mockAny() + ) -> SRImageWireframe { + return SRImageWireframe( + base64: base64, + border: border, + clip: clip, + height: height, + id: id, + isEmpty: isEmpty, + mimeType: mimeType, + shapeStyle: shapeStyle, + width: width, + x: x, + y: y + ) + } + + static func mockRandomWith(id: WireframeID) -> SRImageWireframe { + return SRImageWireframe( + base64: .mockRandom(), + border: .mockRandom(), + clip: .mockRandom(), + height: .mockRandom(), + id: id, + isEmpty: .mockRandom(), + mimeType: .mockRandom(), + shapeStyle: .mockRandom(), + width: .mockRandom(), + x: .mockRandom(), + y: .mockRandom() + ) + } +} + extension SRWireframe: AnyMockable, RandomMockable { public static func mockAny() -> SRWireframe { return .shapeWireframe(value: .mockAny()) diff --git a/DatadogSessionReplay/Tests/Processor/Diffing/Diff+SRWireframesTests.swift b/DatadogSessionReplay/Tests/Processor/Diffing/Diff+SRWireframesTests.swift index 61f30af588..e170cb5ae1 100644 --- a/DatadogSessionReplay/Tests/Processor/Diffing/Diff+SRWireframesTests.swift +++ b/DatadogSessionReplay/Tests/Processor/Diffing/Diff+SRWireframesTests.swift @@ -15,7 +15,9 @@ class DiffSRWireframes: XCTestCase { let randomID: Int64 = .mockRandom() let wireframes: [SRWireframe] = [ .shapeWireframe(value: .mockWith(id: randomID)), - .textWireframe(value: .mockWith(id: randomID)) + .textWireframe(value: .mockWith(id: randomID)), + .imageWireframe(value: .mockWith(id: randomID)), + .placeholderWireframe(value: .mockWith(id: randomID)) ] wireframes.forEach { XCTAssertEqual($0.id, randomID) } @@ -55,6 +57,32 @@ class DiffSRWireframes: XCTestCase { DDAssertReflectionEqual(result, otherWireframe) } + func testsWhenMergingMutationsToTheOriginalImageWireframe_itShouldProduceTheOtherOne() throws { + // Given + let originalWireframe: SRWireframe = .imageWireframe(value: .mockRandom()) + let otherWireframe: SRWireframe = .imageWireframe(value: .mockRandomWith(id: originalWireframe.id)) + + // When + let mutations = try XCTUnwrap(otherWireframe.mutations(from: originalWireframe), "Failed to compute mutations") + + // Then + let result = try XCTUnwrap(originalWireframe.merge(mutation: mutations), "Failed to merge mutations") + DDAssertReflectionEqual(result, otherWireframe) + } + + func testsWhenMergingMutationsToTheOriginalPlaceholderWireframe_itShouldProduceTheOtherOne() throws { + // Given + let originalWireframe: SRWireframe = .placeholderWireframe(value: .mockRandom()) + let otherWireframe: SRWireframe = .placeholderWireframe(value: .mockRandomWith(id: originalWireframe.id)) + + // When + let mutations = try XCTUnwrap(otherWireframe.mutations(from: originalWireframe), "Failed to compute mutations") + + // Then + let result = try XCTUnwrap(originalWireframe.merge(mutation: mutations), "Failed to merge mutations") + DDAssertReflectionEqual(result, otherWireframe) + } + func testWhenComputingMutationsForWireframesWithDifferentID_itThrows() throws { let randomID: WireframeID = .mockRandom() let otherID: WireframeID = .mockRandom(otherThan: [randomID]) @@ -97,6 +125,8 @@ class DiffSRWireframes: XCTestCase { private typealias TextWireframeUpdate = SRIncrementalSnapshotRecord.Data.MutationData.Updates.TextWireframeUpdate private typealias ShapeWireframeUpdate = SRIncrementalSnapshotRecord.Data.MutationData.Updates.ShapeWireframeUpdate +private typealias ImageWireframeUpdate = SRIncrementalSnapshotRecord.Data.MutationData.Updates.ImageWireframeUpdate +private typealias PlaceholderWireframeUpdate = SRIncrementalSnapshotRecord.Data.MutationData.Updates.PlaceholderWireframeUpdate extension SRWireframe { func merge(mutation: WireframeMutation) -> SRWireframe? { @@ -105,6 +135,10 @@ extension SRWireframe { return .shapeWireframe(value: merge(update: update, into: wireframe)) case let (.textWireframe(wireframe), .textWireframeUpdate(update)): return .textWireframe(value: merge(update: update, into: wireframe)) + case let (.imageWireframe(wireframe), .imageWireframeUpdate(update)): + return .imageWireframe(value: merge(update: update, into: wireframe)) + case let (.placeholderWireframe(wireframe), .placeholderWireframeUpdate(update)): + return .placeholderWireframe(value: merge(update: update, into: wireframe)) default: return nil } @@ -138,4 +172,32 @@ extension SRWireframe { y: update.y ?? wireframe.y ) } + + private func merge(update: ImageWireframeUpdate, into wireframe: SRImageWireframe) -> SRImageWireframe { + return SRImageWireframe( + base64: update.base64 ?? wireframe.base64, + border: update.border ?? wireframe.border, + clip: update.clip ?? wireframe.clip, + height: update.height ?? wireframe.height, + id: update.id, + isEmpty: update.isEmpty ?? wireframe.isEmpty, + mimeType: update.mimeType ?? wireframe.mimeType, + shapeStyle: update.shapeStyle ?? wireframe.shapeStyle, + width: update.width ?? wireframe.width, + x: update.x ?? wireframe.x, + y: update.y ?? wireframe.y + ) + } + + private func merge(update: PlaceholderWireframeUpdate, into wireframe: SRPlaceholderWireframe) -> SRPlaceholderWireframe { + return SRPlaceholderWireframe( + clip: update.clip ?? wireframe.clip, + height: update.height ?? wireframe.height, + id: update.id, + label: update.label ?? wireframe.label, + width: update.width ?? wireframe.width, + x: update.x ?? wireframe.x, + y: update.y ?? wireframe.y + ) + } } From 053a8510232aadc046298eb6aa893267e4919936 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Fri, 30 Jun 2023 14:00:15 +0200 Subject: [PATCH 37/87] RUMM-2987 Use instance name for data persistency --- DatadogCore/Sources/Core/Storage/Directories.swift | 6 +++--- DatadogCore/Sources/Datadog.swift | 5 +++-- DatadogCore/Tests/Datadog/Core/DirectoriesTests.swift | 10 +++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/DatadogCore/Sources/Core/Storage/Directories.swift b/DatadogCore/Sources/Core/Storage/Directories.swift index 3b18f933f1..94e8166eef 100644 --- a/DatadogCore/Sources/Core/Storage/Directories.swift +++ b/DatadogCore/Sources/Core/Storage/Directories.swift @@ -41,10 +41,10 @@ internal extension CoreDirectory { /// /// - Parameters: /// - osDirectory: the root OS directory (`/Library/Caches`) to create core directory inside. - /// - clientToken: The core instance client token. + /// - instancenName: The core instance name. /// - site: The cor instance site. - init(in osDirectory: Directory, clientToken: String, site: DatadogSite) throws { - let sdkInstanceUUID = sha256("\(clientToken)\(site)") + init(in osDirectory: Directory, instancenName: String, site: DatadogSite) throws { + let sdkInstanceUUID = sha256("\(instancenName)\(site)") let path = "com.datadoghq/v2/\(sdkInstanceUUID)" self.init( diff --git a/DatadogCore/Sources/Datadog.swift b/DatadogCore/Sources/Datadog.swift index b24a474dc3..ae320757ea 100644 --- a/DatadogCore/Sources/Datadog.swift +++ b/DatadogCore/Sources/Datadog.swift @@ -240,7 +240,8 @@ public struct Datadog { /// - Parameters: /// - configuration: the SDK configuration. /// - trackingConsent: the initial state of the Data Tracking Consent given by the user of the app. - /// - instanceName: The core instance name. + /// - instanceName: The core instance name. This value will be used for data persistency and should be + /// stable between application runs. public static func initialize( with configuration: Configuration, trackingConsent: TrackingConsent, @@ -299,7 +300,7 @@ public struct Datadog { let core = DatadogCore( directory: try CoreDirectory( in: Directory.cache(), - clientToken: configuration.clientToken, + instancenName: instanceName, site: configuration.site ), dateProvider: configuration.dateProvider, diff --git a/DatadogCore/Tests/Datadog/Core/DirectoriesTests.swift b/DatadogCore/Tests/Datadog/Core/DirectoriesTests.swift index d98ae330fa..42a110fd1d 100644 --- a/DatadogCore/Tests/Datadog/Core/DirectoriesTests.swift +++ b/DatadogCore/Tests/Datadog/Core/DirectoriesTests.swift @@ -24,7 +24,7 @@ class DirectoriesTests: XCTestCase { func testWhenCreatingCoreDirectory_thenItsNameIsUniqueForClientTokenAndSite() throws { // Given - let fixtures: [(clientToken: String, site: DatadogSite, expectedName: String)] = [ + let fixtures: [(instancenName: String, site: DatadogSite, expectedName: String)] = [ ("abcdef", .us1, "d5f91716d9c17bc76cb9931e1f9ff37724a27d4c05f1eb7081f59ea34d44c777"), ("abcdef", .us3, "4a2e7e5b459af9976950e85463db2ba1e71500cdd77ead26b41559bf5a372dfb"), ("abcdef", .us5, "38028ebbeab2aa980eab9e5a8ee714f93e8118621472697dabe084e6a9c55cd1"), @@ -40,10 +40,10 @@ class DirectoriesTests: XCTestCase { ] // When - let coreDirectories = try fixtures.map { clientToken, site, _ in + let coreDirectories = try fixtures.map { instancenName, site, _ in try CoreDirectory( in: directory, - clientToken: clientToken, + instancenName: instancenName, site: site ) } @@ -54,7 +54,7 @@ class DirectoriesTests: XCTestCase { let directoryName = coreDirectory.coreDirectory.url.lastPathComponent XCTAssertEqual(directoryName, fixture.expectedName) XCTAssertFalse( - directoryName.contains(fixture.clientToken), + directoryName.contains(fixture.instancenName), "The core directory name must not include client token" ) } @@ -65,7 +65,7 @@ class DirectoriesTests: XCTestCase { let coreDirectories = try (0..<50).map { index in try CoreDirectory( in: directory, - clientToken: .mockRandom(among: .alphanumerics, length: 31) + "\(index)", + instancenName: .mockRandom(among: .alphanumerics, length: 31) + "\(index)", site: .mockRandom() ) } From f005ecafcd3e8098cb333ef57ab6f4e6ebfee286 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Fri, 30 Jun 2023 17:09:06 +0200 Subject: [PATCH 38/87] feat: remove RUMViewUpdatesThrottlerType and send all events to batch writer --- Datadog/Datadog.xcodeproj/project.pbxproj | 12 -- .../Scopes/RUMScopeDependencies.swift | 3 - .../RUM/RUMMonitor/Scopes/RUMViewScope.swift | 10 +- .../Utils/RUMViewUpdatesThrottler.swift | 54 ------- Tests/DatadogTests/Datadog/LoggerTests.swift | 8 +- .../Datadog/Mocks/RUMFeatureMocks.swift | 10 -- .../Datadog/RUM/RUMInternalProxyTests.swift | 2 +- .../RUMMonitor/Scopes/RUMViewScopeTests.swift | 136 ------------------ .../Utils/RUMViewUpdatesThrottlerTests.swift | 53 ------- .../Datadog/RUMMonitorTests.swift | 2 +- .../DatadogObjc/DDRUMMonitorTests.swift | 3 +- 11 files changed, 8 insertions(+), 285 deletions(-) delete mode 100644 Sources/Datadog/RUM/RUMMonitor/Scopes/Utils/RUMViewUpdatesThrottler.swift delete mode 100644 Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/Utils/RUMViewUpdatesThrottlerTests.swift diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index 211c41a12d..da6ecf6ad0 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -165,8 +165,6 @@ 6141015B251A601D00E3C2D9 /* UIKitRUMUserActionsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6141015A251A601D00E3C2D9 /* UIKitRUMUserActionsHandler.swift */; }; 61410167251A661D00E3C2D9 /* UIApplicationSwizzlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61410166251A661D00E3C2D9 /* UIApplicationSwizzlerTests.swift */; }; 61411B1024EC15AC0012EAB2 /* Casting+RUM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61411B0F24EC15AC0012EAB2 /* Casting+RUM.swift */; }; - 6141CE672806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6141CE662806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift */; }; - 6141CE682806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6141CE662806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift */; }; 61441C0524616DE9003D8BB8 /* ExampleAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61441C0424616DE9003D8BB8 /* ExampleAppDelegate.swift */; }; 61441C0C24616DE9003D8BB8 /* Main iOS.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61441C0A24616DE9003D8BB8 /* Main iOS.storyboard */; }; 61441C0E24616DEC003D8BB8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 61441C0D24616DEC003D8BB8 /* Assets.xcassets */; }; @@ -188,8 +186,6 @@ 61441C9D2461A796003D8BB8 /* AppConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61441C9C2461A796003D8BB8 /* AppConfiguration.swift */; }; 6147E3B3270486920092BC9F /* TracingConfigurationE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6147E3B2270486920092BC9F /* TracingConfigurationE2ETests.swift */; }; 614872772485067300E3EBDB /* SpanTagsReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614872762485067300E3EBDB /* SpanTagsReducer.swift */; }; - 61494B7A27F352570082BBCC /* RUMViewUpdatesThrottler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494B7927F352570082BBCC /* RUMViewUpdatesThrottler.swift */; }; - 61494B7B27F352570082BBCC /* RUMViewUpdatesThrottler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494B7927F352570082BBCC /* RUMViewUpdatesThrottler.swift */; }; 61494CB124C839460082C633 /* RUMResourceScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494CB024C839460082C633 /* RUMResourceScope.swift */; }; 61494CB524C864680082C633 /* RUMResourceScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494CB424C864680082C633 /* RUMResourceScopeTests.swift */; }; 61494CBA24CB126F0082C633 /* RUMUserActionScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494CB924CB126F0082C633 /* RUMUserActionScope.swift */; }; @@ -1528,7 +1524,6 @@ 61410166251A661D00E3C2D9 /* UIApplicationSwizzlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationSwizzlerTests.swift; sourceTree = ""; }; 61411B0F24EC15AC0012EAB2 /* Casting+RUM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Casting+RUM.swift"; sourceTree = ""; }; 61417DC52525CDDE00E2D55C /* TaskInterception.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskInterception.swift; sourceTree = ""; }; - 6141CE662806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewUpdatesThrottlerTests.swift; sourceTree = ""; }; 61441C0224616DE9003D8BB8 /* Example iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Example iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 61441C0424616DE9003D8BB8 /* ExampleAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleAppDelegate.swift; sourceTree = ""; }; 61441C0B24616DE9003D8BB8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "Base.lproj/Main iOS.storyboard"; sourceTree = ""; }; @@ -1549,7 +1544,6 @@ 61441C9C2461A796003D8BB8 /* AppConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConfiguration.swift; sourceTree = ""; }; 6147E3B2270486920092BC9F /* TracingConfigurationE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingConfigurationE2ETests.swift; sourceTree = ""; }; 614872762485067300E3EBDB /* SpanTagsReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpanTagsReducer.swift; sourceTree = ""; }; - 61494B7927F352570082BBCC /* RUMViewUpdatesThrottler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewUpdatesThrottler.swift; sourceTree = ""; }; 61494CB024C839460082C633 /* RUMResourceScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMResourceScope.swift; sourceTree = ""; }; 61494CB424C864680082C633 /* RUMResourceScopeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMResourceScopeTests.swift; sourceTree = ""; }; 61494CB924CB126F0082C633 /* RUMUserActionScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMUserActionScope.swift; sourceTree = ""; }; @@ -3093,7 +3087,6 @@ children = ( 61C1510C25AC8C1B00362D4B /* RUMViewIdentityTests.swift */, 61A614E9276B9D4C00A06CE7 /* RUMOffViewEventsHandlingRuleTests.swift */, - 6141CE662806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift */, ); path = Utils; sourceTree = ""; @@ -3190,7 +3183,6 @@ children = ( 61FF9A4425AC5DEA001058CC /* RUMViewIdentity.swift */, 61A614E7276B2BD000A06CE7 /* RUMOffViewEventsHandlingRule.swift */, - 61494B7927F352570082BBCC /* RUMViewUpdatesThrottler.swift */, ); path = Utils; sourceTree = ""; @@ -5614,7 +5606,6 @@ 614B0A4F24EBDC6B00A2A780 /* RUMConnectivityInfoProvider.swift in Sources */, D2CBC2572942008800134409 /* AnyDecodable.swift in Sources */, 9E68FB55244707FD0013A8AA /* ObjcExceptionHandler.m in Sources */, - 61494B7A27F352570082BBCC /* RUMViewUpdatesThrottler.swift in Sources */, D2B3F04A2829510600C2B5EE /* DatadogCoreProtocol.swift in Sources */, 6122514827FDFF82004F5AE4 /* RUMScopeDependencies.swift in Sources */, 615950EE291C058F00470E0C /* SessionReplayDependency.swift in Sources */, @@ -5968,7 +5959,6 @@ 614B0A4D24EBD71500A2A780 /* RUMUserInfoProviderTests.swift in Sources */, 61DA8CB828647A500074A606 /* InternalLoggerTests.swift in Sources */, 9EF963E82537556300235F98 /* DDURLSessionDelegateAsSuperclassTests.swift in Sources */, - 6141CE672806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift in Sources */, 61F3CDAB25121FB500C816E5 /* UIViewControllerSwizzlerTests.swift in Sources */, A728ADA32934DB5000397996 /* W3CHTTPHeadersWriterTests.swift in Sources */, 9E989A4225F640D100235FC3 /* AppStateListenerTests.swift in Sources */, @@ -6298,7 +6288,6 @@ 6122514927FDFF82004F5AE4 /* RUMScopeDependencies.swift in Sources */, D2CB6E2B27C50EAE00A62B57 /* RUMViewScope.swift in Sources */, D2CB6E2C27C50EAE00A62B57 /* KronosNTPPacket.swift in Sources */, - 61494B7B27F352570082BBCC /* RUMViewUpdatesThrottler.swift in Sources */, D2CB6E2F27C50EAE00A62B57 /* SpanTagsReducer.swift in Sources */, D2CB6E3027C50EAE00A62B57 /* RUMApplicationScope.swift in Sources */, D2D37DC02846335F00FB4348 /* DatadogV1CoreProtocol.swift in Sources */, @@ -6690,7 +6679,6 @@ D2CB6F7627C520D400A62B57 /* RUMUserInfoProviderTests.swift in Sources */, 61DA8CB928647A500074A606 /* InternalLoggerTests.swift in Sources */, D2CB6F7727C520D400A62B57 /* DDURLSessionDelegateAsSuperclassTests.swift in Sources */, - 6141CE682806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift in Sources */, D2CB6F7927C520D400A62B57 /* UIViewControllerSwizzlerTests.swift in Sources */, D2CB6F7A27C520D400A62B57 /* AppStateListenerTests.swift in Sources */, D2CB6F7B27C520D400A62B57 /* RUMApplicationScopeTests.swift in Sources */, diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMScopeDependencies.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMScopeDependencies.swift index f36095f6c3..facbc8ad4d 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMScopeDependencies.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMScopeDependencies.swift @@ -27,8 +27,6 @@ internal struct RUMScopeDependencies { let rumUUIDGenerator: RUMUUIDGenerator /// Integration with CIApp tests. It contains the CIApp test context when active. let ciTest: RUMCITest? - /// Produces `RUMViewUpdatesThrottlerType` for each started RUM view scope. - let viewUpdatesThrottlerFactory: () -> RUMViewUpdatesThrottlerType let vitalsReaders: VitalsReaders? let onSessionStart: RUMSessionListener? @@ -57,7 +55,6 @@ internal extension RUMScopeDependencies { ), rumUUIDGenerator: rumFeature.configuration.uuidGenerator, ciTest: CITestIntegration.active?.rumCITest, - viewUpdatesThrottlerFactory: { RUMViewUpdatesThrottler() }, vitalsReaders: rumFeature.configuration.vitalsFrequency.map { .init( frequency: $0, diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift index ebadc9c12a..73238c566e 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift @@ -89,9 +89,6 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { private let vitalInfoSampler: VitalInfoSampler? - /// Samples view update events, so we can minimize the number of events in payload. - private let viewUpdatesThrottler: RUMViewUpdatesThrottlerType - private var viewPerformanceMetrics: [PerformanceMetric: VitalInfo] = [:] init( @@ -126,7 +123,6 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { frequency: $0.frequency ) } - self.viewUpdatesThrottler = dependencies.viewUpdatesThrottlerFactory() } // MARK: - RUMContextProvider @@ -512,11 +508,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { ) if let event = dependencies.eventBuilder.build(from: viewEvent) { - if viewUpdatesThrottler.accept(event: event) { - writer.write(value: event, metadata: event.metadata()) - } else { // if event was dropped by sampler - version -= 1 - } + writer.write(value: event, metadata: event.metadata()) // Update `CrashContext` with recent RUM view (no matter sampling - we want to always // have recent information if process is interrupted by crash): diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/Utils/RUMViewUpdatesThrottler.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/Utils/RUMViewUpdatesThrottler.swift deleted file mode 100644 index ab70e5ac47..0000000000 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/Utils/RUMViewUpdatesThrottler.swift +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 2019-Present Datadog, Inc. - */ - -import Foundation - -internal protocol RUMViewUpdatesThrottlerType { - func accept(event: RUMViewEvent) -> Bool -} - -/// An utility suppressing the number of view updates sent for a single view. -/// -/// It uses time-based heuristic for view updates throttling: -/// - it suppresses updates which happen more frequent than `viewUpdateThreshold`, -/// - it always samples (accepts) first and last update for the view. -internal final class RUMViewUpdatesThrottler: RUMViewUpdatesThrottlerType { - struct Constants { - /// Default suppression interval, in seconds. - static let defaultViewUpdateThreshold: TimeInterval = 30.0 - } - - /// Suppression interval, in nanoseconds. - private let viewUpdateThresholdInNs: Int64 - /// The `timeSpent` (in ns) from the last accepted view event. - private var lastSampledTimeSpentInNs: Int64? = nil - - init(viewUpdateThreshold: TimeInterval = Constants.defaultViewUpdateThreshold) { - self.viewUpdateThresholdInNs = viewUpdateThreshold.toInt64Nanoseconds - } - - /// Based on the `viewUpdateThresholdInNs` and `viewUpdate.timeSpent`, it decides if an event should be "sampled" or not. - /// - Returns: `true` if event should be sent to Datadog and `false` if it should be dropped. - func accept(event: RUMViewEvent) -> Bool { - var sample: Bool - - if let lastTimeSpent = lastSampledTimeSpentInNs { - sample = (event.view.timeSpent - lastTimeSpent) >= viewUpdateThresholdInNs - } else { - sample = true // always accept the first event in a view - } - - sample = sample || event.view.isActive == false // always accept the last event in a view - - sample = sample || event.view.crash.map { $0.count > 0 } ?? false - - if sample { - lastSampledTimeSpentInNs = event.view.timeSpent - } - - return sample - } -} diff --git a/Tests/DatadogTests/Datadog/LoggerTests.swift b/Tests/DatadogTests/Datadog/LoggerTests.swift index 9cec620c43..3de755e75a 100644 --- a/Tests/DatadogTests/Datadog/LoggerTests.swift +++ b/Tests/DatadogTests/Datadog/LoggerTests.swift @@ -631,7 +631,7 @@ class LoggerTests: XCTestCase { dependencies: RUMScopeDependencies( core: core, rumFeature: rum - ).replacing(viewUpdatesThrottlerFactory: { NoOpRUMViewUpdatesThrottler() }), + ), dateProvider: SystemDateProvider() ) Global.rum.startView(viewController: mockView) @@ -675,7 +675,7 @@ class LoggerTests: XCTestCase { dependencies: RUMScopeDependencies( core: core, rumFeature: rum - ).replacing(viewUpdatesThrottlerFactory: { NoOpRUMViewUpdatesThrottler() }), + ), dateProvider: SystemDateProvider() ) Global.rum.startView(viewController: mockView) @@ -725,7 +725,7 @@ class LoggerTests: XCTestCase { dependencies: RUMScopeDependencies( core: core, rumFeature: rum - ).replacing(viewUpdatesThrottlerFactory: { NoOpRUMViewUpdatesThrottler() }), + ), dateProvider: SystemDateProvider() ) Global.rum.startView(viewController: mockView) @@ -771,7 +771,7 @@ class LoggerTests: XCTestCase { dependencies: RUMScopeDependencies( core: core, rumFeature: rum - ).replacing(viewUpdatesThrottlerFactory: { NoOpRUMViewUpdatesThrottler() }), + ), dateProvider: SystemDateProvider() ) Global.rum.startView(viewController: mockView) diff --git a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift index b781746d76..2b642804e7 100644 --- a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift @@ -676,12 +676,6 @@ extension RUMSessionState: AnyMockable, RandomMockable { // MARK: - RUMScope Mocks -internal struct NoOpRUMViewUpdatesThrottler: RUMViewUpdatesThrottlerType { - func accept(event: RUMViewEvent) -> Bool { - return true // always send view update - } -} - func mockNoOpSessionListener() -> RUMSessionListener { return { _, _ in } } @@ -701,7 +695,6 @@ extension RUMScopeDependencies { eventBuilder: RUMEventBuilder = RUMEventBuilder(eventsMapper: .mockNoOp()), rumUUIDGenerator: RUMUUIDGenerator = DefaultRUMUUIDGenerator(), ciTest: RUMCITest? = nil, - viewUpdatesThrottlerFactory: @escaping () -> RUMViewUpdatesThrottlerType = { NoOpRUMViewUpdatesThrottler() }, vitalsReaders: VitalsReaders? = nil, onSessionStart: @escaping RUMSessionListener = mockNoOpSessionListener() ) -> RUMScopeDependencies { @@ -715,7 +708,6 @@ extension RUMScopeDependencies { eventBuilder: eventBuilder, rumUUIDGenerator: rumUUIDGenerator, ciTest: ciTest, - viewUpdatesThrottlerFactory: viewUpdatesThrottlerFactory, vitalsReaders: vitalsReaders, onSessionStart: onSessionStart ) @@ -731,7 +723,6 @@ extension RUMScopeDependencies { eventBuilder: RUMEventBuilder? = nil, rumUUIDGenerator: RUMUUIDGenerator? = nil, ciTest: RUMCITest? = nil, - viewUpdatesThrottlerFactory: (() -> RUMViewUpdatesThrottlerType)? = nil, vitalsReaders: VitalsReaders? = nil, onSessionStart: RUMSessionListener? = nil ) -> RUMScopeDependencies { @@ -745,7 +736,6 @@ extension RUMScopeDependencies { eventBuilder: eventBuilder ?? self.eventBuilder, rumUUIDGenerator: rumUUIDGenerator ?? self.rumUUIDGenerator, ciTest: ciTest ?? self.ciTest, - viewUpdatesThrottlerFactory: viewUpdatesThrottlerFactory ?? self.viewUpdatesThrottlerFactory, vitalsReaders: vitalsReaders ?? self.vitalsReaders, onSessionStart: onSessionStart ?? self.onSessionStart ) diff --git a/Tests/DatadogTests/Datadog/RUM/RUMInternalProxyTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMInternalProxyTests.swift index 86d166ed64..3f24e57bcb 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMInternalProxyTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMInternalProxyTests.swift @@ -32,7 +32,7 @@ class RUMInternalProxyTests: XCTestCase { dependencies: RUMScopeDependencies( core: core, rumFeature: rumFeature - ).replacing(viewUpdatesThrottlerFactory: { NoOpRUMViewUpdatesThrottler() }), + ), dateProvider: rumFeature.configuration.dateProvider ) } diff --git a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift index 939726ee23..0fd894b903 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift @@ -1901,96 +1901,6 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(event.dd.documentVersion, 1, "It should record only one view update") } - // MARK: Suppressing number of view updates - - // swiftlint:disable opening_brace - func testGivenScopeWithViewUpdatesThrottler_whenReceivingStreamOfCommands_thenItSendsLessViewUpdatesThanScopeWithNoThrottler() throws { - let commandsIssuingViewUpdates: [(Date) -> RUMCommand] = [ - // receive resource: - { date in RUMStartResourceCommand.mockWith(resourceKey: "resource", time: date) }, - { date in RUMStopResourceCommand.mockWith(resourceKey: "resource", time: date) }, - // add action: - { date in RUMStartUserActionCommand.mockWith(time: date, actionType: .scroll) }, - { date in RUMStopUserActionCommand.mockWith(time: date, actionType: .scroll) }, - // add error: - { date in RUMAddCurrentViewErrorCommand.mockWithErrorObject(time: date) }, - // add long task: - { date in RUMAddLongTaskCommand.mockWith(time: date) }, - // receive timing: - { date in RUMAddViewTimingCommand.mockWith(time: date, timingName: .mockRandom()) }, - ] - let stopViewCommand: [(Date) -> RUMCommand] = [ - { date in RUMStopViewCommand.mockWith(time: date, identity: mockView) } - ] - - let commands = (0..<5).flatMap({ _ in commandsIssuingViewUpdates }) + stopViewCommand // loop 5 times through all commands - let timeIntervalBetweenCommands = 1.0 - let simulationDuration = timeIntervalBetweenCommands * Double(commands.count) - let samplingDuration = simulationDuration * 0.5 // at least half view updates should be skipped - - // Given - let throttler = RUMViewUpdatesThrottler(viewUpdateThreshold: samplingDuration) - let sampledWriter = FileWriterMock() - let sampledScope: RUMViewScope = .mockWith( - parent: parent, - dependencies: .mockWith( - viewUpdatesThrottlerFactory: { throttler } - ) - ) - - let noOpThrottler = NoOpRUMViewUpdatesThrottler() - let notSampledWriter = FileWriterMock() - let notSampledScope: RUMViewScope = .mockWith( - parent: parent, - dependencies: .mockWith( - viewUpdatesThrottlerFactory: { noOpThrottler } - ) - ) - - // When - func send(commands: [(Date) -> RUMCommand], to scope: RUMViewScope, writer: Writer) { - var currentTime = scope.viewStartTime - commands.forEach { command in - currentTime.addTimeInterval(timeIntervalBetweenCommands) - _ = scope.process( - command: command(currentTime), - context: context, - writer: writer - ) - } - } - - send(commands: commands, to: sampledScope, writer: sampledWriter) - send(commands: commands, to: notSampledScope, writer: notSampledWriter) - - // Then - let viewUpdatesInSampledScope = sampledWriter.events(ofType: RUMViewEvent.self) - let viewUpdatesInNotSampledScope = notSampledWriter.events(ofType: RUMViewEvent.self) - XCTAssertLessThan( - viewUpdatesInSampledScope.count, - viewUpdatesInNotSampledScope.count , - "Sampled scope should send less view updates than not sampled" - ) - - let actualSamplingRatio = Double(viewUpdatesInSampledScope.count) / Double(viewUpdatesInNotSampledScope.count) - let maxExpectedSamplingRatio = samplingDuration / simulationDuration - XCTAssertLessThan( - actualSamplingRatio, - maxExpectedSamplingRatio, - "Less than \(maxExpectedSamplingRatio * 100)% of view updates should be sampled" - ) - - let actualLastUpdate = try XCTUnwrap(viewUpdatesInSampledScope.last) - let expectedLastUpdate = try XCTUnwrap(viewUpdatesInNotSampledScope.last) - XCTAssertEqual(actualLastUpdate.view.resource.count, expectedLastUpdate.view.resource.count, "It should count all resources") - XCTAssertEqual(actualLastUpdate.view.action.count, expectedLastUpdate.view.action.count, "It should count all actions") - XCTAssertEqual(actualLastUpdate.view.error.count, expectedLastUpdate.view.error.count, "It should count all errors") - XCTAssertEqual(actualLastUpdate.view.longTask?.count, expectedLastUpdate.view.longTask?.count, "It should count all long tasks") - XCTAssertEqual(actualLastUpdate.view.customTimings?.count, expectedLastUpdate.view.customTimings?.count, "It should count all view timings") - XCTAssertTrue(actualLastUpdate.view.isActive == false, "Terminal view update must always be sent") - } - // swiftlint:enable opening_brace - // MARK: Integration with Crash Context func testWhenViewIsStarted_thenItUpdatesLastRUMViewEventInCrashContext() throws { @@ -2034,50 +1944,4 @@ class RUMViewScopeTests: XCTestCase { let rumViewSent = try XCTUnwrap(core.events(ofType: RUMViewEvent.self).last, "It should send view event") DDAssertReflectionEqual(viewEvent, rumViewSent, "It must inject sent event to crash context") } - - // MARK: Cross-platform crashes - - func testGivenScopeWithViewUpdatesThrottler_whenReceivingCrossPlatformCrash_thenItSendsViewUpdateWithUpdatedCrashCount() throws { - let commands: [(Date) -> RUMCommand] = [ - // receive resource: - { date in RUMStartResourceCommand.mockWith(resourceKey: "resource", time: date) }, { date in RUMStopResourceCommand.mockWith(resourceKey: "resource", time: date) }, - // receive error: - { date in RUMAddCurrentViewErrorCommand.mockWithErrorMessage(time: date, attributes: [CrossPlatformAttributes.errorIsCrash: true]) } - ] - let timeIntervalBetweenCommands = 1.0 - let simulationDuration = timeIntervalBetweenCommands * Double(commands.count) - let samplingDuration = simulationDuration * 0.5 // at least half view updates should be skipped - - // Given - let throttler = RUMViewUpdatesThrottler(viewUpdateThreshold: samplingDuration) - let sampledWriter = FileWriterMock() - let sampledScope: RUMViewScope = .mockWith( - parent: parent, - dependencies: .mockWith( - viewUpdatesThrottlerFactory: { throttler } - ) - ) - - // When - func send(commands: [(Date) -> RUMCommand], to scope: RUMViewScope, writer: Writer) { - var currentTime = scope.viewStartTime - commands.forEach { command in - currentTime.addTimeInterval(timeIntervalBetweenCommands) - _ = scope.process( - command: command(currentTime), - context: context, - writer: writer - ) - } - } - - send(commands: commands, to: sampledScope, writer: sampledWriter) - - // Then - let viewUpdatesInSampledScope = sampledWriter.events(ofType: RUMViewEvent.self) - XCTAssertEqual(viewUpdatesInSampledScope.count, 2, "It should send the first event and the error") - - let actualLastUpdate = try XCTUnwrap(viewUpdatesInSampledScope.last) - XCTAssertEqual(actualLastUpdate.view.crash?.count, 1, "It should contain a crash") - } } diff --git a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/Utils/RUMViewUpdatesThrottlerTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/Utils/RUMViewUpdatesThrottlerTests.swift deleted file mode 100644 index 6a549185a1..0000000000 --- a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/Utils/RUMViewUpdatesThrottlerTests.swift +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 2019-Present Datadog, Inc. - */ - -import XCTest -@testable import Datadog - -class RUMViewUpdatesThrottlerTests: XCTestCase { - private let randomViewUpdateThreshold: TimeInterval = .mockRandom(min: 1, max: 10) - private lazy var throttler = RUMViewUpdatesThrottler(viewUpdateThreshold: randomViewUpdateThreshold) - - func testItAcceptsTheFirstEvent() { - XCTAssertTrue(throttler.accept(event: .mockRandom())) - } - - func testItAcceptsTheLastEvent() { - XCTAssertTrue(throttler.accept(event: .mockRandomWith(viewIsActive: false))) - } - - func testItRejectsNextEventWhenItArrivesEarlierThanThreshold() { - let firstEvent: RUMViewEvent = .mockRandomWith( - viewIsActive: true, // not a final event - viewTimeSpent: 0, - crashCount: 0 - ) - let nextEvent: RUMViewEvent = .mockRandomWith( - viewIsActive: true, // not a final event - viewTimeSpent: randomViewUpdateThreshold.toInt64Nanoseconds - 1, - crashCount: 0 - ) - - XCTAssertTrue(throttler.accept(event: firstEvent), "It should always accepts first event") - XCTAssertFalse(throttler.accept(event: nextEvent), "It should reject next event as it arrived earlier than threshold") - } - - func testItAcceptsNextEventWhenItArrivesLaterThanThreshold() { - let firstEvent: RUMViewEvent = .mockRandomWith( - viewIsActive: true, // not a final event - viewTimeSpent: 0, - crashCount: 0 - ) - let nextEvent: RUMViewEvent = .mockRandomWith( - viewIsActive: true, // not a final event - viewTimeSpent: randomViewUpdateThreshold.toInt64Nanoseconds + 1, - crashCount: 0 - ) - - XCTAssertTrue(throttler.accept(event: firstEvent), "It should always accepts first event") - XCTAssertTrue(throttler.accept(event: nextEvent), "It should accept next event as it arrived later than threshold") - } -} diff --git a/Tests/DatadogTests/Datadog/RUMMonitorTests.swift b/Tests/DatadogTests/Datadog/RUMMonitorTests.swift index 43c9982cd4..b0328b832e 100644 --- a/Tests/DatadogTests/Datadog/RUMMonitorTests.swift +++ b/Tests/DatadogTests/Datadog/RUMMonitorTests.swift @@ -32,7 +32,7 @@ class RUMMonitorTests: XCTestCase { dependencies: RUMScopeDependencies( core: core, rumFeature: rumFeature - ).replacing(viewUpdatesThrottlerFactory: { NoOpRUMViewUpdatesThrottler() }), + ), dateProvider: rumFeature.configuration.dateProvider ) } diff --git a/Tests/DatadogTests/DatadogObjc/DDRUMMonitorTests.swift b/Tests/DatadogTests/DatadogObjc/DDRUMMonitorTests.swift index a859b7edf9..d9b8bee805 100644 --- a/Tests/DatadogTests/DatadogObjc/DDRUMMonitorTests.swift +++ b/Tests/DatadogTests/DatadogObjc/DDRUMMonitorTests.swift @@ -153,8 +153,7 @@ class DDRUMMonitorTests: XCTestCase { dependencies: RUMScopeDependencies( core: core, rumFeature: rumFeature - ) - .replacing(viewUpdatesThrottlerFactory: { NoOpRUMViewUpdatesThrottler() }), + ), dateProvider: rumFeature.configuration.dateProvider ) return DatadogObjc.DDRUMMonitor(swiftRUMMonitor: swiftMonitor) From a3bf3df85ddf66e42dbe60e1cbaf4e10c21d9aea Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 3 Jul 2023 13:26:30 +0200 Subject: [PATCH 39/87] Add podpecs to distribution pipeline --- tools/distribution/release.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/distribution/release.py b/tools/distribution/release.py index 94d6cdc73d..28c9b4f25a 100755 --- a/tools/distribution/release.py +++ b/tools/distribution/release.py @@ -127,6 +127,13 @@ if publish_to_cp: podspecs = [ CPPodspec(name='DatadogInternal'), + CPPodspec(name='DatadogCore'), + CPPodspec(name='DatadogLogs'), + CPPodspec(name='DatadogTrace'), + CPPodspec(name='DatadogRUM'), + CPPodspec(name='DatadogCrashReporting'), + CPPodspec(name='DatadogWebViewTracking'), + CPPodspec(name='DatadogObjc'), CPPodspec(name='DatadogSDK'), CPPodspec(name='DatadogSDKObjc'), CPPodspec(name='DatadogSDKCrashReporting'), From ca258e691eee894f80369a8f201cc10c698fdbff Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 3 Jul 2023 17:18:04 +0200 Subject: [PATCH 40/87] RUMM-3387 align v2 logs apis --- .../DebugLoggingViewController.swift | 3 +- Datadog/Example/ExampleAppDelegate.swift | 2 +- DatadogCore/Tests/Datadog/LoggerTests.swift | 6 +-- .../Tests/Datadog/Mocks/LogsMocks.swift | 4 +- .../Tests/DatadogObjc/DDLogsTests.swift | 4 +- .../Sources/Feature/MessageReceivers.swift | 2 +- DatadogLogs/Sources/Log/LogEventBuilder.swift | 6 +-- DatadogLogs/Sources/Logger.swift | 31 ++++++++------- DatadogLogs/Sources/RemoteLogger.swift | 4 +- .../Tests/Log/LogEventBuilderTests.swift | 10 ++--- .../Tests/LogMessageReceiverTests.swift | 2 +- DatadogLogs/Tests/LoggerTests.swift | 14 +++---- .../Tests/Mocks/LoggingFeatureMocks.swift | 4 +- DatadogLogs/Tests/RemoteLoggerTests.swift | 4 +- DatadogObjc/Sources/DDLogs+objc.swift | 39 ++++++++++--------- .../TracingWithLoggingIntegration.swift | 2 +- .../Runner/ExampleAppDelegate.swift | 2 +- 17 files changed, 73 insertions(+), 66 deletions(-) diff --git a/Datadog/Example/Debugging/DebugLoggingViewController.swift b/Datadog/Example/Debugging/DebugLoggingViewController.swift index 1f226311e5..498eca828f 100644 --- a/Datadog/Example/Debugging/DebugLoggingViewController.swift +++ b/Datadog/Example/Debugging/DebugLoggingViewController.swift @@ -94,7 +94,8 @@ class DebugLoggingViewController: UIViewController { return Logger.create( with: Logger.Configuration( name: "stress-logger-\(index)", - sendNetworkInfo: true + networkInfoEnabled + : true ) ) } diff --git a/Datadog/Example/ExampleAppDelegate.swift b/Datadog/Example/ExampleAppDelegate.swift index 76f0c7142c..032d1a562e 100644 --- a/Datadog/Example/ExampleAppDelegate.swift +++ b/Datadog/Example/ExampleAppDelegate.swift @@ -45,7 +45,7 @@ class ExampleAppDelegate: UIResponder, UIApplicationDelegate { logger = Logger.create( with: Logger.Configuration( name: "logger-name", - sendNetworkInfo: true, + networkInfoEnabled: true, consoleLogFormat: .shortWith(prefix: "[iOS App] ") ) ) diff --git a/DatadogCore/Tests/Datadog/LoggerTests.swift b/DatadogCore/Tests/Datadog/LoggerTests.swift index 48361119e7..715f1ffe73 100644 --- a/DatadogCore/Tests/Datadog/LoggerTests.swift +++ b/DatadogCore/Tests/Datadog/LoggerTests.swift @@ -79,7 +79,7 @@ class LoggerTests: XCTestCase { with: Logger.Configuration( service: "custom-service-name", name: "custom-logger-name", - sendNetworkInfo: true, + networkInfoEnabled: true, consoleLogFormat: .short ), in: core @@ -318,7 +318,7 @@ class LoggerTests: XCTestCase { let feature: LogsFeature = .mockAny() try core.register(feature: feature) - let logger = Logger.create(with: Logger.Configuration(sendNetworkInfo: true), in: core) + let logger = Logger.create(with: Logger.Configuration(networkInfoEnabled: true), in: core) // simulate entering cellular service range core.context.carrierInfo = .mockWith( @@ -353,7 +353,7 @@ class LoggerTests: XCTestCase { let feature: LogsFeature = .mockAny() try core.register(feature: feature) - let logger = Logger.create(with: Logger.Configuration(sendNetworkInfo: true), in: core) + let logger = Logger.create(with: Logger.Configuration(networkInfoEnabled: true), in: core) // simulate reachable network core.context.networkConnectionInfo = .mockWith( diff --git a/DatadogCore/Tests/Datadog/Mocks/LogsMocks.swift b/DatadogCore/Tests/Datadog/Mocks/LogsMocks.swift index 7b03f772ff..5e728108ce 100644 --- a/DatadogCore/Tests/Datadog/Mocks/LogsMocks.swift +++ b/DatadogCore/Tests/Datadog/Mocks/LogsMocks.swift @@ -231,14 +231,14 @@ extension LogEventBuilder: AnyMockable { public static func mockWith( service: String = .mockAny(), loggerName: String = .mockAny(), - sendNetworkInfo: Bool = .mockAny(), + networkInfoEnabled: Bool = .mockAny(), eventMapper: LogEventMapper? = nil, deviceInfo: DeviceInfo = .mockAny() ) -> LogEventBuilder { return LogEventBuilder( service: service, loggerName: loggerName, - sendNetworkInfo: sendNetworkInfo, + networkInfoEnabled: networkInfoEnabled, eventMapper: eventMapper ) } diff --git a/DatadogCore/Tests/DatadogObjc/DDLogsTests.swift b/DatadogCore/Tests/DatadogObjc/DDLogsTests.swift index 592aab4163..d2521338fc 100644 --- a/DatadogCore/Tests/DatadogObjc/DDLogsTests.swift +++ b/DatadogCore/Tests/DatadogObjc/DDLogsTests.swift @@ -208,13 +208,13 @@ class DDLogsTests: XCTestCase { let objcConfig = DDLoggerConfiguration() objcConfig.name = "logger-name" objcConfig.service = "service-name" - objcConfig.sendNetworkInfo = true + objcConfig.networkInfoEnabled = true objcConfig.remoteSampleRate = 50 objcConfig.printLogsToConsole = true XCTAssertEqual(objcConfig.configuration.name, "logger-name") XCTAssertEqual(objcConfig.configuration.service, "service-name") - XCTAssertTrue(objcConfig.configuration.sendNetworkInfo) + XCTAssertTrue(objcConfig.configuration.networkInfoEnabled) XCTAssertEqual(objcConfig.configuration.remoteSampleRate, 50) XCTAssertNotNil(objcConfig.configuration.consoleLogFormat) } diff --git a/DatadogLogs/Sources/Feature/MessageReceivers.swift b/DatadogLogs/Sources/Feature/MessageReceivers.swift index b299c77955..f181dc8dcc 100644 --- a/DatadogLogs/Sources/Feature/MessageReceivers.swift +++ b/DatadogLogs/Sources/Feature/MessageReceivers.swift @@ -48,7 +48,7 @@ internal struct LogMessageReceiver: FeatureMessageReceiver { let builder = LogEventBuilder( service: attributes["service"] ?? context.service, loggerName: loggerName, - sendNetworkInfo: attributes["sendNetworkInfo"] ?? false, + networkInfoEnabled: attributes["networkInfoEnabled"] ?? false, eventMapper: logEventMapper ) diff --git a/DatadogLogs/Sources/Log/LogEventBuilder.swift b/DatadogLogs/Sources/Log/LogEventBuilder.swift index 3ace284c33..7ca584aba6 100644 --- a/DatadogLogs/Sources/Log/LogEventBuilder.swift +++ b/DatadogLogs/Sources/Log/LogEventBuilder.swift @@ -15,7 +15,7 @@ internal struct LogEventBuilder { /// The `logger.name` value for logs. let loggerName: String? /// Whether to send the network info in `network.client.*` log attributes. - let sendNetworkInfo: Bool + let networkInfoEnabled: Bool /// Allows for modifying (or dropping) logs before they get sent. let eventMapper: LogEventMapper? @@ -79,8 +79,8 @@ internal struct LogEventBuilder { email: userInfo.email, extraInfo: userInfo.extraInfo ), - networkConnectionInfo: sendNetworkInfo ? context.networkConnectionInfo : nil, - mobileCarrierInfo: sendNetworkInfo ? context.carrierInfo : nil, + networkConnectionInfo: networkInfoEnabled ? context.networkConnectionInfo : nil, + mobileCarrierInfo: networkInfoEnabled ? context.carrierInfo : nil, attributes: attributes, tags: !tags.isEmpty ? Array(tags) : nil ) diff --git a/DatadogLogs/Sources/Logger.swift b/DatadogLogs/Sources/Logger.swift index ea98ae8292..b96b731d7b 100644 --- a/DatadogLogs/Sources/Logger.swift +++ b/DatadogLogs/Sources/Logger.swift @@ -25,25 +25,28 @@ public struct Logger { public var name: String? /// Enriches logs with network connection info. + /// /// This means: reachability status, connection type, mobile carrier name and many more will be added to each log. /// For full list of network info attributes see `NetworkConnectionInfo` and `CarrierInfo`. /// /// `false` by default. - public var sendNetworkInfo: Bool + public var networkInfoEnabled: Bool /// Enables the logs integration with RUM. + /// /// If enabled all the logs will be enriched with the current RUM View information and /// it will be possible to see all the logs sent during a specific View lifespan in the RUM Explorer. /// /// `true` by default. - public var bundleWithRUM: Bool + public var bundleWithRumEnabled: Bool /// Enables the logs integration with active span API from Tracing. + /// /// If enabled all the logs will be bundled with the `DatadogTracer.shared().activeSpan` trace and /// it will be possible to see all the logs sent during that specific trace. /// /// `true` by default. - public var bundleWithTrace: Bool + public var bundleWithTraceEnabled: Bool /// Sets the sample rate for remote logging. /// @@ -77,27 +80,27 @@ public struct Logger { /// - Parameters: /// - service: The service name (default value is set to application bundle identifier) /// - name: The logger custom name (default value is set to main bundle identifier) - /// - sendNetworkInfo: Enriches logs with network connection info. `false` by default. + /// - networkInfoEnabled: Enriches logs with network connection info. `false` by default. /// - bundleWithRUM: Enables the logs integration with RUM. `true` by default. - /// - bundleWithTrace: Enables the logs integration with active span API from Tracing. `true` by default + /// - bundleWithTraceEnabled: Enables the logs integration with active span API from Tracing. `true` by default /// - remoteSampleRate: The sample rate for remote logging. **When set to `0`, no log entries will be sent to Datadog servers.** /// - remoteLogThreshold: Set the minimum log level reported to Datadog servers. .debug by default. /// - consoleLogFormat: Format to use when printing logs to console - either `.short` or `.json`. public init( service: String? = nil, name: String? = nil, - sendNetworkInfo: Bool = false, - bundleWithRUM: Bool = true, - bundleWithTrace: Bool = true, + networkInfoEnabled: Bool = false, + bundleWithRumEnabled: Bool = true, + bundleWithTraceEnabled: Bool = true, remoteSampleRate: Float = 100, remoteLogThreshold: LogLevel = .debug, consoleLogFormat: ConsoleLogFormat? = nil ) { self.service = service self.name = name - self.sendNetworkInfo = sendNetworkInfo - self.bundleWithRUM = bundleWithRUM - self.bundleWithTrace = bundleWithTrace + self.networkInfoEnabled = networkInfoEnabled + self.bundleWithRumEnabled = bundleWithRumEnabled + self.bundleWithTraceEnabled = bundleWithTraceEnabled self.remoteSampleRate = remoteSampleRate self.remoteLogThreshold = remoteLogThreshold self.consoleLogFormat = consoleLogFormat @@ -155,14 +158,14 @@ public struct Logger { configuration: RemoteLogger.Configuration( service: configuration.service, name: configuration.name, - sendNetworkInfo: configuration.sendNetworkInfo, + networkInfoEnabled: configuration.networkInfoEnabled, threshold: configuration.remoteLogThreshold, eventMapper: feature.logEventMapper, sampler: Sampler(samplingRate: debug ? 100 : configuration.remoteSampleRate) ), dateProvider: feature.dateProvider, - rumContextIntegration: configuration.bundleWithRUM, - activeSpanIntegration: configuration.bundleWithTrace + rumContextIntegration: configuration.bundleWithRumEnabled, + activeSpanIntegration: configuration.bundleWithTraceEnabled ) }() diff --git a/DatadogLogs/Sources/RemoteLogger.swift b/DatadogLogs/Sources/RemoteLogger.swift index 85c32dacd1..d9671d3e14 100644 --- a/DatadogLogs/Sources/RemoteLogger.swift +++ b/DatadogLogs/Sources/RemoteLogger.swift @@ -16,7 +16,7 @@ internal final class RemoteLogger: LoggerProtocol { /// The `logger.name` value for logs. let name: String? /// Whether to send the network info in `network.client.*` log attributes. - let sendNetworkInfo: Bool + let networkInfoEnabled: Bool /// Only logs equal or above this threshold will be sent. let threshold: LogLevel /// Allows for modifying (or dropping) logs before they get sent. @@ -130,7 +130,7 @@ internal final class RemoteLogger: LoggerProtocol { let builder = LogEventBuilder( service: self.configuration.service ?? context.service, loggerName: self.configuration.name, - sendNetworkInfo: self.configuration.sendNetworkInfo, + networkInfoEnabled: self.configuration.networkInfoEnabled, eventMapper: self.configuration.eventMapper ) diff --git a/DatadogLogs/Tests/Log/LogEventBuilderTests.swift b/DatadogLogs/Tests/Log/LogEventBuilderTests.swift index 479779350a..b3ca4f0e08 100644 --- a/DatadogLogs/Tests/Log/LogEventBuilderTests.swift +++ b/DatadogLogs/Tests/Log/LogEventBuilderTests.swift @@ -28,7 +28,7 @@ class LogEventBuilderTests: XCTestCase { let builder = LogEventBuilder( service: randomService, loggerName: randomLoggerName, - sendNetworkInfo: .mockAny(), + networkInfoEnabled: .mockAny(), eventMapper: nil ) @@ -92,7 +92,7 @@ class LogEventBuilderTests: XCTestCase { let builder = LogEventBuilder( service: .mockAny(), loggerName: .mockAny(), - sendNetworkInfo: true, + networkInfoEnabled: true, eventMapper: nil ) @@ -131,7 +131,7 @@ class LogEventBuilderTests: XCTestCase { let builder = LogEventBuilder( service: .mockAny(), loggerName: .mockAny(), - sendNetworkInfo: false, + networkInfoEnabled: false, eventMapper: nil ) @@ -167,7 +167,7 @@ class LogEventBuilderTests: XCTestCase { let builder = LogEventBuilder( service: .mockAny(), loggerName: .mockAny(), - sendNetworkInfo: .mockAny(), + networkInfoEnabled: .mockAny(), eventMapper: SyncLogEventMapper { log in var mutableLog = log mutableLog.message = "modified message" @@ -202,7 +202,7 @@ class LogEventBuilderTests: XCTestCase { let builder = LogEventBuilder( service: .mockAny(), loggerName: .mockAny(), - sendNetworkInfo: .mockAny(), + networkInfoEnabled: .mockAny(), eventMapper: SyncLogEventMapper { _ in return nil } diff --git a/DatadogLogs/Tests/LogMessageReceiverTests.swift b/DatadogLogs/Tests/LogMessageReceiverTests.swift index 3cf7be72ce..4f51382b11 100644 --- a/DatadogLogs/Tests/LogMessageReceiverTests.swift +++ b/DatadogLogs/Tests/LogMessageReceiverTests.swift @@ -96,7 +96,7 @@ class LogMessageReceiverTests: XCTestCase { "error": DDError.mockAny(), "userAttributes": ["user": "attribute"], "internalAttributes": ["internal": "attribute"], - "sendNetworkInfo": true + "networkInfoEnabled": true ] ) ) diff --git a/DatadogLogs/Tests/LoggerTests.swift b/DatadogLogs/Tests/LoggerTests.swift index f64be8164e..6c61497eec 100644 --- a/DatadogLogs/Tests/LoggerTests.swift +++ b/DatadogLogs/Tests/LoggerTests.swift @@ -30,7 +30,7 @@ class LoggerTests: XCTestCase { let remoteLogger = try XCTUnwrap(logger as? RemoteLogger) XCTAssertNil(remoteLogger.configuration.service) XCTAssertNil(remoteLogger.configuration.name) - XCTAssertFalse(remoteLogger.configuration.sendNetworkInfo) + XCTAssertFalse(remoteLogger.configuration.networkInfoEnabled) XCTAssertEqual(remoteLogger.configuration.threshold, .debug) XCTAssertEqual(remoteLogger.configuration.sampler.samplingRate, 100) XCTAssertNil(remoteLogger.configuration.eventMapper) @@ -44,7 +44,7 @@ class LoggerTests: XCTestCase { let logger2 = Logger.create( with: Logger.Configuration( - bundleWithRUM: false + bundleWithRumEnabled: false ), in: core ) @@ -57,7 +57,7 @@ class LoggerTests: XCTestCase { let logger2 = Logger.create( with: Logger.Configuration( - bundleWithTrace: false + bundleWithTraceEnabled: false ), in: core ) @@ -69,9 +69,9 @@ class LoggerTests: XCTestCase { with: Logger.Configuration( service: "custom-service-name", name: "custom-logger-name", - sendNetworkInfo: true, - bundleWithRUM: false, - bundleWithTrace: false, + networkInfoEnabled: true, + bundleWithRumEnabled: false, + bundleWithTraceEnabled: false, remoteSampleRate: 50, remoteLogThreshold: .error ), @@ -81,7 +81,7 @@ class LoggerTests: XCTestCase { let remoteLogger = try XCTUnwrap(logger as? RemoteLogger) XCTAssertEqual(remoteLogger.configuration.service, "custom-service-name") XCTAssertEqual(remoteLogger.configuration.name, "custom-logger-name") - XCTAssertTrue(remoteLogger.configuration.sendNetworkInfo) + XCTAssertTrue(remoteLogger.configuration.networkInfoEnabled) XCTAssertEqual(remoteLogger.configuration.threshold, .error) XCTAssertNil(remoteLogger.configuration.eventMapper) XCTAssertFalse(remoteLogger.rumContextIntegration) diff --git a/DatadogLogs/Tests/Mocks/LoggingFeatureMocks.swift b/DatadogLogs/Tests/Mocks/LoggingFeatureMocks.swift index 81d26fcd01..84e1fe9dc4 100644 --- a/DatadogLogs/Tests/Mocks/LoggingFeatureMocks.swift +++ b/DatadogLogs/Tests/Mocks/LoggingFeatureMocks.swift @@ -225,14 +225,14 @@ extension LogEventBuilder: AnyMockable { public static func mockWith( service: String = .mockAny(), loggerName: String = .mockAny(), - sendNetworkInfo: Bool = .mockAny(), + networkInfoEnabled: Bool = .mockAny(), eventMapper: LogEventMapper? = nil, deviceInfo: DeviceInfo = .mockAny() ) -> LogEventBuilder { return LogEventBuilder( service: service, loggerName: loggerName, - sendNetworkInfo: sendNetworkInfo, + networkInfoEnabled: networkInfoEnabled, eventMapper: eventMapper ) } diff --git a/DatadogLogs/Tests/RemoteLoggerTests.swift b/DatadogLogs/Tests/RemoteLoggerTests.swift index ee586c932b..8d3fb2fddb 100644 --- a/DatadogLogs/Tests/RemoteLoggerTests.swift +++ b/DatadogLogs/Tests/RemoteLoggerTests.swift @@ -46,7 +46,7 @@ class RemoteLoggerTests: XCTestCase { configuration: .init( service: "logger.tests", name: "TestLogger", - sendNetworkInfo: false, + networkInfoEnabled: false, threshold: LogLevel.info, eventMapper: nil, sampler: Sampler(samplingRate: 100.0) @@ -83,7 +83,7 @@ class RemoteLoggerTests: XCTestCase { configuration: .init( service: "logger.tests", name: "TestLogger", - sendNetworkInfo: false, + networkInfoEnabled: false, threshold: LogLevel.info, eventMapper: nil, sampler: Sampler(samplingRate: 100.0) diff --git a/DatadogObjc/Sources/DDLogs+objc.swift b/DatadogObjc/Sources/DDLogs+objc.swift index 9c04d00976..624351e147 100644 --- a/DatadogObjc/Sources/DDLogs+objc.swift +++ b/DatadogObjc/Sources/DDLogs+objc.swift @@ -102,33 +102,36 @@ public class DDLoggerConfiguration: NSObject { } /// Enriches logs with network connection info. + /// /// This means: reachability status, connection type, mobile carrier name and many more will be added to each log. /// For full list of network info attributes see `NetworkConnectionInfo` and `CarrierInfo`. /// /// `false` by default - @objc public var sendNetworkInfo: Bool { - get { configuration.sendNetworkInfo } - set { configuration.sendNetworkInfo = newValue } + @objc public var networkInfoEnabled: Bool { + get { configuration.networkInfoEnabled } + set { configuration.networkInfoEnabled = newValue } } /// Enables the logs integration with RUM. + /// /// If enabled all the logs will be enriched with the current RUM View information and /// it will be possible to see all the logs sent during a specific View lifespan in the RUM Explorer. /// /// `true` by default - @objc public var bundleWithRUM: Bool { - get { configuration.bundleWithRUM } - set { configuration.bundleWithRUM = newValue } + @objc public var bundleWithRumEnabled: Bool { + get { configuration.bundleWithRumEnabled } + set { configuration.bundleWithRumEnabled = newValue } } /// Enables the logs integration with active span API from Tracing. + /// /// If enabled all the logs will be bundled with the `DatadogTracer.shared().activeSpan` trace and /// it will be possible to see all the logs sent during that specific trace. /// /// `true` by default - @objc public var bundleWithTrace: Bool { - get { configuration.bundleWithTrace } - set { configuration.bundleWithTrace = newValue } + @objc public var bundleWithTraceEnabled: Bool { + get { configuration.bundleWithTraceEnabled } + set { configuration.bundleWithTraceEnabled = newValue } } /// Sets the sampling rate for logging. @@ -167,9 +170,9 @@ public class DDLoggerConfiguration: NSObject { /// - Parameters: /// - service: The service name (default value is set to application bundle identifier) /// - name: The logger custom name (default value is set to main bundle identifier) - /// - sendNetworkInfo: Enriches logs with network connection info. `false` by default. - /// - bundleWithRUM: Enables the logs integration with RUM. `true` by default. - /// - bundleWithTrace: Enables the logs integration with active span API from Tracing. `true` by default + /// - networkInfoEnabled: Enriches logs with network connection info. `false` by default. + /// - bundleWithRumEnabled: Enables the logs integration with RUM. `true` by default. + /// - bundleWithTraceEnabled: Enables the logs integration with active span API from Tracing. `true` by default /// - remoteSampleRate: The sample rate for remote logging. **When set to `0`, no log entries will be sent to Datadog servers.** /// - remoteLogThreshold: Set the minimum log level reported to Datadog servers. .debug by default. /// - printLogsToConsole: Format to use when printing logs to console - either `.short` or `.json`. @@ -177,9 +180,9 @@ public class DDLoggerConfiguration: NSObject { public init( service: String? = nil, name: String? = nil, - sendNetworkInfo: Bool = false, - bundleWithRUM: Bool = true, - bundleWithTrace: Bool = true, + networkInfoEnabled: Bool = false, + bundleWithRumEnabled: Bool = true, + bundleWithTraceEnabled: Bool = true, remoteSampleRate: Float = 100, remoteLogThreshold: DDLogLevel = .debug, printLogsToConsole: Bool = false @@ -187,9 +190,9 @@ public class DDLoggerConfiguration: NSObject { configuration = .init( service: service, name: name, - sendNetworkInfo: sendNetworkInfo, - bundleWithRUM: bundleWithRUM, - bundleWithTrace: bundleWithTrace, + networkInfoEnabled: networkInfoEnabled, + bundleWithRumEnabled: bundleWithRumEnabled, + bundleWithTraceEnabled: bundleWithTraceEnabled, remoteSampleRate: remoteSampleRate, remoteLogThreshold: remoteLogThreshold.swift, consoleLogFormat: printLogsToConsole ? .short : nil diff --git a/DatadogTrace/Sources/Integrations/TracingWithLoggingIntegration.swift b/DatadogTrace/Sources/Integrations/TracingWithLoggingIntegration.swift index b3dd3b50a4..778d76076e 100644 --- a/DatadogTrace/Sources/Integrations/TracingWithLoggingIntegration.swift +++ b/DatadogTrace/Sources/Integrations/TracingWithLoggingIntegration.swift @@ -86,7 +86,7 @@ internal struct TracingWithLoggingIntegration { "error": extractedError, "userAttributes": AnyEncodable(userAttributes), "internalAttributes": internalAttributes, - "sendNetworkInfo": sendNetworkInfo + "networkInfoEnabled": sendNetworkInfo ] ), else: fallback diff --git a/IntegrationTests/Runner/ExampleAppDelegate.swift b/IntegrationTests/Runner/ExampleAppDelegate.swift index 9416986839..ac34ee1703 100644 --- a/IntegrationTests/Runner/ExampleAppDelegate.swift +++ b/IntegrationTests/Runner/ExampleAppDelegate.swift @@ -46,7 +46,7 @@ class ExampleAppDelegate: UIResponder, UIApplicationDelegate { logger = Logger.create( with: Logger.Configuration( name: "logger-name", - sendNetworkInfo: true, + networkInfoEnabled: true, consoleLogFormat: .shortWith(prefix: "[iOS App] ") ) ) From c8f9afb1af848b6c8087bf840e033547666d15dd Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 3 Jul 2023 17:36:57 +0200 Subject: [PATCH 41/87] RUMM-3387 align v2 trace apis --- Datadog/Example/ExampleAppDelegate.swift | 2 +- .../TracingWithLoggingIntegrationTests.swift | 6 +++--- .../Datadog/Mocks/TracingFeatureMocks.swift | 8 ++++---- DatadogCore/Tests/Datadog/TracerTests.swift | 6 +++--- .../TracingURLSessionHandlerTests.swift | 4 ++-- .../DDTraceConfigurationTests.swift | 12 ++++++------ .../ObjcAPITests/DDTrace+apiTests.m | 8 ++++---- DatadogObjc/Sources/Trace+objc.swift | 12 ++++++------ DatadogTrace/Sources/DDSpan.swift | 2 +- DatadogTrace/Sources/DatadogTracer.swift | 6 +++--- .../Sources/Feature/MessageReceivers.swift | 8 ++++---- .../Sources/Feature/TraceFeature.swift | 6 +++--- .../TracingWithLoggingIntegration.swift | 8 ++++---- .../Sources/Span/SpanEventBuilder.swift | 6 +++--- DatadogTrace/Sources/TraceConfiguration.swift | 16 ++++++++-------- .../Tests/ContextMessageReceiverTests.swift | 6 +++--- .../Tests/TraceConfigurationTests.swift | 4 ++-- DatadogTrace/Tests/TraceTests.swift | 18 +++++++++--------- DatadogTrace/Tests/TracingFeatureMocks.swift | 12 ++++++------ .../Tests/TracingURLSessionHandlerTests.swift | 8 ++++---- .../Scenarios/Tracing/TracingScenarios.swift | 4 ++-- .../TrackingConsentScenarios.swift | 2 +- 22 files changed, 82 insertions(+), 82 deletions(-) diff --git a/Datadog/Example/ExampleAppDelegate.swift b/Datadog/Example/ExampleAppDelegate.swift index 032d1a562e..9c50928077 100644 --- a/Datadog/Example/ExampleAppDelegate.swift +++ b/Datadog/Example/ExampleAppDelegate.swift @@ -73,7 +73,7 @@ class ExampleAppDelegate: UIResponder, UIApplicationDelegate { // Enable Trace Trace.enable( with: Trace.Configuration( - sendNetworkInfo: true, + networkInfoEnabled: true, customEndpoint: Environment.readCustomTraceURL() ) ) diff --git a/DatadogCore/Tests/Datadog/FeaturesIntegration/TracingWithLoggingIntegrationTests.swift b/DatadogCore/Tests/Datadog/FeaturesIntegration/TracingWithLoggingIntegrationTests.swift index 38da523730..26f221fb06 100644 --- a/DatadogCore/Tests/Datadog/FeaturesIntegration/TracingWithLoggingIntegrationTests.swift +++ b/DatadogCore/Tests/Datadog/FeaturesIntegration/TracingWithLoggingIntegrationTests.swift @@ -29,7 +29,7 @@ class TracingWithLoggingIntegrationTests: XCTestCase { core.expectation = expectation(description: "Send log") // Given - let integration = TracingWithLoggingIntegration(core: core, service: .mockAny(), sendNetworkInfo: .mockAny()) + let integration = TracingWithLoggingIntegration(core: core, service: .mockAny(), networkInfoEnabled: .mockAny()) // When integration.writeLog( @@ -67,7 +67,7 @@ class TracingWithLoggingIntegrationTests: XCTestCase { core.expectation?.expectedFulfillmentCount = 3 // Given - let integration = TracingWithLoggingIntegration(core: core, service: .mockAny(), sendNetworkInfo: .mockAny()) + let integration = TracingWithLoggingIntegration(core: core, service: .mockAny(), networkInfoEnabled: .mockAny()) // When integration.writeLog( @@ -106,7 +106,7 @@ class TracingWithLoggingIntegrationTests: XCTestCase { core.expectation = expectation(description: "Send log") // Given - let integration = TracingWithLoggingIntegration(core: core, service: .mockAny(), sendNetworkInfo: .mockAny()) + let integration = TracingWithLoggingIntegration(core: core, service: .mockAny(), networkInfoEnabled: .mockAny()) // When integration.writeLog( diff --git a/DatadogCore/Tests/Datadog/Mocks/TracingFeatureMocks.swift b/DatadogCore/Tests/Datadog/Mocks/TracingFeatureMocks.swift index 481fd56ee2..a61a3c9e90 100644 --- a/DatadogCore/Tests/Datadog/Mocks/TracingFeatureMocks.swift +++ b/DatadogCore/Tests/Datadog/Mocks/TracingFeatureMocks.swift @@ -95,7 +95,7 @@ extension DatadogTracer { sampler: Sampler = .mockKeepAll(), tags: [String: Encodable] = [:], service: String? = nil, - sendNetworkInfo: Bool = true, + networkInfoEnabled: Bool = true, spanEventMapper: ((SpanEvent) -> SpanEvent)? = nil, tracingUUIDGenerator: TraceIDGenerator = DefaultTraceIDGenerator(), dateProvider: DateProvider = SystemDateProvider(), @@ -107,7 +107,7 @@ extension DatadogTracer { sampler: sampler, tags: tags, service: service, - sendNetworkInfo: sendNetworkInfo, + networkInfoEnabled: networkInfoEnabled, spanEventMapper: spanEventMapper, tracingUUIDGenerator: tracingUUIDGenerator, dateProvider: dateProvider, @@ -122,13 +122,13 @@ extension TracingWithLoggingIntegration { return TracingWithLoggingIntegration( core: NOPDatadogCore(), service: .mockAny(), - sendNetworkInfo: .mockAny() + networkInfoEnabled: .mockAny() ) } } extension ContextMessageReceiver { static func mockAny() -> ContextMessageReceiver { - return ContextMessageReceiver(bundleWithRUM: true) + return ContextMessageReceiver(bundleWithRumEnabled: true) } } diff --git a/DatadogCore/Tests/Datadog/TracerTests.swift b/DatadogCore/Tests/Datadog/TracerTests.swift index 7ee0e104e5..84adda00ee 100644 --- a/DatadogCore/Tests/Datadog/TracerTests.swift +++ b/DatadogCore/Tests/Datadog/TracerTests.swift @@ -81,7 +81,7 @@ class TracerTests: XCTestCase { func testSendingSpanWithCustomizedTracer() throws { config.service = "custom-service-name" - config.sendNetworkInfo = true + config.networkInfoEnabled = true Trace.enable(with: config, in: core) let tracer = Tracer.shared(in: core) @@ -390,7 +390,7 @@ class TracerTests: XCTestCase { carrierInfo: nil ) - config.sendNetworkInfo = true + config.networkInfoEnabled = true Trace.enable(with: config, in: core) let tracer = Tracer.shared(in: core).dd @@ -427,7 +427,7 @@ class TracerTests: XCTestCase { func testSendingNetworkConnectionInfoWhenReachabilityChanges() throws { core.context = .mockWith(networkConnectionInfo: nil) - config.sendNetworkInfo = true + config.networkInfoEnabled = true Trace.enable(with: config, in: core) let tracer = Tracer.shared(in: core).dd diff --git a/DatadogCore/Tests/Datadog/Tracing/TracingURLSessionHandlerTests.swift b/DatadogCore/Tests/Datadog/Tracing/TracingURLSessionHandlerTests.swift index 25c43597a1..dad254f5d4 100644 --- a/DatadogCore/Tests/Datadog/Tracing/TracingURLSessionHandlerTests.swift +++ b/DatadogCore/Tests/Datadog/Tracing/TracingURLSessionHandlerTests.swift @@ -20,7 +20,7 @@ class TracingURLSessionHandlerTests: XCTestCase { override func setUp() { super.setUp() - let receiver = ContextMessageReceiver(bundleWithRUM: true) + let receiver = ContextMessageReceiver(bundleWithRumEnabled: true) core = PassthroughCoreMock(messageReceiver: CombinedFeatureMessageReceiver([ LogMessageReceiver.mockAny(), receiver @@ -29,7 +29,7 @@ class TracingURLSessionHandlerTests: XCTestCase { tracer = .mockWith( core: core, tracingUUIDGenerator: RelativeTracingUUIDGenerator(startingFrom: 1, advancingByCount: 0), - loggingIntegration: TracingWithLoggingIntegration(core: core, service: .mockAny(), sendNetworkInfo: .mockAny()) + loggingIntegration: TracingWithLoggingIntegration(core: core, service: .mockAny(), networkInfoEnabled: .mockAny()) ) handler = TracingURLSessionHandler( diff --git a/DatadogCore/Tests/DatadogObjc/DDTraceConfigurationTests.swift b/DatadogCore/Tests/DatadogObjc/DDTraceConfigurationTests.swift index 4f0ba8e2f5..16957ca9a5 100644 --- a/DatadogCore/Tests/DatadogObjc/DDTraceConfigurationTests.swift +++ b/DatadogCore/Tests/DatadogObjc/DDTraceConfigurationTests.swift @@ -54,16 +54,16 @@ class DDTraceConfigurationTests: XCTestCase { func testBundleWithRUM() { let random: Bool = .mockRandom() - objc.bundleWithRUM = random - XCTAssertEqual(objc.bundleWithRUM, random) - XCTAssertEqual(swift.bundleWithRUM, random) + objc.bundleWithRumEnabled = random + XCTAssertEqual(objc.bundleWithRumEnabled, random) + XCTAssertEqual(swift.bundleWithRumEnabled, random) } func testSendNetworkInfo() { let random: Bool = .mockRandom() - objc.sendNetworkInfo = random - XCTAssertEqual(objc.sendNetworkInfo, random) - XCTAssertEqual(swift.sendNetworkInfo, random) + objc.networkInfoEnabled = random + XCTAssertEqual(objc.networkInfoEnabled, random) + XCTAssertEqual(swift.networkInfoEnabled, random) } func testCustomEndpoint() { diff --git a/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDTrace+apiTests.m b/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDTrace+apiTests.m index 06899bda9a..33a1e83345 100644 --- a/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDTrace+apiTests.m +++ b/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDTrace+apiTests.m @@ -46,11 +46,11 @@ - (void)testDDTraceConfigurationAPI { tracing = [[DDTraceFirstPartyHostsTracing alloc] initWithHostsWithHeaderTypes:@{} sampleRate:20]; DDTraceURLSessionTracking *urlSessionTracking = [[DDTraceURLSessionTracking alloc] initWithFirstPartyHostsTracing:tracing]; - config.bundleWithRUM = NO; - XCTAssertFalse(config.bundleWithRUM); + config.bundleWithRumEnabled = NO; + XCTAssertFalse(config.bundleWithRumEnabled); - config.sendNetworkInfo = YES; - XCTAssertTrue(config.sendNetworkInfo); + config.networkInfoEnabled = YES; + XCTAssertTrue(config.networkInfoEnabled); XCTAssertNil(config.customEndpoint); config.customEndpoint = [NSURL new]; diff --git a/DatadogObjc/Sources/Trace+objc.swift b/DatadogObjc/Sources/Trace+objc.swift index c753fa9fa5..88d96e7101 100644 --- a/DatadogObjc/Sources/Trace+objc.swift +++ b/DatadogObjc/Sources/Trace+objc.swift @@ -37,14 +37,14 @@ public class DDTraceConfiguration: NSObject { swiftConfig.urlSessionTracking = tracking.swiftConfig } - @objc public var bundleWithRUM: Bool { - set { swiftConfig.bundleWithRUM = newValue } - get { swiftConfig.bundleWithRUM } + @objc public var bundleWithRumEnabled: Bool { + set { swiftConfig.bundleWithRumEnabled = newValue } + get { swiftConfig.bundleWithRumEnabled } } - @objc public var sendNetworkInfo: Bool { - set { swiftConfig.sendNetworkInfo = newValue } - get { swiftConfig.sendNetworkInfo } + @objc public var networkInfoEnabled: Bool { + set { swiftConfig.networkInfoEnabled = newValue } + get { swiftConfig.networkInfoEnabled } } @objc public var customEndpoint: URL? { diff --git a/DatadogTrace/Sources/DDSpan.swift b/DatadogTrace/Sources/DDSpan.swift index d76be807ac..c2411c95c2 100644 --- a/DatadogTrace/Sources/DDSpan.swift +++ b/DatadogTrace/Sources/DDSpan.swift @@ -147,7 +147,7 @@ internal class DDSpan: OTSpan { let event: SpanEvent = self.queue.sync { let builder = SpanEventBuilder( serviceName: self.ddTracer.service, - sendNetworkInfo: self.ddTracer.sendNetworkInfo, + networkInfoEnabled: self.ddTracer.networkInfoEnabled, eventsMapper: self.ddTracer.spanEventMapper ) diff --git a/DatadogTrace/Sources/DatadogTracer.swift b/DatadogTrace/Sources/DatadogTracer.swift index 1d9641b0ee..16acbb505d 100644 --- a/DatadogTrace/Sources/DatadogTracer.swift +++ b/DatadogTrace/Sources/DatadogTracer.swift @@ -13,7 +13,7 @@ internal class DatadogTracer: OTTracer { /// Global tags configured for Trace feature. let tags: [String: Encodable] let service: String? - let sendNetworkInfo: Bool + let networkInfoEnabled: Bool let spanEventMapper: ((SpanEvent) -> SpanEvent)? /// Queue ensuring thread-safety of the `Tracer` and `DDSpan` operations. let queue: DispatchQueue @@ -44,7 +44,7 @@ internal class DatadogTracer: OTTracer { sampler: Sampler, tags: [String: Encodable], service: String?, - sendNetworkInfo: Bool, + networkInfoEnabled: Bool, spanEventMapper: ((SpanEvent) -> SpanEvent)?, tracingUUIDGenerator: TraceIDGenerator, dateProvider: DateProvider, @@ -54,7 +54,7 @@ internal class DatadogTracer: OTTracer { self.core = core self.tags = tags self.service = service - self.sendNetworkInfo = sendNetworkInfo + self.networkInfoEnabled = networkInfoEnabled self.spanEventMapper = spanEventMapper self.queue = DispatchQueue( label: "com.datadoghq.tracer", diff --git a/DatadogTrace/Sources/Feature/MessageReceivers.swift b/DatadogTrace/Sources/Feature/MessageReceivers.swift index 4774be8d11..8c3e60cf41 100644 --- a/DatadogTrace/Sources/Feature/MessageReceivers.swift +++ b/DatadogTrace/Sources/Feature/MessageReceivers.swift @@ -18,7 +18,7 @@ internal struct CoreContext { } internal final class ContextMessageReceiver: FeatureMessageReceiver { - let bundleWithRUM: Bool + let bundleWithRumEnabled: Bool /// The up-to-date core context. /// @@ -26,8 +26,8 @@ internal final class ContextMessageReceiver: FeatureMessageReceiver { @ReadWriteLock var context: CoreContext = .init() - init(bundleWithRUM: Bool) { - self.bundleWithRUM = bundleWithRUM + init(bundleWithRumEnabled: Bool) { + self.bundleWithRumEnabled = bundleWithRumEnabled } /// Process messages receives from the bus. @@ -51,7 +51,7 @@ internal final class ContextMessageReceiver: FeatureMessageReceiver { _context.mutate { $0.applicationStateHistory = context.applicationStateHistory - if bundleWithRUM { + if bundleWithRumEnabled { $0.rum = context.featuresAttributes["rum"]?.ids } } diff --git a/DatadogTrace/Sources/Feature/TraceFeature.swift b/DatadogTrace/Sources/Feature/TraceFeature.swift index e5b266c0a8..0ae3012632 100644 --- a/DatadogTrace/Sources/Feature/TraceFeature.swift +++ b/DatadogTrace/Sources/Feature/TraceFeature.swift @@ -20,7 +20,7 @@ internal final class TraceFeature: DatadogRemoteFeature { configuration: Trace.Configuration ) { let contextReceiver = ContextMessageReceiver( - bundleWithRUM: configuration.bundleWithRUM + bundleWithRumEnabled: configuration.bundleWithRumEnabled ) self.requestBuilder = TracingRequestBuilder(customIntakeURL: configuration.customEndpoint) self.messageReceiver = contextReceiver @@ -29,7 +29,7 @@ internal final class TraceFeature: DatadogRemoteFeature { sampler: Sampler(samplingRate: configuration.debugSDK ? 100 : configuration.sampleRate), tags: configuration.tags ?? [:], service: configuration.service, - sendNetworkInfo: configuration.sendNetworkInfo, + networkInfoEnabled: configuration.networkInfoEnabled, spanEventMapper: configuration.eventMapper, tracingUUIDGenerator: configuration.traceIDGenerator, dateProvider: configuration.dateProvider, @@ -37,7 +37,7 @@ internal final class TraceFeature: DatadogRemoteFeature { loggingIntegration: TracingWithLoggingIntegration( core: core, service: configuration.service, - sendNetworkInfo: configuration.sendNetworkInfo + networkInfoEnabled: configuration.networkInfoEnabled ) ) self.telemetry = TelemetryCore(core: core) diff --git a/DatadogTrace/Sources/Integrations/TracingWithLoggingIntegration.swift b/DatadogTrace/Sources/Integrations/TracingWithLoggingIntegration.swift index 778d76076e..afacba195c 100644 --- a/DatadogTrace/Sources/Integrations/TracingWithLoggingIntegration.swift +++ b/DatadogTrace/Sources/Integrations/TracingWithLoggingIntegration.swift @@ -33,12 +33,12 @@ internal struct TracingWithLoggingIntegration { /// `DatadogCore` instance managing this integration. weak var core: DatadogCoreProtocol? let service: String? - let sendNetworkInfo: Bool + let networkInfoEnabled: Bool - init(core: DatadogCoreProtocol, service: String?, sendNetworkInfo: Bool) { + init(core: DatadogCoreProtocol, service: String?, networkInfoEnabled: Bool) { self.core = core self.service = service - self.sendNetworkInfo = sendNetworkInfo + self.networkInfoEnabled = networkInfoEnabled } func writeLog(withSpanContext spanContext: DDSpanContext, fields: [String: Encodable], date: Date, else fallback: @escaping () -> Void) { @@ -86,7 +86,7 @@ internal struct TracingWithLoggingIntegration { "error": extractedError, "userAttributes": AnyEncodable(userAttributes), "internalAttributes": internalAttributes, - "networkInfoEnabled": sendNetworkInfo + "networkInfoEnabled": networkInfoEnabled ] ), else: fallback diff --git a/DatadogTrace/Sources/Span/SpanEventBuilder.swift b/DatadogTrace/Sources/Span/SpanEventBuilder.swift index 4abd5699ed..3009d2b15c 100644 --- a/DatadogTrace/Sources/Span/SpanEventBuilder.swift +++ b/DatadogTrace/Sources/Span/SpanEventBuilder.swift @@ -14,7 +14,7 @@ internal struct SpanEventBuilder { /// Enriches traces with network connection info. /// This means: reachability status, connection type, mobile carrier name and many more will be added to every span and span logs. /// For full list of network info attributes see `NetworkConnectionInfo` and `CarrierInfo`. - let sendNetworkInfo: Bool + let networkInfoEnabled: Bool /// Span events mapper configured by the user, `nil` if not set. let eventsMapper: SpanEventMapper? @@ -67,8 +67,8 @@ internal struct SpanEventBuilder { isKept: isKept, tracerVersion: context.sdkVersion, applicationVersion: context.version, - networkConnectionInfo: sendNetworkInfo ? context.networkConnectionInfo : nil, - mobileCarrierInfo: sendNetworkInfo ? context.carrierInfo : nil, + networkConnectionInfo: networkInfoEnabled ? context.networkConnectionInfo : nil, + mobileCarrierInfo: networkInfoEnabled ? context.carrierInfo : nil, userInfo: spanUserInfo, tags: tags ) diff --git a/DatadogTrace/Sources/TraceConfiguration.swift b/DatadogTrace/Sources/TraceConfiguration.swift index 6b847d271b..ef94ec2ffd 100644 --- a/DatadogTrace/Sources/TraceConfiguration.swift +++ b/DatadogTrace/Sources/TraceConfiguration.swift @@ -49,14 +49,14 @@ extension Trace { /// When enabled, all spans will be enriched with the current RUM view information. /// /// Default: `true`. - public var bundleWithRUM: Bool + public var bundleWithRumEnabled: Bool /// Enriches traces with network connection information. /// /// This includes reachability status, connection type, mobile carrier name, and more, which will be added to every span and span log. /// /// Default: `false` - public var sendNetworkInfo: Bool + public var networkInfoEnabled: Bool /// Custom mapper for span events. /// @@ -126,8 +126,8 @@ extension Trace { /// - service: The `service` value for spans. /// - tags: Global tags associated with each span created with the default tracer. /// - urlSessionTracking: The configuration for automatic network requests tracing. - /// - bundleWithRUM: Determines if traces should be enriched with RUM information. - /// - sendNetworkInfo: Determines if traces should be enriched with network connection information. + /// - bundleWithRumEnabled: Determines if traces should be enriched with RUM information. + /// - networkInfoEnabled: Determines if traces should be enriched with network connection information. /// - eventMapper: Custom mapper for span events. /// - customEndpoint: Custom server url for sending traces. public init( @@ -135,8 +135,8 @@ extension Trace { service: String? = nil, tags: [String: Encodable]? = nil, urlSessionTracking: URLSessionTracking? = nil, - bundleWithRUM: Bool = true, - sendNetworkInfo: Bool = false, + bundleWithRumEnabled: Bool = true, + networkInfoEnabled: Bool = false, eventMapper: EventMapper? = nil, customEndpoint: URL? = nil ) { @@ -144,8 +144,8 @@ extension Trace { self.service = service self.tags = tags self.urlSessionTracking = urlSessionTracking - self.bundleWithRUM = bundleWithRUM - self.sendNetworkInfo = sendNetworkInfo + self.bundleWithRumEnabled = bundleWithRumEnabled + self.networkInfoEnabled = networkInfoEnabled self.eventMapper = eventMapper self.customEndpoint = customEndpoint } diff --git a/DatadogTrace/Tests/ContextMessageReceiverTests.swift b/DatadogTrace/Tests/ContextMessageReceiverTests.swift index f0a63e5d22..d5a3693c71 100644 --- a/DatadogTrace/Tests/ContextMessageReceiverTests.swift +++ b/DatadogTrace/Tests/ContextMessageReceiverTests.swift @@ -12,7 +12,7 @@ import TestUtilities class ContextMessageReceiverTests: XCTestCase { func testItReceivesApplicationStateHistory() throws { // Given - let receiver = ContextMessageReceiver(bundleWithRUM: .mockRandom()) + let receiver = ContextMessageReceiver(bundleWithRumEnabled: .mockRandom()) let core = PassthroughCoreMock( context: .mockWith(applicationStateHistory: .mockAppInBackground()), messageReceiver: receiver @@ -29,7 +29,7 @@ class ContextMessageReceiverTests: XCTestCase { func testItReceivesRUMContext() throws { // Given - let receiver = ContextMessageReceiver(bundleWithRUM: true) + let receiver = ContextMessageReceiver(bundleWithRumEnabled: true) var ids: [String: String] = .mockRandom() let core = PassthroughCoreMock( @@ -49,7 +49,7 @@ class ContextMessageReceiverTests: XCTestCase { func testItIngnoresRUMContext() throws { // Given - let receiver = ContextMessageReceiver(bundleWithRUM: false) + let receiver = ContextMessageReceiver(bundleWithRumEnabled: false) var ids: [String: String] = .mockRandom() let core = PassthroughCoreMock( diff --git a/DatadogTrace/Tests/TraceConfigurationTests.swift b/DatadogTrace/Tests/TraceConfigurationTests.swift index 1d6621d372..a14e2be2fb 100644 --- a/DatadogTrace/Tests/TraceConfigurationTests.swift +++ b/DatadogTrace/Tests/TraceConfigurationTests.swift @@ -17,8 +17,8 @@ class TraceConfigurationTests: XCTestCase { XCTAssertNil(config.service) XCTAssertNil(config.tags) XCTAssertNil(config.urlSessionTracking) - XCTAssertTrue(config.bundleWithRUM) - XCTAssertFalse(config.sendNetworkInfo) + XCTAssertTrue(config.bundleWithRumEnabled) + XCTAssertFalse(config.networkInfoEnabled) XCTAssertNil(config.eventMapper) XCTAssertNil(config.customEndpoint) } diff --git a/DatadogTrace/Tests/TraceTests.swift b/DatadogTrace/Tests/TraceTests.swift index 677a265ccb..b778fdafcd 100644 --- a/DatadogTrace/Tests/TraceTests.swift +++ b/DatadogTrace/Tests/TraceTests.swift @@ -70,7 +70,7 @@ class TraceTests: XCTestCase { XCTAssertNil(tracer.loggingIntegration.service) XCTAssertTrue(tracer.tags.isEmpty) XCTAssertNil(core.get(feature: NetworkInstrumentationFeature.self)) - XCTAssertEqual(tracer.sendNetworkInfo, false) + XCTAssertEqual(tracer.networkInfoEnabled, false) XCTAssertNil(tracer.spanEventMapper) XCTAssertNil((trace.requestBuilder as? TracingRequestBuilder)?.customIntakeURL) } @@ -175,42 +175,42 @@ class TraceTests: XCTestCase { func testWhenEnabledWithBundleWithRUM() throws { // Given let random: Bool = .mockRandom() - config.bundleWithRUM = random + config.bundleWithRumEnabled = random // When Trace.enable(with: config, in: core) // Then let trace = try XCTUnwrap(core.get(feature: TraceFeature.self)) - XCTAssertEqual((trace.messageReceiver as? ContextMessageReceiver)?.bundleWithRUM, random) + XCTAssertEqual((trace.messageReceiver as? ContextMessageReceiver)?.bundleWithRumEnabled, random) } func testWhenEnabledWithSendNetworkInfo() { // Given let random: Bool = .mockRandom() - config.sendNetworkInfo = random + config.networkInfoEnabled = random // When Trace.enable(with: config, in: core) // Then let tracer = Tracer.shared(in: core).dd - XCTAssertEqual(tracer.sendNetworkInfo, random) - XCTAssertEqual(tracer.loggingIntegration.sendNetworkInfo, random) + XCTAssertEqual(tracer.networkInfoEnabled, random) + XCTAssertEqual(tracer.loggingIntegration.networkInfoEnabled, random) } func testWhenEnabledWithEventMapper() { // Given let random: Bool = .mockRandom() - config.sendNetworkInfo = random + config.networkInfoEnabled = random // When Trace.enable(with: config, in: core) // Then let tracer = Tracer.shared(in: core).dd - XCTAssertEqual(tracer.sendNetworkInfo, random) - XCTAssertEqual(tracer.loggingIntegration.sendNetworkInfo, random) + XCTAssertEqual(tracer.networkInfoEnabled, random) + XCTAssertEqual(tracer.loggingIntegration.networkInfoEnabled, random) } func testWhenEnabledWithCustomEndpoint() throws { diff --git a/DatadogTrace/Tests/TracingFeatureMocks.swift b/DatadogTrace/Tests/TracingFeatureMocks.swift index 4d36d10995..a46c248c94 100644 --- a/DatadogTrace/Tests/TracingFeatureMocks.swift +++ b/DatadogTrace/Tests/TracingFeatureMocks.swift @@ -187,7 +187,7 @@ extension DatadogTracer { sampler: Sampler = .mockKeepAll(), tags: [String: Encodable] = [:], service: String? = nil, - sendNetworkInfo: Bool = true, + networkInfoEnabled: Bool = true, spanEventMapper: ((SpanEvent) -> SpanEvent)? = nil, tracingUUIDGenerator: TraceIDGenerator = DefaultTraceIDGenerator(), dateProvider: DateProvider = SystemDateProvider(), @@ -199,7 +199,7 @@ extension DatadogTracer { sampler: sampler, tags: tags, service: service, - sendNetworkInfo: sendNetworkInfo, + networkInfoEnabled: networkInfoEnabled, spanEventMapper: spanEventMapper, tracingUUIDGenerator: tracingUUIDGenerator, dateProvider: dateProvider, @@ -214,14 +214,14 @@ extension TracingWithLoggingIntegration { return TracingWithLoggingIntegration( core: NOPDatadogCore(), service: .mockAny(), - sendNetworkInfo: .mockAny() + networkInfoEnabled: .mockAny() ) } } extension ContextMessageReceiver { static func mockAny() -> ContextMessageReceiver { - return ContextMessageReceiver(bundleWithRUM: true) + return ContextMessageReceiver(bundleWithRumEnabled: true) } } @@ -232,12 +232,12 @@ extension SpanEventBuilder { static func mockWith( serviceName: String = .mockAny(), - sendNetworkInfo: Bool = false, + networkInfoEnabled: Bool = false, eventsMapper: SpanEventMapper? = nil ) -> SpanEventBuilder { return SpanEventBuilder( serviceName: serviceName, - sendNetworkInfo: sendNetworkInfo, + networkInfoEnabled: networkInfoEnabled, eventsMapper: eventsMapper ) } diff --git a/DatadogTrace/Tests/TracingURLSessionHandlerTests.swift b/DatadogTrace/Tests/TracingURLSessionHandlerTests.swift index 53ad3d022e..42ad94f7a2 100644 --- a/DatadogTrace/Tests/TracingURLSessionHandlerTests.swift +++ b/DatadogTrace/Tests/TracingURLSessionHandlerTests.swift @@ -19,7 +19,7 @@ class TracingURLSessionHandlerTests: XCTestCase { override func setUp() { super.setUp() - let receiver = ContextMessageReceiver(bundleWithRUM: true) + let receiver = ContextMessageReceiver(bundleWithRumEnabled: true) core = PassthroughCoreMock(messageReceiver: receiver) tracer = .mockWith( @@ -46,7 +46,7 @@ class TracingURLSessionHandlerTests: XCTestCase { // Given let handler = TracingURLSessionHandler( tracer: tracer, - contextReceiver: ContextMessageReceiver(bundleWithRUM: true), + contextReceiver: ContextMessageReceiver(bundleWithRumEnabled: true), tracingSampler: .mockKeepAll(), firstPartyHosts: .init() ) @@ -77,7 +77,7 @@ class TracingURLSessionHandlerTests: XCTestCase { // Given let handler = TracingURLSessionHandler( tracer: tracer, - contextReceiver: ContextMessageReceiver(bundleWithRUM: true), + contextReceiver: ContextMessageReceiver(bundleWithRumEnabled: true), tracingSampler: .mockRejectAll(), firstPartyHosts: .init() ) @@ -262,7 +262,7 @@ class TracingURLSessionHandlerTests: XCTestCase { core.expectation?.isInverted = true // Given - let receiver = ContextMessageReceiver(bundleWithRUM: true) + let receiver = ContextMessageReceiver(bundleWithRumEnabled: true) let handler = TracingURLSessionHandler( tracer: .mockWith(core: core), diff --git a/IntegrationTests/Runner/Scenarios/Tracing/TracingScenarios.swift b/IntegrationTests/Runner/Scenarios/Tracing/TracingScenarios.swift index 2d37701b3a..b082ac08a3 100644 --- a/IntegrationTests/Runner/Scenarios/Tracing/TracingScenarios.swift +++ b/IntegrationTests/Runner/Scenarios/Tracing/TracingScenarios.swift @@ -18,7 +18,7 @@ final class TracingManualInstrumentationScenario: TestScenario { Trace.enable( with: Trace.Configuration( sampleRate: 100, - sendNetworkInfo: true, + networkInfoEnabled: true, customEndpoint: Environment.serverMockConfiguration()?.tracesEndpoint ) ) @@ -36,7 +36,7 @@ final class TracingManualInstrumentationScenario: TestScenario { class TracingURLSessionBaseScenario: URLSessionBaseScenario { func configureFeatures() { var config = Trace.Configuration(sampleRate: 100) - config.sendNetworkInfo = true + config.networkInfoEnabled = true config.customEndpoint = Environment.serverMockConfiguration()?.tracesEndpoint config.eventMapper = { var span = $0 diff --git a/IntegrationTests/Runner/Scenarios/TrackingConsent/TrackingConsentScenarios.swift b/IntegrationTests/Runner/Scenarios/TrackingConsent/TrackingConsentScenarios.swift index d4eab8b32a..ae1c6acd1d 100644 --- a/IntegrationTests/Runner/Scenarios/TrackingConsent/TrackingConsentScenarios.swift +++ b/IntegrationTests/Runner/Scenarios/TrackingConsent/TrackingConsentScenarios.swift @@ -22,7 +22,7 @@ internal class TrackingConsentBaseScenario { // Enable Trace var traceConfig = Trace.Configuration() - traceConfig.sendNetworkInfo = true + traceConfig.networkInfoEnabled = true traceConfig.customEndpoint = Environment.serverMockConfiguration()?.tracesEndpoint Trace.enable(with: traceConfig) From 4d9478c3fa3599472d5922220ee643fa6419e8b1 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 3 Jul 2023 18:00:28 +0200 Subject: [PATCH 42/87] RUMM-3387 align v2 rum apis --- Datadog/Example/ExampleAppDelegate.swift | 2 +- .../Tests/Datadog/Mocks/RUMFeatureMocks.swift | 20 +++++++------- .../CrashReportReceiverTests.swift | 26 +++++++++---------- .../DatadogObjc/DDRUMConfigurationTests.swift | 12 ++++----- .../DatadogObjc/ObjcAPITests/DDRUM+apiTests.m | 12 ++++----- DatadogObjc/Sources/RUM+objc.swift | 12 ++++----- DatadogRUM/Sources/Feature/RUMFeature.swift | 10 +++---- .../Integrations/CrashReportReceiver.swift | 10 +++---- DatadogRUM/Sources/RUMConfiguration.swift | 16 ++++++------ .../Scopes/RUMScopeDependencies.swift | 4 +-- .../RUMMonitor/Scopes/RUMSessionScope.swift | 6 ++--- .../Scopes/RUMUserActionScope.swift | 2 +- DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift | 20 +++++++------- DatadogRUM/Tests/RUMConfigurationTests.swift | 4 +-- .../Scopes/RUMSessionScopeTests.swift | 10 +++---- .../Scopes/RUMUserActionScopeTests.swift | 2 +- 16 files changed, 84 insertions(+), 84 deletions(-) diff --git a/Datadog/Example/ExampleAppDelegate.swift b/Datadog/Example/ExampleAppDelegate.swift index 9c50928077..6842c39e86 100644 --- a/Datadog/Example/ExampleAppDelegate.swift +++ b/Datadog/Example/ExampleAppDelegate.swift @@ -82,7 +82,7 @@ class ExampleAppDelegate: UIResponder, UIApplicationDelegate { RUM.enable( with: RUM.Configuration( applicationID: Environment.readRUMApplicationID(), - backgroundEventsTracking: true, + trackBackgroundEvents: true, customEndpoint: Environment.readCustomRUMURL(), telemetrySampleRate: 100 ) diff --git a/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift b/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift index bb1f853b28..f58e85cc94 100644 --- a/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift +++ b/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift @@ -57,7 +57,7 @@ extension CrashReportReceiver: AnyMockable { applicationID: String = .mockAny(), dateProvider: DateProvider = SystemDateProvider(), sessionSampler: Sampler = .mockKeepAll(), - backgroundEventTrackingEnabled: Bool = true, + trackBackgroundEvents: Bool = true, uuidGenerator: RUMUUIDGenerator = DefaultRUMUUIDGenerator(), ciTest: RUMCITest? = nil ) -> Self { @@ -65,7 +65,7 @@ extension CrashReportReceiver: AnyMockable { applicationID: applicationID, dateProvider: dateProvider, sessionSampler: sessionSampler, - backgroundEventTrackingEnabled: backgroundEventTrackingEnabled, + trackBackgroundEvents: trackBackgroundEvents, uuidGenerator: uuidGenerator, ciTest: ciTest ) @@ -672,8 +672,8 @@ extension RUMScopeDependencies { core: DatadogCoreProtocol = NOPDatadogCore(), rumApplicationID: String = .mockAny(), sessionSampler: Sampler = .mockKeepAll(), - backgroundEventTrackingEnabled: Bool = .mockAny(), - frustrationTrackingEnabled: Bool = true, + trackBackgroundEvents: Bool = .mockAny(), + trackFrustrations: Bool = true, firstPartyHosts: FirstPartyHosts = .init([:]), eventBuilder: RUMEventBuilder = RUMEventBuilder(eventsMapper: .mockNoOp()), rumUUIDGenerator: RUMUUIDGenerator = DefaultRUMUUIDGenerator(), @@ -686,8 +686,8 @@ extension RUMScopeDependencies { core: core, rumApplicationID: rumApplicationID, sessionSampler: sessionSampler, - backgroundEventTrackingEnabled: backgroundEventTrackingEnabled, - frustrationTrackingEnabled: frustrationTrackingEnabled, + trackBackgroundEvents: trackBackgroundEvents, + trackFrustrations: trackFrustrations, firstPartyHosts: firstPartyHosts, eventBuilder: eventBuilder, rumUUIDGenerator: rumUUIDGenerator, @@ -702,8 +702,8 @@ extension RUMScopeDependencies { func replacing( rumApplicationID: String? = nil, sessionSampler: Sampler? = nil, - backgroundEventTrackingEnabled: Bool? = nil, - frustrationTrackingEnabled: Bool? = nil, + trackBackgroundEvents: Bool? = nil, + trackFrustrations: Bool? = nil, firstPartyHosts: FirstPartyHosts? = nil, eventBuilder: RUMEventBuilder? = nil, rumUUIDGenerator: RUMUUIDGenerator? = nil, @@ -716,8 +716,8 @@ extension RUMScopeDependencies { core: self.core, rumApplicationID: rumApplicationID ?? self.rumApplicationID, sessionSampler: sessionSampler ?? self.sessionSampler, - backgroundEventTrackingEnabled: backgroundEventTrackingEnabled ?? self.backgroundEventTrackingEnabled, - frustrationTrackingEnabled: frustrationTrackingEnabled ?? self.frustrationTrackingEnabled, + trackBackgroundEvents: trackBackgroundEvents ?? self.trackBackgroundEvents, + trackFrustrations: trackFrustrations ?? self.trackFrustrations, firstPartyHosts: firstPartyHosts ?? self.firstPartyHosts, eventBuilder: eventBuilder ?? self.eventBuilder, rumUUIDGenerator: rumUUIDGenerator ?? self.rumUUIDGenerator, diff --git a/DatadogCore/Tests/Datadog/RUM/Integrations/CrashReportReceiverTests.swift b/DatadogCore/Tests/Datadog/RUM/Integrations/CrashReportReceiverTests.swift index 123aac9259..ea7b9f003b 100644 --- a/DatadogCore/Tests/Datadog/RUM/Integrations/CrashReportReceiverTests.swift +++ b/DatadogCore/Tests/Datadog/RUM/Integrations/CrashReportReceiverTests.swift @@ -88,7 +88,7 @@ class CrashReportReceiverTests: XCTestCase { let receiver: CrashReportReceiver = .mockWith( dateProvider: RelativeDateProvider(using: currentDate), sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) - backgroundEventTrackingEnabled: .mockRandom() // no matter BET + trackBackgroundEvents: .mockRandom() // no matter BET ) // When @@ -125,7 +125,7 @@ class CrashReportReceiverTests: XCTestCase { let receiver: CrashReportReceiver = .mockWith( dateProvider: RelativeDateProvider(using: currentDate), sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) - backgroundEventTrackingEnabled: .mockRandom() // no matter BET + trackBackgroundEvents: .mockRandom() // no matter BET ) // When @@ -160,7 +160,7 @@ class CrashReportReceiverTests: XCTestCase { let receiver: CrashReportReceiver = .mockWith( dateProvider: RelativeDateProvider(using: currentDate), sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) - backgroundEventTrackingEnabled: .mockRandom() // no matter BET + trackBackgroundEvents: .mockRandom() // no matter BET ) // When @@ -196,7 +196,7 @@ class CrashReportReceiverTests: XCTestCase { let receiver: CrashReportReceiver = .mockWith( dateProvider: RelativeDateProvider(using: currentDate), sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) - backgroundEventTrackingEnabled: true // BET enabled + trackBackgroundEvents: true // BET enabled ) // When @@ -233,7 +233,7 @@ class CrashReportReceiverTests: XCTestCase { let receiver: CrashReportReceiver = .mockWith( dateProvider: RelativeDateProvider(using: currentDate), - backgroundEventTrackingEnabled: true // BET enabled + trackBackgroundEvents: true // BET enabled ) // When @@ -301,7 +301,7 @@ class CrashReportReceiverTests: XCTestCase { let receiver: CrashReportReceiver = .mockWith( dateProvider: RelativeDateProvider(using: crashDate), - backgroundEventTrackingEnabled: false // BET disabled + trackBackgroundEvents: false // BET disabled ) // When @@ -342,7 +342,7 @@ class CrashReportReceiverTests: XCTestCase { let receiver: CrashReportReceiver = .mockWith( dateProvider: RelativeDateProvider(using: currentDate), sessionSampler: .mockRandom(), // no matter current session sampling - backgroundEventTrackingEnabled: .mockRandom() + trackBackgroundEvents: .mockRandom() ) // When @@ -378,7 +378,7 @@ class CrashReportReceiverTests: XCTestCase { let receiver: CrashReportReceiver = .mockWith( dateProvider: RelativeDateProvider(using: crashDate), sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) - backgroundEventTrackingEnabled: .mockRandom() // no matter BET + trackBackgroundEvents: .mockRandom() // no matter BET ) // When @@ -478,7 +478,7 @@ class CrashReportReceiverTests: XCTestCase { ) ), sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) - backgroundEventTrackingEnabled: .mockRandom() // no matter BET + trackBackgroundEvents: .mockRandom() // no matter BET ) // When @@ -563,7 +563,7 @@ class CrashReportReceiverTests: XCTestCase { messageReceiver: CrashReportReceiver.mockWith( applicationID: randomRUMAppID, sessionSampler: .mockKeepAll(), - backgroundEventTrackingEnabled: backgroundEventsTrackingEnabled, + trackBackgroundEvents: backgroundEventsTrackingEnabled, uuidGenerator: DefaultRUMUUIDGenerator() ) ) @@ -591,7 +591,7 @@ class CrashReportReceiverTests: XCTestCase { applicationID: randomRUMAppID, dateProvider: RelativeDateProvider(using: crashDate), sessionSampler: Bool.random() ? .mockKeepAll() : .mockRejectAll(), // no matter sampling (as previous session was sampled) - backgroundEventTrackingEnabled: backgroundEventsTrackingEnabled + trackBackgroundEvents: backgroundEventsTrackingEnabled ) // When @@ -708,7 +708,7 @@ class CrashReportReceiverTests: XCTestCase { messageReceiver: CrashReportReceiver.mockWith( applicationID: randomRUMAppID, sessionSampler: .mockKeepAll(), - backgroundEventTrackingEnabled: backgroundEventsTrackingEnabled, + trackBackgroundEvents: backgroundEventsTrackingEnabled, uuidGenerator: DefaultRUMUUIDGenerator() ) ) @@ -735,7 +735,7 @@ class CrashReportReceiverTests: XCTestCase { let receiver: CrashReportReceiver = .mockWith( applicationID: randomRUMAppID, dateProvider: RelativeDateProvider(using: crashDate), - backgroundEventTrackingEnabled: backgroundEventsTrackingEnabled + trackBackgroundEvents: backgroundEventsTrackingEnabled ) // When diff --git a/DatadogCore/Tests/DatadogObjc/DDRUMConfigurationTests.swift b/DatadogCore/Tests/DatadogObjc/DDRUMConfigurationTests.swift index 1355d724e5..2ad6fd04b8 100644 --- a/DatadogCore/Tests/DatadogObjc/DDRUMConfigurationTests.swift +++ b/DatadogCore/Tests/DatadogObjc/DDRUMConfigurationTests.swift @@ -87,16 +87,16 @@ class DDRUMConfigurationTests: XCTestCase { func testFrustrationsTracking() { let random: Bool = .mockRandom() - objc.frustrationsTracking = random - XCTAssertEqual(objc.frustrationsTracking, random) - XCTAssertEqual(swift.frustrationsTracking, random) + objc.trackFrustrations = random + XCTAssertEqual(objc.trackFrustrations, random) + XCTAssertEqual(swift.trackFrustrations, random) } func testBackgroundEventsTracking() { let random: Bool = .mockRandom() - objc.backgroundEventsTracking = random - XCTAssertEqual(objc.backgroundEventsTracking, random) - XCTAssertEqual(swift.backgroundEventsTracking, random) + objc.trackBackgroundEvents = random + XCTAssertEqual(objc.trackBackgroundEvents, random) + XCTAssertEqual(swift.trackBackgroundEvents, random) } func testLongTaskThreshold() { diff --git a/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDRUM+apiTests.m b/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDRUM+apiTests.m index bad853beb3..ab6b08ea25 100644 --- a/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDRUM+apiTests.m +++ b/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDRUM+apiTests.m @@ -87,13 +87,13 @@ - (void)testDDRUMConfigurationAPI { return @{}; }]; - XCTAssertTrue(config.frustrationsTracking); - config.frustrationsTracking = NO; - XCTAssertFalse(config.frustrationsTracking); + XCTAssertTrue(config.trackFrustrations); + config.trackFrustrations = NO; + XCTAssertFalse(config.trackFrustrations); - XCTAssertFalse(config.backgroundEventsTracking); - config.backgroundEventsTracking = YES; - XCTAssertTrue(config.backgroundEventsTracking); + XCTAssertFalse(config.trackBackgroundEvents); + config.trackBackgroundEvents = YES; + XCTAssertTrue(config.trackBackgroundEvents); XCTAssertEqual(config.longTaskThreshold, 0.1); config.longTaskThreshold = 1; diff --git a/DatadogObjc/Sources/RUM+objc.swift b/DatadogObjc/Sources/RUM+objc.swift index d5a8e86a75..48bb3e902d 100644 --- a/DatadogObjc/Sources/RUM+objc.swift +++ b/DatadogObjc/Sources/RUM+objc.swift @@ -327,14 +327,14 @@ public class DDRUMConfiguration: NSObject { swiftConfig.urlSessionTracking = tracking.swiftConfig } - @objc public var frustrationsTracking: Bool { - set { swiftConfig.frustrationsTracking = newValue } - get { swiftConfig.frustrationsTracking } + @objc public var trackFrustrations: Bool { + set { swiftConfig.trackFrustrations = newValue } + get { swiftConfig.trackFrustrations } } - @objc public var backgroundEventsTracking: Bool { - set { swiftConfig.backgroundEventsTracking = newValue } - get { swiftConfig.backgroundEventsTracking } + @objc public var trackBackgroundEvents: Bool { + set { swiftConfig.trackBackgroundEvents = newValue } + get { swiftConfig.trackBackgroundEvents } } @objc public var longTaskThreshold: TimeInterval { diff --git a/DatadogRUM/Sources/Feature/RUMFeature.swift b/DatadogRUM/Sources/Feature/RUMFeature.swift index d1108a0f9f..b375817192 100644 --- a/DatadogRUM/Sources/Feature/RUMFeature.swift +++ b/DatadogRUM/Sources/Feature/RUMFeature.swift @@ -28,8 +28,8 @@ internal final class RUMFeature: DatadogRemoteFeature { core: core, rumApplicationID: configuration.applicationID, sessionSampler: Sampler(samplingRate: configuration.debugSDK ? 100 : configuration.sessionSampleRate), - backgroundEventTrackingEnabled: configuration.backgroundEventsTracking, - frustrationTrackingEnabled: configuration.frustrationsTracking, + trackBackgroundEvents: configuration.trackBackgroundEvents, + trackFrustrations: configuration.trackFrustrations, firstPartyHosts: { switch configuration.urlSessionTracking?.firstPartyHostsTracing { case let .trace(hosts, _): @@ -91,7 +91,7 @@ internal final class RUMFeature: DatadogRemoteFeature { applicationID: configuration.applicationID, dateProvider: configuration.dateProvider, sessionSampler: Sampler(samplingRate: configuration.debugSDK ? 100 : configuration.sessionSampleRate), - backgroundEventTrackingEnabled: configuration.backgroundEventsTracking, + trackBackgroundEvents: configuration.trackBackgroundEvents, uuidGenerator: configuration.uuidGenerator, ciTest: configuration.ciTestExecutionID.map { RUMCITest(testExecutionId: $0) } ) @@ -107,8 +107,8 @@ internal final class RUMFeature: DatadogRemoteFeature { sessionSampleRate: Int64(withNoOverflow: configuration.sessionSampleRate), telemetrySampleRate: Int64(withNoOverflow: configuration.telemetrySampleRate), traceSampleRate: configuration.urlSessionTracking?.firstPartyHostsTracing.map { Int64(withNoOverflow: $0.sampleRate) }, - trackBackgroundEvents: configuration.backgroundEventsTracking, - trackFrustrations: configuration.frustrationsTracking, + trackBackgroundEvents: configuration.trackBackgroundEvents, + trackFrustrations: configuration.trackFrustrations, trackInteractions: configuration.uiKitActionsPredicate != nil, trackLongTask: configuration.longTaskThreshold != nil, trackNativeLongTasks: configuration.longTaskThreshold != nil, diff --git a/DatadogRUM/Sources/Integrations/CrashReportReceiver.swift b/DatadogRUM/Sources/Integrations/CrashReportReceiver.swift index a9f47dba8b..6456b32d58 100644 --- a/DatadogRUM/Sources/Integrations/CrashReportReceiver.swift +++ b/DatadogRUM/Sources/Integrations/CrashReportReceiver.swift @@ -92,7 +92,7 @@ internal struct CrashReportReceiver: FeatureMessageReceiver { let applicationID: String let dateProvider: DateProvider let sessionSampler: Sampler - let backgroundEventTrackingEnabled: Bool + let trackBackgroundEvents: Bool let uuidGenerator: RUMUUIDGenerator /// Integration with CIApp tests. It contains the CIApp test context when active. let ciTest: RUMCITest? @@ -103,14 +103,14 @@ internal struct CrashReportReceiver: FeatureMessageReceiver { applicationID: String, dateProvider: DateProvider, sessionSampler: Sampler, - backgroundEventTrackingEnabled: Bool, + trackBackgroundEvents: Bool, uuidGenerator: RUMUUIDGenerator, ciTest: RUMCITest? ) { self.applicationID = applicationID self.dateProvider = dateProvider self.sessionSampler = sessionSampler - self.backgroundEventTrackingEnabled = backgroundEventTrackingEnabled + self.trackBackgroundEvents = trackBackgroundEvents self.uuidGenerator = uuidGenerator self.ciTest = ciTest } @@ -201,7 +201,7 @@ internal struct CrashReportReceiver: FeatureMessageReceiver { let handlingRule = RUMOffViewEventsHandlingRule( sessionState: lastRUMSessionState, isAppInForeground: crashContext.lastIsAppInForeground, - isBETEnabled: backgroundEventTrackingEnabled + isBETEnabled: trackBackgroundEvents ) let newRUMView: RUMViewEvent? @@ -254,7 +254,7 @@ internal struct CrashReportReceiver: FeatureMessageReceiver { let handlingRule = RUMOffViewEventsHandlingRule( sessionState: nil, isAppInForeground: crashContext.lastIsAppInForeground, - isBETEnabled: backgroundEventTrackingEnabled + isBETEnabled: trackBackgroundEvents ) let newRUMView: RUMViewEvent? diff --git a/DatadogRUM/Sources/RUMConfiguration.swift b/DatadogRUM/Sources/RUMConfiguration.swift index 0aff7202d2..4949b94ccf 100644 --- a/DatadogRUM/Sources/RUMConfiguration.swift +++ b/DatadogRUM/Sources/RUMConfiguration.swift @@ -97,7 +97,7 @@ extension RUM { /// RUM detects "error taps" when an error follows a RUM tap action. /// /// Default: `true`. - public var frustrationsTracking: Bool + public var trackFrustrations: Bool /// Determines whether RUM events should be tracked when no view is active (including when the app is in the background). /// @@ -106,7 +106,7 @@ extension RUM { /// Note: Enabling this option may increase the number of sessions tracked and result in higher billing. /// /// Default: `false`. - public var backgroundEventsTracking: Bool + public var trackBackgroundEvents: Bool /// Enables RUM long tasks tracking with the given threshold (in seconds). /// @@ -297,8 +297,8 @@ extension RUM.Configuration { /// - uiKitViewsPredicate: The predicate for automatically tracking `UIViewControllers` as RUM views. Default: `nil`. /// - uiKitActionsPredicate: The predicate for automatically tracking `UITouch` events as RUM actions. Default: `nil`. /// - urlSessionTracking: The configuration for automatic RUM resources tracking. Default: `nil`. - /// - frustrationsTracking: Determines whether automatic tracking of user frustrations should be enabled. Default: `true`. - /// - backgroundEventsTracking: Determines whether RUM events should be tracked when no view is active. Default: `false`. + /// - trackFrustrations: Determines whether automatic tracking of user frustrations should be enabled. Default: `true`. + /// - trackBackgroundEvents: Determines whether RUM events should be tracked when no view is active. Default: `false`. /// - longTaskThreshold: The threshold for RUM long tasks tracking (in seconds). Default: `0.1`. /// - vitalsUpdateFrequency: The preferred frequency for collecting RUM vitals. Default: `.average`. /// - viewEventMapper: Custom mapper for RUM view events. Default: `nil`. @@ -315,8 +315,8 @@ extension RUM.Configuration { uiKitViewsPredicate: UIKitRUMViewsPredicate? = nil, uiKitActionsPredicate: UIKitRUMActionsPredicate? = nil, urlSessionTracking: URLSessionTracking? = nil, - frustrationsTracking: Bool = true, - backgroundEventsTracking: Bool = false, + trackFrustrations: Bool = true, + trackBackgroundEvents: Bool = false, longTaskThreshold: TimeInterval? = 0.1, vitalsUpdateFrequency: VitalsFrequency? = .average, viewEventMapper: RUM.ViewEventMapper? = nil, @@ -333,8 +333,8 @@ extension RUM.Configuration { self.uiKitViewsPredicate = uiKitViewsPredicate self.uiKitActionsPredicate = uiKitActionsPredicate self.urlSessionTracking = urlSessionTracking - self.frustrationsTracking = frustrationsTracking - self.backgroundEventsTracking = backgroundEventsTracking + self.trackFrustrations = trackFrustrations + self.trackBackgroundEvents = trackBackgroundEvents self.longTaskThreshold = longTaskThreshold self.vitalsUpdateFrequency = vitalsUpdateFrequency self.viewEventMapper = viewEventMapper diff --git a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMScopeDependencies.swift b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMScopeDependencies.swift index a3b7da9210..efdc0cfee6 100644 --- a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMScopeDependencies.swift +++ b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMScopeDependencies.swift @@ -20,8 +20,8 @@ internal struct RUMScopeDependencies { weak var core: DatadogCoreProtocol? let rumApplicationID: String let sessionSampler: Sampler - let backgroundEventTrackingEnabled: Bool - let frustrationTrackingEnabled: Bool + let trackBackgroundEvents: Bool + let trackFrustrations: Bool let firstPartyHosts: FirstPartyHosts? let eventBuilder: RUMEventBuilder let rumUUIDGenerator: RUMUUIDGenerator diff --git a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMSessionScope.swift b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMSessionScope.swift index 6faff63230..6de68365c0 100644 --- a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMSessionScope.swift +++ b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMSessionScope.swift @@ -44,7 +44,7 @@ internal class RUMSessionScope: RUMScope, RUMContextProvider { private let dependencies: RUMScopeDependencies /// Automatically detect background events by creating "Background" view if no other view is active - internal let backgroundEventTrackingEnabled: Bool + internal let trackBackgroundEvents: Bool /// This Session UUID. Equals `.nullUUID` if the Session is sampled. let sessionUUID: RUMUUID @@ -74,7 +74,7 @@ internal class RUMSessionScope: RUMScope, RUMContextProvider { self.isInitialSession = isInitialSession self.sessionStartTime = startTime self.lastInteractionTime = startTime - self.backgroundEventTrackingEnabled = dependencies.backgroundEventTrackingEnabled + self.trackBackgroundEvents = dependencies.trackBackgroundEvents self.isActive = true self.state = RUMSessionState( sessionUUID: sessionUUID.rawValue, @@ -251,7 +251,7 @@ internal class RUMSessionScope: RUMScope, RUMContextProvider { let handlingRule = RUMOffViewEventsHandlingRule( sessionState: state, isAppInForeground: context.applicationStateHistory.currentSnapshot.state.isRunningInForeground, - isBETEnabled: backgroundEventTrackingEnabled + isBETEnabled: trackBackgroundEvents ) switch handlingRule { diff --git a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMUserActionScope.swift b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMUserActionScope.swift index 52778d84f5..2cfba88cfc 100644 --- a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMUserActionScope.swift +++ b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMUserActionScope.swift @@ -133,7 +133,7 @@ internal class RUMUserActionScope: RUMScope, RUMContextProvider { attributes.merge(rumCommandAttributes: command?.attributes) var frustrations: [RUMActionEvent.Action.Frustration.FrustrationType]? = nil - if dependencies.frustrationTrackingEnabled, errorsCount > 0, actionType == .tap { + if dependencies.trackFrustrations, errorsCount > 0, actionType == .tap { frustrations = [.errorTap] } diff --git a/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift b/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift index 2733f340f3..b12d78efbb 100644 --- a/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift +++ b/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift @@ -50,7 +50,7 @@ extension CrashReportReceiver: AnyMockable { applicationID: String = .mockAny(), dateProvider: DateProvider = SystemDateProvider(), sessionSampler: Sampler = .mockKeepAll(), - backgroundEventTrackingEnabled: Bool = true, + trackBackgroundEvents: Bool = true, uuidGenerator: RUMUUIDGenerator = DefaultRUMUUIDGenerator(), ciTest: RUMCITest? = nil ) -> Self { @@ -58,7 +58,7 @@ extension CrashReportReceiver: AnyMockable { applicationID: applicationID, dateProvider: dateProvider, sessionSampler: sessionSampler, - backgroundEventTrackingEnabled: backgroundEventTrackingEnabled, + trackBackgroundEvents: trackBackgroundEvents, uuidGenerator: uuidGenerator, ciTest: ciTest ) @@ -659,8 +659,8 @@ extension RUMScopeDependencies { core: DatadogCoreProtocol = NOPDatadogCore(), rumApplicationID: String = .mockAny(), sessionSampler: Sampler = .mockKeepAll(), - backgroundEventTrackingEnabled: Bool = .mockAny(), - frustrationTrackingEnabled: Bool = true, + trackBackgroundEvents: Bool = .mockAny(), + trackFrustrations: Bool = true, firstPartyHosts: FirstPartyHosts = .init([:]), eventBuilder: RUMEventBuilder = RUMEventBuilder(eventsMapper: .mockNoOp()), rumUUIDGenerator: RUMUUIDGenerator = DefaultRUMUUIDGenerator(), @@ -673,8 +673,8 @@ extension RUMScopeDependencies { core: core, rumApplicationID: rumApplicationID, sessionSampler: sessionSampler, - backgroundEventTrackingEnabled: backgroundEventTrackingEnabled, - frustrationTrackingEnabled: frustrationTrackingEnabled, + trackBackgroundEvents: trackBackgroundEvents, + trackFrustrations: trackFrustrations, firstPartyHosts: firstPartyHosts, eventBuilder: eventBuilder, rumUUIDGenerator: rumUUIDGenerator, @@ -689,8 +689,8 @@ extension RUMScopeDependencies { func replacing( rumApplicationID: String? = nil, sessionSampler: Sampler? = nil, - backgroundEventTrackingEnabled: Bool? = nil, - frustrationTrackingEnabled: Bool? = nil, + trackBackgroundEvents: Bool? = nil, + trackFrustrations: Bool? = nil, firstPartyHosts: FirstPartyHosts? = nil, eventBuilder: RUMEventBuilder? = nil, rumUUIDGenerator: RUMUUIDGenerator? = nil, @@ -703,8 +703,8 @@ extension RUMScopeDependencies { core: self.core, rumApplicationID: rumApplicationID ?? self.rumApplicationID, sessionSampler: sessionSampler ?? self.sessionSampler, - backgroundEventTrackingEnabled: backgroundEventTrackingEnabled ?? self.backgroundEventTrackingEnabled, - frustrationTrackingEnabled: frustrationTrackingEnabled ?? self.frustrationTrackingEnabled, + trackBackgroundEvents: trackBackgroundEvents ?? self.trackBackgroundEvents, + trackFrustrations: trackFrustrations ?? self.trackFrustrations, firstPartyHosts: firstPartyHosts ?? self.firstPartyHosts, eventBuilder: eventBuilder ?? self.eventBuilder, rumUUIDGenerator: rumUUIDGenerator ?? self.rumUUIDGenerator, diff --git a/DatadogRUM/Tests/RUMConfigurationTests.swift b/DatadogRUM/Tests/RUMConfigurationTests.swift index 73e193f9e5..e15a9c0285 100644 --- a/DatadogRUM/Tests/RUMConfigurationTests.swift +++ b/DatadogRUM/Tests/RUMConfigurationTests.swift @@ -19,8 +19,8 @@ class RUMConfigurationTests: XCTestCase { XCTAssertNil(config.uiKitViewsPredicate) XCTAssertNil(config.uiKitActionsPredicate) XCTAssertNil(config.urlSessionTracking) - XCTAssertTrue(config.frustrationsTracking) - XCTAssertFalse(config.backgroundEventsTracking) + XCTAssertTrue(config.trackFrustrations) + XCTAssertFalse(config.trackBackgroundEvents) XCTAssertEqual(config.longTaskThreshold, 0.1) XCTAssertEqual(config.vitalsUpdateFrequency, .average) XCTAssertNil(config.viewEventMapper) diff --git a/DatadogRUM/Tests/RUMMonitor/Scopes/RUMSessionScopeTests.swift b/DatadogRUM/Tests/RUMMonitor/Scopes/RUMSessionScopeTests.swift index 480129e52b..e766cdb461 100644 --- a/DatadogRUM/Tests/RUMMonitor/Scopes/RUMSessionScopeTests.swift +++ b/DatadogRUM/Tests/RUMMonitor/Scopes/RUMSessionScopeTests.swift @@ -142,7 +142,7 @@ class RUMSessionScopeTests: XCTestCase { parent: parent, startTime: sessionStartTime, dependencies: .mockWith( - backgroundEventTrackingEnabled: true // BET enabled + trackBackgroundEvents: true // BET enabled ) ) XCTAssertTrue(scope.viewScopes.isEmpty, "There is no view scope") @@ -171,7 +171,7 @@ class RUMSessionScopeTests: XCTestCase { parent: parent, startTime: sessionStartTime, dependencies: .mockWith( - backgroundEventTrackingEnabled: true // BET enabled + trackBackgroundEvents: true // BET enabled ) ) @@ -207,7 +207,7 @@ class RUMSessionScopeTests: XCTestCase { parent: parent, startTime: sessionStartTime, dependencies: .mockWith( - backgroundEventTrackingEnabled: true // BET enabled + trackBackgroundEvents: true // BET enabled ) ) XCTAssertTrue(scope.viewScopes.isEmpty, "There is no view scope") @@ -233,7 +233,7 @@ class RUMSessionScopeTests: XCTestCase { parent: parent, startTime: sessionStartTime, dependencies: .mockWith( - backgroundEventTrackingEnabled: false // BET disabled + trackBackgroundEvents: false // BET disabled ) ) XCTAssertTrue(scope.viewScopes.isEmpty, "There is no view scope") @@ -261,7 +261,7 @@ class RUMSessionScopeTests: XCTestCase { parent: parent, startTime: sessionStartTime, dependencies: .mockWith( - backgroundEventTrackingEnabled: .mockRandom() // no matter of BET state + trackBackgroundEvents: .mockRandom() // no matter of BET state ) ) XCTAssertTrue(scope.viewScopes.isEmpty, "There is no view scope") diff --git a/DatadogRUM/Tests/RUMMonitor/Scopes/RUMUserActionScopeTests.swift b/DatadogRUM/Tests/RUMMonitor/Scopes/RUMUserActionScopeTests.swift index 859b3ff191..87b6fc2144 100644 --- a/DatadogRUM/Tests/RUMMonitor/Scopes/RUMUserActionScopeTests.swift +++ b/DatadogRUM/Tests/RUMMonitor/Scopes/RUMUserActionScopeTests.swift @@ -663,7 +663,7 @@ class RUMUserActionScopeTests: XCTestCase { let scope = RUMUserActionScope.mockWith( parent: parent, dependencies: .mockWith( - frustrationTrackingEnabled: false + trackFrustrations: false ), actionType: .tap, startTime: currentTime, From 7a7d50c9ab788e2461a07fb7c930712e7fa236d9 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Tue, 4 Jul 2023 11:41:24 +0100 Subject: [PATCH 43/87] REPLAY-1805 Fix image content frame logic --- .../NodeRecorders/UIImageViewRecorder.swift | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift b/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift index 4af5744511..0790756206 100644 --- a/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift +++ b/DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UIImageViewRecorder.swift @@ -98,10 +98,26 @@ internal struct UIImageViewWireframesBuilder: NodeWireframesBuilder { let shouldRecordImage: Bool - private var relativeIntersectedRect: CGRect? { + private var clip: SRContentClip? { guard let contentFrame = contentFrame else { return nil } + let top = max(relativeIntersectedRect.origin.y - contentFrame.origin.y, 0) + let left = max(relativeIntersectedRect.origin.x - contentFrame.origin.x, 0) + let bottom = max(contentFrame.height - (relativeIntersectedRect.height + top), 0) + let right = max(contentFrame.width - (relativeIntersectedRect.width + left), 0) + return SRContentClip( + bottom: Int64(withNoOverflow: bottom), + left: Int64(withNoOverflow: left), + right: Int64(withNoOverflow: right), + top: Int64(withNoOverflow: top) + ) + } + + private var relativeIntersectedRect: CGRect { + guard let contentFrame = contentFrame else { + return .zero + } return attributes.frame.intersection(contentFrame) } @@ -124,20 +140,21 @@ internal struct UIImageViewWireframesBuilder: NodeWireframesBuilder { tintColor: tintColor ) } - if let contentFrame = clipsToBounds ? relativeIntersectedRect : contentFrame { + if let contentFrame = contentFrame { if let base64 = base64 { wireframes.append( builder.createImageWireframe( base64: base64, id: imageWireframeID, - frame: contentFrame + frame: contentFrame, + clip: clipsToBounds ? clip : nil ) ) } else { wireframes.append( builder.createPlaceholderWireframe( id: imageWireframeID, - frame: contentFrame, + frame: clipsToBounds ? relativeIntersectedRect : contentFrame, label: "Content Image" ) ) From a8dbb89e72055f635d2a623119d5662914c1b2b9 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Tue, 4 Jul 2023 14:27:04 +0100 Subject: [PATCH 44/87] REPLAY-1805 Add tests --- .../SRHost/Fixtures/Images.storyboard | 38 ++++++++++++------- .../Fixtures/ImagesViewControllers.swift | 3 ++ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/DatadogSessionReplay/SRSnapshotTests/SRHost/Fixtures/Images.storyboard b/DatadogSessionReplay/SRSnapshotTests/SRHost/Fixtures/Images.storyboard index 06a778a7b3..1c08a90aad 100644 --- a/DatadogSessionReplay/SRSnapshotTests/SRHost/Fixtures/Images.storyboard +++ b/DatadogSessionReplay/SRSnapshotTests/SRHost/Fixtures/Images.storyboard @@ -3,7 +3,7 @@ - + @@ -18,15 +18,15 @@ - - + + - - + + - + @@ -34,7 +34,7 @@ - + @@ -184,7 +184,7 @@ - + @@ -199,7 +199,7 @@ - + @@ -211,14 +211,14 @@ - + + + + + + + + + + @@ -247,17 +256,18 @@ - + - + - + + diff --git a/DatadogSessionReplay/SRSnapshotTests/SRHost/Fixtures/ImagesViewControllers.swift b/DatadogSessionReplay/SRSnapshotTests/SRHost/Fixtures/ImagesViewControllers.swift index 0db8e71456..5b714c4773 100644 --- a/DatadogSessionReplay/SRSnapshotTests/SRHost/Fixtures/ImagesViewControllers.swift +++ b/DatadogSessionReplay/SRSnapshotTests/SRHost/Fixtures/ImagesViewControllers.swift @@ -9,6 +9,7 @@ import UIKit internal class ImagesViewController: UIViewController { @IBOutlet weak var customButton: UIButton! @IBOutlet weak var customImageView: UIImageView! + @IBOutlet weak var contentImageView: UIImageView! @IBOutlet weak var tabBar: UITabBar! @IBOutlet weak var navigationBar: UINavigationBar! @@ -23,6 +24,8 @@ internal class ImagesViewController: UIViewController { navigationBar.setBackgroundImage(UIImage(color: color), for: .default) customImageView.image = UIImage(named: "dd_logo")?.withRenderingMode(.alwaysTemplate) + + contentImageView.image = UIImage(color: color) } } From 5b3309db2ef295373c93da84635c9d52016a6d8d Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Tue, 4 Jul 2023 15:46:11 +0100 Subject: [PATCH 45/87] REPLAY-1805 Fix flaky tests --- .../Sources/Processor/Diffing/Diff+SRWireframes.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift b/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift index 292e476910..16ebc079c6 100644 --- a/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift +++ b/DatadogSessionReplay/Sources/Processor/Diffing/Diff+SRWireframes.swift @@ -136,6 +136,7 @@ extension SRImageWireframe: MutableWireframe { clip: use(clip, ifDifferentThan: other.clip), height: use(height, ifDifferentThan: other.height), id: id, + isEmpty: use(isEmpty, ifDifferentThan: other.isEmpty), mimeType: use(mimeType, ifDifferentThan: other.mimeType), shapeStyle: use(shapeStyle, ifDifferentThan: other.shapeStyle), width: use(width, ifDifferentThan: other.width), From 2bfce1b4deb287c951d79abd0c70667f800c7cc1 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Tue, 4 Jul 2023 21:24:42 +0200 Subject: [PATCH 46/87] RUMM-3404 Create MIGRATION.md --- MIGRATION.md | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 MIGRATION.md diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 0000000000..0eb1a5286f --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,239 @@ +# Migration from 1.x to 2.0 + +This document describes the main changes introduced in SDK `2.0` compared to `1.x`. + +### Product Modules + +All the products (RUM, Trace, Logs, etc.) are now extracted into different modules. That allows you to integrate only what is needed into your application. + +In comparison with version 1.x where all products were in a single module `Datadog`, now you need to adopt the following libraries instead: + +- `DatadogCore` +- `DatadogLogs` +- `DatadogTrace` +- `DatadogRUM` +- `DatadogWebViewTracking` + +These come in addition to the existing `DatadogCrashReporting` and `DatadogObjc`. + +**NOTE**: In case of Crash Reporting and WebView Tracking usage it's also needed to add RUM and/or Logs modules to be able to report events to RUM and/or Logs respectively. + +The `2.0` version of the iOS SDK also expose unified API layouts and naming between iOS and Android SDKs and with other Datadog products. + +### Support for multiple SDK instances + +Previously Datadog SDK implemented a singleton and only one SDK instance could exist in the application process. This created obstacles for use-cases like the usage of the SDK by 3rd party libraries. + +With version 2.0 we addressed this limitation: + +* Now it is possible to initialize multiple instances of the SDK, associating them with a name. +* Many methods of the SDK can optionally take a SDK instance as an argument. If not provided, the call will be associated with the default (nameless) SDK instance. + +Here is an example illustrating the typical usage in case of default instance vs named instance: + +```swift +// default instance +Datadog.initialize( + with: configuration, + trackingConsent: trackingConsent +) + +Datadog.setUserInfo(...) + +// named instance +let core = Datadog.initialize( + with: configuration, + trackingConsent: trackingConsent, + instanceName: "myInstance" +) + +Datadog.setUserInfo(..., in: core) +``` + +**NOTE**: SDK instance name should have the same value between application runs. Storage paths for SDK events are associated with it. + +You can retrieve the named SDK instance by calling `Datadog.sdkInstance(named: "")` and use the `Datadog.isInitialized(instanceName: "")` method to check if the particular SDK instance is initialized. + +## SDK Configuration Changes + +Better SDK granularity is achieved with the extraction of different products into independent modules, therefor all product-specific configurations have been moved to their dedicated modules. + +> The SDK must be initialized before enabling any product. + +The Builder pattern of the SDK initialization has been removed in favor of structure definitions. The following example shows how a `1.x` initialization would translate in `2.0`. + +**V1 Initialization** +```swift +import Datadog + +Datadog.initialize( + appContext: .init(), + trackingConsent: .granted, + configuration: Datadog.Configuration + .builderUsing( + clientToken: "", + environment: "" + ) + .set(serviceName: "") + .build() +``` +**V2 Initialization** +```swift +import DatadogCore + +Datadog.initialize( + with: Datadog.Configuration( + clientToken: "", + env: "", + service: "" + ), + trackingConsent: .granted +) +``` + +API changes: + +|`1.x`|`2.0`| +|---|---| +|`Datadog.Configuration.Builder.set(serviceName:)`|`Datadog.Configuration.service`| +|`Datadog.Configuration.Builder.set(batchSize:)`|`Datadog.Configuration.batchSize`| +|`Datadog.Configuration.Builder.set(uploadFrequency:)`|`Datadog.Configuration.uploadFrequency`| +|`Datadog.Configuration.Builder.set(proxyConfiguration:)`|`Datadog.Configuration.proxyConfiguration`| +|`Datadog.Configuration.Builder.set(encryption:)`|`Datadog.Configuration.encryption`| +|`Datadog.Configuration.Builder.set(serverDateProvider:)`|`Datadog.Configuration.serverDateProvider`| +|`Datadog.AppContext(mainBundle:)`|`Datadog.Configuration.bundle`| + +## Logs Product Changes + +All the classes related to Logs are now strictly in the `DatadogLogs` module. You will first need to enable the product: + +```swift +import DatadogLogs + +Logs.enable() +``` + +Then, you can create a logger instance: + +```swift +import DatadogLogs + +let logger = Logger.create(with: Logger.Configuration(name: "")) +``` + +API changes: + +|`1.x`|`2.0`| +|---|---| +|`Datadog.Configuration.Builder.setLogEventMapper`|`Logs.Configuration.eventMapper`| +|`Datadog.Configuration.Builder.set(loggingSamplingRate:)`|`Logs.Configuration.eventMapper`| +|`Logger.Builder.set(serviceName:)`|`Logger.Configuration.service`| +|`Logger.Builder.set(loggerName:)`|`Logger.Configuration.name`| +|`Logger.Builder.sendNetworkInfo`|`Logger.Configuration.networkInfoEnabled`| +|`Logger.Builder.bundleWithRUM`|`Logger.Configuration.bundleWithRumEnabled`| +|`Logger.Builder.bundleWithTrace`|`Logger.Configuration.bundleWithTraceEnabled`| +|`Logger.Builder.sendLogsToDatadog = false`|`Logger.Configuration.remoteSampleRate = 0`| +|`Logger.Builder.set(datadogReportingThreshold:)`|`Logger.Configuration.remoteLogThreshold`| +|`Logger.Builder.printLogsToConsole(:, usingFormat)`|`Logger.Configuration.consoleLogFormat`| + +## APM Trace Product Changes + +All the classes related to Trace are now strictly in the `DatadogTrace` module. You will first need to enable the product: + +```swift +import DatadogTrace + +Trace.enable() +``` + +Then, you can access the shared Tracer instance: + +```swift +import DatadogTrace + +let tracer = Tracer.shared() +``` + +API changes: + +|`1.x`|`2.0`| +|---|---| +|`Datadog.Configuration.Builder.trackURLSession`|`Trace.Configuration.urlSessionTracking`| +|`Datadog.Configuration.Builder.setSpanEventMapper`|`Trace.Configuration.eventMapper`| +|`Datadog.Configuration.Builder.set(tracingSamplingRate:)`|`Trace.Configuration.sampleRate`| +|`Tracer.Configuration.serviceName`|`Trace.Configuration.service`| +|`Tracer.Configuration.sendNetworkInfo`|`Trace.Configuration.networkInfoEnabled`| +|`Tracer.Configuration.globalTags`|`Trace.Configuration.tags`| +|`Tracer.Configuration.bundleWithRUM`|`Trace.Configuration.bundleWithRumEnabled`| +|`Tracer.Configuration.samplingRate`|`Trace.Configuration.sampleRate`| + +## RUM Product Changes + +All the classes related to RUM are now strictly in the `DatadogRUM` module. You will first need to enable the product: + +```swift +import DatadogRUM + +RUM.enable( + with: RUM.Configuration(applicationID: "") +) +``` + +Then, you can access the shared RUM monitor instance: + +```swift +import DatadogRUM + +let monitor = RUMMonitor.shared() +``` + +API changes: + +|`1.x`|`2.0`| +|---|---| +|`Datadog.Configuration.Builder.trackURLSession`|`RUM.Configuration.urlSessionTracking`| +|`Datadog.Configuration.Builder.set(rumSessionsSamplingRate:)`|`RUM.Configuration.sessionSampleRate`| +|`Datadog.Configuration.Builder.onRUMSessionStart`|`RUM.Configuration.onSessionStart`| +|`Datadog.Configuration.Builder.trackUIKitRUMViews(using:)`|`RUM.Configuration.uiKitViewsPredicate`| +|`Datadog.Configuration.Builder.trackUIKitRUMActions(using:)`|`RUM.Configuration.uiKitActionsPredicate`| +|`Datadog.Configuration.Builder.trackRUMLongTasks(threshold:)`|`RUM.Configuration.longTaskThreshold`| +|`Datadog.Configuration.Builder.setRUMViewEventMapper`|`RUM.Configuration.viewEventMapper`| +|`Datadog.Configuration.Builder.setRUMResourceEventMapper`|`RUM.Configuration.resourceEventMapper`| +|`Datadog.Configuration.Builder.setRUMActionEventMapper`|`RUM.Configuration.actionEventMapper`| +|`Datadog.Configuration.Builder.setRUMErrorEventMapper`|`RUM.Configuration.errorEventMapper`| +|`Datadog.Configuration.Builder.setRUMLongTaskEventMapper`|`RUM.Configuration.longTaskEventMapper`| +|`Datadog.Configuration.Builder.setRUMResourceAttributesProvider`|`RUM.Configuration.urlSessionTracking.resourceAttributesProvider`| +|`Datadog.Configuration.Builder.trackBackgroundEvents`|`RUM.Configuration.trackBackgroundEvents`| +|`Datadog.Configuration.Builder.trackFrustrations`|`RUM.Configuration.frustrationsTracking`| +|`Datadog.Configuration.Builder.set(mobileVitalsFrequency:)`|`RUM.Configuration.vitalsUpdateFrequency`| +|`Datadog.Configuration.Builder.set(sampleTelemetry:)`|`RUM.Configuration.telemetrySampleRate`| + +## Crash Reporting Changes + +To enable Crash Reporting, make sure to also enable RUM and/or Logs. + +```swift +import DatadogCrashReporting + +CrashReporting.enable() +``` + +|`1.x`|`2.0`| +|---|---| +|`Datadog.Configuration.Builder.enableCrashReporting()`|`CrashReporting.enable`| + +## WebViewTracking Changes + +To enable WebViewTracking, make sure to also enable RUM and/or Logs. + +```swift +import WebKit +import DatadogWebViewTracking + +let webView = WKWebView(...) +WebViewTracking.enable(webView: webView) +``` + +|`1.x`|`2.0`| +|---|---| +|`WKUserContentController.startTrackingDatadogEvents`|`WebViewTracking.enable(webView:)`| \ No newline at end of file From 3d4acba5cf6e6e2eaaedc48deb9d6c9a8b8b8ea8 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 09:16:32 +0200 Subject: [PATCH 47/87] RUMM-3387 aligne v2 core apis --- DatadogCore/Sources/Datadog.swift | 54 ++++++++++++++++--- .../Datadog/DatadogConfigurationTests.swift | 8 +-- DatadogCore/Tests/Datadog/DatadogTests.swift | 8 +-- .../Tests/DatadogObjc/DDDatadogTests.swift | 6 +-- .../TestsObserver/DatadogTestsObserver.swift | 2 +- 5 files changed, 59 insertions(+), 19 deletions(-) diff --git a/DatadogCore/Sources/Datadog.swift b/DatadogCore/Sources/Datadog.swift index ae320757ea..8736c79357 100644 --- a/DatadogCore/Sources/Datadog.swift +++ b/DatadogCore/Sources/Datadog.swift @@ -12,14 +12,14 @@ import DatadogInternal /// An entry point to Datadog SDK. /// -/// Initialize the core instance of the Datadog SDK prior to enabling any Features. +/// Initialize the core instance of the Datadog SDK prior to enabling any Product. /// /// Datadog.initialize( /// with: Datadog.Configuration(clientToken: "", env: ""), /// trackingConsent: .pending /// ) /// -/// Once Datadog SDK is initialized, you can enable Features, such as RUM: +/// Once Datadog SDK is initialized, you can enable products, such as RUM: /// /// RUM.enable( /// with: RUM.Configuration(applicationID: "") @@ -173,8 +173,10 @@ public struct Datadog { public static var verbosityLevel: CoreLoggerLevel? = nil /// Returns `true` if the Datadog SDK is already initialized, `false` otherwise. - public static var isInitialized: Bool { - return CoreRegistry.default is DatadogCore + /// + /// - Parameter name: The name of the SDK instance to verify. + public static func isInitialized(instanceName name: String = CoreRegistry.defaultInstanceName) -> Bool { + CoreRegistry.instance(named: name) is DatadogCore } /// Returns the Datadog SDK instance for the given name. @@ -186,7 +188,9 @@ public struct Datadog { } /// Sets current user information. + /// /// Those will be added to logs, traces and RUM events automatically. + /// /// - Parameters: /// - id: User ID, if any /// - name: Name representing the user, if any @@ -212,6 +216,7 @@ public struct Datadog { /// /// This extra info will be added to already existing extra info that is added /// to logs traces and RUM events automatically. + /// /// - Parameters: /// - extraInfo: User's additionall custom attributes public static func addUserExtraInfo( @@ -237,29 +242,62 @@ public struct Datadog { /// Initializes the Datadog SDK. /// + /// You **must** initialize the core instance of the Datadog SDK prior to enabling any Product. + /// + /// Datadog.initialize( + /// with: Datadog.Configuration(clientToken: "", env: ""), + /// trackingConsent: .pending + /// ) + /// + /// Once Datadog SDK is initialized, you can enable products, such as RUM: + /// + /// RUM.enable( + /// with: RUM.Configuration(applicationID: "") + /// ) + /// + /// It is possible to initialize multiple instances of the SDK, associating them with a name. + /// Many methods of the SDK can optionally take a SDK instance as an argument. If not provided, + /// the call will be associated with the default (nameless) SDK instance. + /// + /// To use a secondary instance of the SDK, provide a name to the ``initialize`` method + /// and use the returned instance to enable products: + /// + /// let core = Datadog.initialize( + /// with: Datadog.Configuration(clientToken: "", env: ""), + /// trackingConsent: .pending, + /// instanceName: "my-instance" + /// ) + /// + /// RUM.enable( + /// with: RUM.Configuration(applicationID: ""), + /// in: core + /// ) + /// /// - Parameters: /// - configuration: the SDK configuration. /// - trackingConsent: the initial state of the Data Tracking Consent given by the user of the app. /// - instanceName: The core instance name. This value will be used for data persistency and should be /// stable between application runs. + @discardableResult public static func initialize( with configuration: Configuration, trackingConsent: TrackingConsent, instanceName: String = CoreRegistry.defaultInstanceName - ) { + ) -> DatadogCoreProtocol { // TODO: RUMM-511 remove this warning #if targetEnvironment(macCatalyst) consolePrint("⚠️ Catalyst is not officially supported by Datadog SDK: some features may NOT be functional!") #endif do { - try initializeOrThrow( + return try initializeOrThrow( with: configuration, trackingConsent: trackingConsent, instanceName: instanceName ) } catch { consolePrint("\(error)") + return NOPDatadogCore() } } @@ -267,7 +305,7 @@ public struct Datadog { with configuration: Configuration, trackingConsent: TrackingConsent, instanceName: String - ) throws { + ) throws -> DatadogCoreProtocol { if CoreRegistry.default is DatadogCore { throw ProgrammerError(description: "SDK is already initialized.") } @@ -351,6 +389,8 @@ public struct Datadog { ) DD.telemetry = telemetry + + return core } private static func deleteV1Folders(in core: DatadogCore) { diff --git a/DatadogCore/Tests/Datadog/DatadogConfigurationTests.swift b/DatadogCore/Tests/Datadog/DatadogConfigurationTests.swift index c75ab6f2af..55712f2a57 100644 --- a/DatadogCore/Tests/Datadog/DatadogConfigurationTests.swift +++ b/DatadogCore/Tests/Datadog/DatadogConfigurationTests.swift @@ -17,7 +17,7 @@ class DatadogConfigurationTests: XCTestCase { override func setUp() { super.setUp() - XCTAssertFalse(Datadog.isInitialized) + XCTAssertFalse(Datadog.isInitialized()) printFunction = PrintFunctionMock() consolePrint = printFunction.print } @@ -25,7 +25,7 @@ class DatadogConfigurationTests: XCTestCase { override func tearDown() { consolePrint = { print($0) } printFunction = nil - XCTAssertFalse(Datadog.isInitialized) + XCTAssertFalse(Datadog.isInitialized()) super.tearDown() } @@ -142,7 +142,7 @@ class DatadogConfigurationTests: XCTestCase { trackingConsent: .mockRandom() ) - XCTAssertTrue(Datadog.isInitialized) + XCTAssertTrue(Datadog.isInitialized()) Datadog.flushAndDeinitialize() } @@ -158,7 +158,7 @@ class DatadogConfigurationTests: XCTestCase { printFunction.printedMessage, "🔥 Datadog SDK usage error: `clientToken` cannot be empty." ) - XCTAssertFalse(Datadog.isInitialized) + XCTAssertFalse(Datadog.isInitialized()) } func testGivenValidConfiguration_whenInitializedMoreThanOnce_itPrintsError() { diff --git a/DatadogCore/Tests/Datadog/DatadogTests.swift b/DatadogCore/Tests/Datadog/DatadogTests.swift index a499fa098d..785f51314d 100644 --- a/DatadogCore/Tests/Datadog/DatadogTests.swift +++ b/DatadogCore/Tests/Datadog/DatadogTests.swift @@ -19,7 +19,7 @@ class DatadogTests: XCTestCase { override func setUp() { super.setUp() - XCTAssertFalse(Datadog.isInitialized) + XCTAssertFalse(Datadog.isInitialized()) printFunction = PrintFunctionMock() consolePrint = printFunction.print } @@ -27,7 +27,7 @@ class DatadogTests: XCTestCase { override func tearDown() { consolePrint = { print($0) } printFunction = nil - XCTAssertFalse(Datadog.isInitialized) + XCTAssertFalse(Datadog.isInitialized()) super.tearDown() } @@ -143,7 +143,7 @@ class DatadogTests: XCTestCase { with: defaultConfig, trackingConsent: .mockRandom() ) - XCTAssertTrue(Datadog.isInitialized) + XCTAssertTrue(Datadog.isInitialized()) Datadog.flushAndDeinitialize() } @@ -159,7 +159,7 @@ class DatadogTests: XCTestCase { printFunction.printedMessage, "🔥 Datadog SDK usage error: `clientToken` cannot be empty." ) - XCTAssertFalse(Datadog.isInitialized) + XCTAssertFalse(Datadog.isInitialized()) } func testGivenValidConfiguration_whenInitializedMoreThanOnce_itPrintsError() { diff --git a/DatadogCore/Tests/DatadogObjc/DDDatadogTests.swift b/DatadogCore/Tests/DatadogObjc/DDDatadogTests.swift index 478fa6bf2f..299bcc7130 100644 --- a/DatadogCore/Tests/DatadogObjc/DDDatadogTests.swift +++ b/DatadogCore/Tests/DatadogObjc/DDDatadogTests.swift @@ -16,11 +16,11 @@ import TestUtilities class DDDatadogTests: XCTestCase { override func setUp() { super.setUp() - XCTAssertFalse(Datadog.isInitialized) + XCTAssertFalse(Datadog.isInitialized()) } override func tearDown() { - XCTAssertFalse(Datadog.isInitialized) + XCTAssertFalse(Datadog.isInitialized()) super.tearDown() } @@ -39,7 +39,7 @@ class DDDatadogTests: XCTestCase { trackingConsent: randomConsent().objc ) - XCTAssertTrue(Datadog.isInitialized) + XCTAssertTrue(Datadog.isInitialized()) let context = try XCTUnwrap(CoreRegistry.default as? DatadogCore).contextProvider.read() XCTAssertEqual(context.applicationName, "app-name") diff --git a/DatadogCore/Tests/TestsObserver/DatadogTestsObserver.swift b/DatadogCore/Tests/TestsObserver/DatadogTestsObserver.swift index 9f6a2dc9bb..23a25ccbd0 100644 --- a/DatadogCore/Tests/TestsObserver/DatadogTestsObserver.swift +++ b/DatadogCore/Tests/TestsObserver/DatadogTestsObserver.swift @@ -23,7 +23,7 @@ internal class DatadogTestsObserver: NSObject, XCTestObservation { /// A list of checks ensuring global state integrity before and after each tests. private let checks: [TestIntegrityCheck] = [ .init( - assert: { !Datadog.isInitialized }, + assert: { !Datadog.isInitialized() }, problem: "`Datadog` must not be initialized.", solution: """ Make sure `Datadog.flushAndDeinitialize()` is called before the end of test that uses `Datadog.initialize()`. From 5aeb967f943ca138e9bc3d1ec5b405a03f345d22 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 10:30:17 +0200 Subject: [PATCH 48/87] RUMM-3404 Update MIGRATION.md --- MIGRATION.md | 153 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 96 insertions(+), 57 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 0eb1a5286f..0dce1ca6b1 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -20,40 +20,6 @@ These come in addition to the existing `DatadogCrashReporting` and `DatadogObjc` The `2.0` version of the iOS SDK also expose unified API layouts and naming between iOS and Android SDKs and with other Datadog products. -### Support for multiple SDK instances - -Previously Datadog SDK implemented a singleton and only one SDK instance could exist in the application process. This created obstacles for use-cases like the usage of the SDK by 3rd party libraries. - -With version 2.0 we addressed this limitation: - -* Now it is possible to initialize multiple instances of the SDK, associating them with a name. -* Many methods of the SDK can optionally take a SDK instance as an argument. If not provided, the call will be associated with the default (nameless) SDK instance. - -Here is an example illustrating the typical usage in case of default instance vs named instance: - -```swift -// default instance -Datadog.initialize( - with: configuration, - trackingConsent: trackingConsent -) - -Datadog.setUserInfo(...) - -// named instance -let core = Datadog.initialize( - with: configuration, - trackingConsent: trackingConsent, - instanceName: "myInstance" -) - -Datadog.setUserInfo(..., in: core) -``` - -**NOTE**: SDK instance name should have the same value between application runs. Storage paths for SDK events are associated with it. - -You can retrieve the named SDK instance by calling `Datadog.sdkInstance(named: "")` and use the `Datadog.isInitialized(instanceName: "")` method to check if the particular SDK instance is initialized. - ## SDK Configuration Changes Better SDK granularity is achieved with the extraction of different products into independent modules, therefor all product-specific configurations have been moved to their dedicated modules. @@ -110,7 +76,7 @@ All the classes related to Logs are now strictly in the `DatadogLogs` module. Yo ```swift import DatadogLogs -Logs.enable() +Logs.enable(with: Logs.Configuration(...)) ``` Then, you can create a logger instance: @@ -118,23 +84,25 @@ Then, you can create a logger instance: ```swift import DatadogLogs -let logger = Logger.create(with: Logger.Configuration(name: "")) +let logger = Logger.create( + with: Logger.Configuration(name: "") +) ``` API changes: |`1.x`|`2.0`| |---|---| -|`Datadog.Configuration.Builder.setLogEventMapper`|`Logs.Configuration.eventMapper`| +|`Datadog.Configuration.Builder.setLogEventMapper(_:)`|`Logs.Configuration.eventMapper`| |`Datadog.Configuration.Builder.set(loggingSamplingRate:)`|`Logs.Configuration.eventMapper`| |`Logger.Builder.set(serviceName:)`|`Logger.Configuration.service`| |`Logger.Builder.set(loggerName:)`|`Logger.Configuration.name`| -|`Logger.Builder.sendNetworkInfo`|`Logger.Configuration.networkInfoEnabled`| -|`Logger.Builder.bundleWithRUM`|`Logger.Configuration.bundleWithRumEnabled`| -|`Logger.Builder.bundleWithTrace`|`Logger.Configuration.bundleWithTraceEnabled`| -|`Logger.Builder.sendLogsToDatadog = false`|`Logger.Configuration.remoteSampleRate = 0`| +|`Logger.Builder.sendNetworkInfo(_:)`|`Logger.Configuration.networkInfoEnabled`| +|`Logger.Builder.bundleWithRUM(_:)`|`Logger.Configuration.bundleWithRumEnabled`| +|`Logger.Builder.bundleWithTrace(_:)`|`Logger.Configuration.bundleWithTraceEnabled`| +|`Logger.Builder.sendLogsToDatadog(false)`|`Logger.Configuration.remoteSampleRate = 0`| |`Logger.Builder.set(datadogReportingThreshold:)`|`Logger.Configuration.remoteLogThreshold`| -|`Logger.Builder.printLogsToConsole(:, usingFormat)`|`Logger.Configuration.consoleLogFormat`| +|`Logger.Builder.printLogsToConsole(_:, usingFormat)`|`Logger.Configuration.consoleLogFormat`| ## APM Trace Product Changes @@ -143,7 +111,10 @@ All the classes related to Trace are now strictly in the `DatadogTrace` module. ```swift import DatadogTrace -Trace.enable() +// Using the default SDK core instance +Trace.enable( + with: Trace.Configuration(...) + ) ``` Then, you can access the shared Tracer instance: @@ -151,6 +122,7 @@ Then, you can access the shared Tracer instance: ```swift import DatadogTrace +// Using the default SDK core instance let tracer = Tracer.shared() ``` @@ -158,8 +130,8 @@ API changes: |`1.x`|`2.0`| |---|---| -|`Datadog.Configuration.Builder.trackURLSession`|`Trace.Configuration.urlSessionTracking`| -|`Datadog.Configuration.Builder.setSpanEventMapper`|`Trace.Configuration.eventMapper`| +|`Datadog.Configuration.Builder.trackURLSession(_:)`|`Trace.Configuration.urlSessionTracking`| +|`Datadog.Configuration.Builder.setSpanEventMapper(_:)`|`Trace.Configuration.eventMapper`| |`Datadog.Configuration.Builder.set(tracingSamplingRate:)`|`Trace.Configuration.sampleRate`| |`Tracer.Configuration.serviceName`|`Trace.Configuration.service`| |`Tracer.Configuration.sendNetworkInfo`|`Trace.Configuration.networkInfoEnabled`| @@ -191,20 +163,20 @@ API changes: |`1.x`|`2.0`| |---|---| -|`Datadog.Configuration.Builder.trackURLSession`|`RUM.Configuration.urlSessionTracking`| +|`Datadog.Configuration.Builder.trackURLSession(_:)`|`RUM.Configuration.urlSessionTracking`| |`Datadog.Configuration.Builder.set(rumSessionsSamplingRate:)`|`RUM.Configuration.sessionSampleRate`| |`Datadog.Configuration.Builder.onRUMSessionStart`|`RUM.Configuration.onSessionStart`| |`Datadog.Configuration.Builder.trackUIKitRUMViews(using:)`|`RUM.Configuration.uiKitViewsPredicate`| |`Datadog.Configuration.Builder.trackUIKitRUMActions(using:)`|`RUM.Configuration.uiKitActionsPredicate`| |`Datadog.Configuration.Builder.trackRUMLongTasks(threshold:)`|`RUM.Configuration.longTaskThreshold`| -|`Datadog.Configuration.Builder.setRUMViewEventMapper`|`RUM.Configuration.viewEventMapper`| -|`Datadog.Configuration.Builder.setRUMResourceEventMapper`|`RUM.Configuration.resourceEventMapper`| -|`Datadog.Configuration.Builder.setRUMActionEventMapper`|`RUM.Configuration.actionEventMapper`| -|`Datadog.Configuration.Builder.setRUMErrorEventMapper`|`RUM.Configuration.errorEventMapper`| -|`Datadog.Configuration.Builder.setRUMLongTaskEventMapper`|`RUM.Configuration.longTaskEventMapper`| -|`Datadog.Configuration.Builder.setRUMResourceAttributesProvider`|`RUM.Configuration.urlSessionTracking.resourceAttributesProvider`| -|`Datadog.Configuration.Builder.trackBackgroundEvents`|`RUM.Configuration.trackBackgroundEvents`| -|`Datadog.Configuration.Builder.trackFrustrations`|`RUM.Configuration.frustrationsTracking`| +|`Datadog.Configuration.Builder.setRUMViewEventMapper(_:)`|`RUM.Configuration.viewEventMapper`| +|`Datadog.Configuration.Builder.setRUMResourceEventMapper(_:)`|`RUM.Configuration.resourceEventMapper`| +|`Datadog.Configuration.Builder.setRUMActionEventMapper(_:)`|`RUM.Configuration.actionEventMapper`| +|`Datadog.Configuration.Builder.setRUMErrorEventMapper(_:)`|`RUM.Configuration.errorEventMapper`| +|`Datadog.Configuration.Builder.setRUMLongTaskEventMapper(_:)`|`RUM.Configuration.longTaskEventMapper`| +|`Datadog.Configuration.Builder.setRUMResourceAttributesProvider(_:)`|`RUM.Configuration.urlSessionTracking.resourceAttributesProvider`| +|`Datadog.Configuration.Builder.trackBackgroundEvents(_:)`|`RUM.Configuration.trackBackgroundEvents`| +|`Datadog.Configuration.Builder.trackFrustrations(_:)`|`RUM.Configuration.frustrationsTracking`| |`Datadog.Configuration.Builder.set(mobileVitalsFrequency:)`|`RUM.Configuration.vitalsUpdateFrequency`| |`Datadog.Configuration.Builder.set(sampleTelemetry:)`|`RUM.Configuration.telemetrySampleRate`| @@ -220,9 +192,9 @@ CrashReporting.enable() |`1.x`|`2.0`| |---|---| -|`Datadog.Configuration.Builder.enableCrashReporting()`|`CrashReporting.enable`| +|`Datadog.Configuration.Builder.enableCrashReporting()`|`CrashReporting.enable()`| -## WebViewTracking Changes +## WebView Tracking Changes To enable WebViewTracking, make sure to also enable RUM and/or Logs. @@ -236,4 +208,71 @@ WebViewTracking.enable(webView: webView) |`1.x`|`2.0`| |---|---| -|`WKUserContentController.startTrackingDatadogEvents`|`WebViewTracking.enable(webView:)`| \ No newline at end of file +|`WKUserContentController.startTrackingDatadogEvents`|`WebViewTracking.enable(webView:)`| + +## Using a Secondary Instance of the SDK + +Previously Datadog SDK implemented a singleton and only one SDK instance could exist in the application process. This created obstacles for use-cases like the usage of the SDK by 3rd party libraries. + +With version 2.0 we addressed this limitation: + +* Now it is possible to initialize multiple instances of the SDK, associating them with a name. +* Many methods of the SDK can optionally take a SDK instance as an argument. If not provided, the call will be associated with the default (nameless) SDK instance. + +Here is an example illustrating how to initialize a secondary core instance and enable products: + +```swift +import DatadogCore +import DatadogRUM +import DatadogLogs +import DatadogTrace + +let core = Datadog.initialize( + with: configuration, + trackingConsent: trackingConsent, + instanceName: "my-instance" +) + +RUM.enable( + with: RUM.Configuration(applicationID: ""), + in: core +) + +Logs.enable(in: core) + +Trace.enable(in: core) +``` + +**NOTE**: SDK instance name should have the same value between application runs. Storage paths for SDK events are associated with it. + +Once initialized, you can retrieve the named SDK instance by calling `Datadog.sdkInstance(named: "")` and use it for accessing the products. + +```swift +import DatadogCore + +let core = Datadog.sdkInstance(named: "my-instance") +``` + +### Logs +```swift +import DatadogLogs + +Logs.enable(in: core) +let logger = Logger.create(in: core) +``` + +### Trace +```swift +import DatadogRUM + +RUM.enable(in: core) +let monitor = RUMMonitor.shared(in: core) +``` + +### RUM +```swift +import DatadogRUM + +RUM.enable(in: core) +let monitor = RUMMonitor.shared(in: core) +``` From 5c411e7b34205d034f5fcab1cb8c29553ae5a596 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 10:44:32 +0200 Subject: [PATCH 49/87] Apply suggestions from code review Co-authored-by: Ganesh Jangir --- MIGRATION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 0dce1ca6b1..b4c0dc2dab 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -18,11 +18,11 @@ These come in addition to the existing `DatadogCrashReporting` and `DatadogObjc` **NOTE**: In case of Crash Reporting and WebView Tracking usage it's also needed to add RUM and/or Logs modules to be able to report events to RUM and/or Logs respectively. -The `2.0` version of the iOS SDK also expose unified API layouts and naming between iOS and Android SDKs and with other Datadog products. +The `2.0` version of the iOS SDK also exposes unified API layouts and naming between iOS and Android SDKs and with other Datadog products. ## SDK Configuration Changes -Better SDK granularity is achieved with the extraction of different products into independent modules, therefor all product-specific configurations have been moved to their dedicated modules. +Better SDK granularity is achieved with the extraction of different products into independent modules, therefore all product-specific configurations have been moved to their dedicated modules. > The SDK must be initialized before enabling any product. From c0b1541ea46c9be51a0735fe8468132ca9460ff4 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Thu, 29 Jun 2023 13:25:10 +0100 Subject: [PATCH 50/87] REPLAY-1765 Add records count --- .../RUMDependency.swift | 3 +++ .../SRContextPublisher.swift | 8 +++++++ .../Sources/Drafts/SessionReplayFeature.swift | 3 ++- .../Sources/Processor/Processor.swift | 22 ++++++++++++++++++- .../SessionReplayDependency.swift | 11 ++++++++++ .../RUM/RUMMonitor/Scopes/RUMViewScope.swift | 6 ++++- 6 files changed, 50 insertions(+), 3 deletions(-) diff --git a/DatadogSessionReplay/Sources/DatadogCoreIntegration/RUMDependency.swift b/DatadogSessionReplay/Sources/DatadogCoreIntegration/RUMDependency.swift index 0e1b256793..8299cce9ec 100644 --- a/DatadogSessionReplay/Sources/DatadogCoreIntegration/RUMDependency.swift +++ b/DatadogSessionReplay/Sources/DatadogCoreIntegration/RUMDependency.swift @@ -41,4 +41,7 @@ internal enum RUMDependency { /// The key referencing a `Bool` value that indicates if replay is being recorded. static let hasReplay = "has_replay" + + /// They key referencing a `[String: Int64]` dictionary of viewIDs and associated records count. + static let recordsCount = "records_count" } diff --git a/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift b/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift index 495031f43c..bd314fb051 100644 --- a/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift +++ b/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift @@ -22,4 +22,12 @@ internal class SRContextPublisher { attributes: { [RUMDependency.hasReplay: value] } ) } + + /// Notifies other Features on the state of Session Replay recording. + func setRecordsCount(_ value: [String: Int64]) { + core?.set( + feature: RUMDependency.srBaggageKey, + attributes: { [RUMDependency.recordsCount: value] } + ) + } } diff --git a/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift b/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift index 20e7e1bfd2..bceabda3fe 100644 --- a/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift +++ b/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift @@ -37,7 +37,8 @@ internal class SessionReplayFeature: DatadogFeature, SessionReplayController { let processor = Processor( queue: BackgroundAsyncQueue(named: "com.datadoghq.session-replay.processor"), - writer: writer + writer: writer, + contextPublisher: SRContextPublisher(core: core) ) let scheduler = MainThreadScheduler(interval: 0.1) diff --git a/DatadogSessionReplay/Sources/Processor/Processor.swift b/DatadogSessionReplay/Sources/Processor/Processor.swift index acc8ca1b90..fc36e467e5 100644 --- a/DatadogSessionReplay/Sources/Processor/Processor.swift +++ b/DatadogSessionReplay/Sources/Processor/Processor.swift @@ -52,9 +52,16 @@ internal class Processor: Processing { var interceptWireframes: (([SRWireframe]) -> Void)? = nil #endif - init(queue: Queue, writer: Writing) { + private var contextPublisher: SRContextPublisher + + init( + queue: Queue, + writer: Writing, + contextPublisher: SRContextPublisher + ) { self.queue = queue self.writer = writer + self.contextPublisher = contextPublisher } // MARK: - Processing @@ -114,6 +121,8 @@ internal class Processor: Processing { // Transform `[SRRecord]` to `EnrichedRecord` so we can write it to `DatadogCore` and // later read it back (as `EnrichedRecordJSON`) for preparing upload request(s): let enrichedRecord = EnrichedRecord(context: viewTreeSnapshot.context, records: records) + trackRecord(key: enrichedRecord.viewID, value: Int64(records.count)) + writer.write(nextRecord: enrichedRecord) } @@ -121,4 +130,15 @@ internal class Processor: Processing { lastSnapshot = viewTreeSnapshot lastWireframes = wireframes } + + var recordsCount: [String: Int64] = [:] + + func trackRecord(key: String, value: Int64) { + if let existingValue = recordsCount[key] { + recordsCount[key] = existingValue + value + } else { + recordsCount[key] = value + } + contextPublisher.setRecordsCount(recordsCount) + } } diff --git a/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift b/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift index c4250b93ee..e42274dca8 100644 --- a/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift +++ b/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift @@ -18,6 +18,9 @@ internal struct SessionReplayDependency { /// The key referencing a `Bool` value that indicates if replay is being recorded. static let hasReplay = "has_replay" + + /// The key referencing a `[String: Int64]` value that indicates number of records recorded for a given viewID. + static let recordsCount = "records_count" } // MARK: - Extracting SR context from `DatadogContext` @@ -37,4 +40,12 @@ extension FeatureBaggage { } return hasReplay } + + /// The value of `[String: Int64]` that indicates number of records recorded for a given viewID. + var recordsCount: [String: Int64] { + guard let recordsCount: [String: Int64] = self[SessionReplayDependency.recordsCount] else { + return [:] + } + return recordsCount + } } diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift index 73238c566e..296bad9c2a 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift @@ -438,7 +438,11 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { browserSdkVersion: nil, documentVersion: version.toInt64, pageStates: nil, - replayStats: nil, + replayStats: .init( + recordsCount: context.srBaggage?.recordsCount[viewUUID.rawValue.uuidString], + segmentsCount: nil, + segmentsTotalRawSize: nil + ), session: .init(plan: .plan1) ), application: .init(id: self.context.rumApplicationID), From bcc64a77a6ed142a18f42385027bcbeb738c5237 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 30 Jun 2023 09:51:02 +0100 Subject: [PATCH 51/87] REPLAY-1765 Add tests --- .../Sources/Drafts/SessionReplayFeature.swift | 2 +- .../Sources/Processor/Processor.swift | 8 ++-- .../SRContextPublisherTests.swift | 22 +++++++-- .../Tests/Processor/ProcessorTests.swift | 48 ++++++++++++++++--- 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift b/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift index bceabda3fe..bf6c0df206 100644 --- a/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift +++ b/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift @@ -38,7 +38,7 @@ internal class SessionReplayFeature: DatadogFeature, SessionReplayController { let processor = Processor( queue: BackgroundAsyncQueue(named: "com.datadoghq.session-replay.processor"), writer: writer, - contextPublisher: SRContextPublisher(core: core) + srContextPublisher: SRContextPublisher(core: core) ) let scheduler = MainThreadScheduler(interval: 0.1) diff --git a/DatadogSessionReplay/Sources/Processor/Processor.swift b/DatadogSessionReplay/Sources/Processor/Processor.swift index fc36e467e5..03d34ac035 100644 --- a/DatadogSessionReplay/Sources/Processor/Processor.swift +++ b/DatadogSessionReplay/Sources/Processor/Processor.swift @@ -52,16 +52,16 @@ internal class Processor: Processing { var interceptWireframes: (([SRWireframe]) -> Void)? = nil #endif - private var contextPublisher: SRContextPublisher + private var srContextPublisher: SRContextPublisher init( queue: Queue, writer: Writing, - contextPublisher: SRContextPublisher + srContextPublisher: SRContextPublisher ) { self.queue = queue self.writer = writer - self.contextPublisher = contextPublisher + self.srContextPublisher = srContextPublisher } // MARK: - Processing @@ -139,6 +139,6 @@ internal class Processor: Processing { } else { recordsCount[key] = value } - contextPublisher.setRecordsCount(recordsCount) + srContextPublisher.setRecordsCount(recordsCount) } } diff --git a/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift b/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift index 0ccb90f29b..d7b5329c6c 100644 --- a/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift +++ b/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift @@ -6,13 +6,25 @@ import XCTest @testable import DatadogSessionReplay +import TestUtilities -// swiftlint:disable empty_xctest_method class SRContextPublisherTests: XCTestCase { func testItSetsHasReplayAccordingly() { - // TODO: RUMM-2690 - // Implementing this test requires creating mocks for `DatadogCore` and `DatadogContext`, - // which is yet not possible as we lack separate, shared module to facilitate tests. + let core = PassthroughCoreMock() + let srContextPublisher = SRContextPublisher(core: core) + + srContextPublisher.setRecordingIsPending(true) + + XCTAssertEqual(core.context.featuresAttributes["session-replay"]?.attributes["has_replay"] as? Bool, true) + } + + func testItSetsRecordsCountAccordingly() { + let core = PassthroughCoreMock() + let srContextPublisher = SRContextPublisher(core: core) + + let recordsCount: [String: Int64] = ["view-id": 2] + srContextPublisher.setRecordsCount(recordsCount) + + XCTAssertEqual(core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64], recordsCount) } } -// swiftlint:enable empty_xctest_method diff --git a/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift b/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift index b8a53fb547..00c4a01de4 100644 --- a/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift +++ b/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift @@ -26,7 +26,9 @@ class ProcessorTests: XCTestCase { let rum: RUMContext = .mockWith(serverTimeOffset: 0) // Given - let processor = Processor(queue: NoQueue(), writer: writer) + let core = PassthroughCoreMock() + let srContextPublisher = SRContextPublisher(core: core) + let processor = Processor(queue: NoQueue(), writer: writer, srContextPublisher: srContextPublisher) let viewTree = generateSimpleViewTree() // When @@ -47,6 +49,8 @@ class ProcessorTests: XCTestCase { XCTAssertTrue(enrichedRecord.records[0].isMetaRecord) XCTAssertTrue(enrichedRecord.records[1].isFocusRecord) XCTAssertTrue(enrichedRecord.records[2].isFullSnapshotRecord && enrichedRecord.hasFullSnapshot) + + XCTAssertEqual(core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64], ["abc": 3]) } func testWhenRUMContextDoesNotChangeInSucceedingViewTreeSnapshots_itWritesRecordsThatContinueCurrentSegment() { @@ -54,7 +58,9 @@ class ProcessorTests: XCTestCase { let rum: RUMContext = .mockWith(serverTimeOffset: 0) // Given - let processor = Processor(queue: NoQueue(), writer: writer) + let core = PassthroughCoreMock() + let srContextPublisher = SRContextPublisher(core: core) + let processor = Processor(queue: NoQueue(), writer: writer, srContextPublisher: srContextPublisher) let viewTree = generateSimpleViewTree() // When @@ -90,6 +96,8 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecord.earliestTimestamp, expectedTime.timeIntervalSince1970.toInt64Milliseconds) XCTAssertEqual(enrichedRecord.latestTimestamp, expectedTime.timeIntervalSince1970.toInt64Milliseconds) } + + XCTAssertEqual(core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64], ["abc": 5]) } func testWhenOrientationChanges_itWritesRecordsViewportResizeDataSegment() { @@ -97,7 +105,9 @@ class ProcessorTests: XCTestCase { let rum: RUMContext = .mockRandom() // Given - let processor = Processor(queue: NoQueue(), writer: writer) + let core = PassthroughCoreMock() + let srContextPublisher = SRContextPublisher(core: core) + let processor = Processor(queue: NoQueue(), writer: writer, srContextPublisher: srContextPublisher) let view = UIView.mock(withFixture: .visible(.someAppearance)) view.frame = CGRect(x: 0, y: 0, width: 100, height: 200) let rotatedView = UIView.mock(withFixture: .visible(.someAppearance)) @@ -124,6 +134,11 @@ class ProcessorTests: XCTestCase { XCTAssertTrue(enrichedRecords[1].records[1].isIncrementalSnapshotRecord) XCTAssertEqual(enrichedRecords[1].records[1].incrementalSnapshot?.viewportResizeData?.height, 100) XCTAssertEqual(enrichedRecords[1].records[1].incrementalSnapshot?.viewportResizeData?.width, 200) + + XCTAssertEqual( + (core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64])?.values.first, + 5 + ) } func testWhenRUMContextChangesInSucceedingViewTreeSnapshots_itWritesRecordsThatIndicateNextSegments() { @@ -132,7 +147,9 @@ class ProcessorTests: XCTestCase { let rum2: RUMContext = .mockRandom() // Given - let processor = Processor(queue: NoQueue(), writer: writer) + let core = PassthroughCoreMock() + let srContextPublisher = SRContextPublisher(core: core) + let processor = Processor(queue: NoQueue(), writer: writer, srContextPublisher: srContextPublisher) let viewTree = generateSimpleViewTree() // When @@ -171,6 +188,11 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecord.sessionID, expectedRUM.ids.sessionID) XCTAssertEqual(enrichedRecord.viewID, expectedRUM.ids.viewID) } + + XCTAssertEqual( + (core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64])?.values.map { $0 }, + [4, 4] + ) } // MARK: - Processing `TouchSnapshots` @@ -182,7 +204,9 @@ class ProcessorTests: XCTestCase { let rum: RUMContext = .mockWith(serverTimeOffset: 0) // Given - let processor = Processor(queue: NoQueue(), writer: writer) + let core = PassthroughCoreMock() + let srContextPublisher = SRContextPublisher(core: core) + let processor = Processor(queue: NoQueue(), writer: writer, srContextPublisher: srContextPublisher) // When let touchSnapshot = generateTouchSnapshot(startAt: earliestTouchTime, endAt: snapshotTime, numberOfTouches: numberOfTouches) @@ -215,6 +239,11 @@ class ProcessorTests: XCTestCase { XCTAssertGreaterThanOrEqual(record.timestamp, earliestTouchTime.timeIntervalSince1970.toInt64Milliseconds) XCTAssertLessThanOrEqual(record.timestamp, snapshotTime.timeIntervalSince1970.toInt64Milliseconds) } + + XCTAssertEqual( + (core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64]), + ["abc": 13] + ) } func testWhenRUMContextTimeOffsetChangesInSucceedingViewTreeSnapshots_itWritesRecordsThatContinueCurrentSegment() { @@ -223,7 +252,9 @@ class ProcessorTests: XCTestCase { let rum2: RUMContext = .mockWith(serverTimeOffset: 456) // Given - let processor = Processor(queue: NoQueue(), writer: writer) + let core = PassthroughCoreMock() + let srContextPublisher = SRContextPublisher(core: core) + let processor = Processor(queue: NoQueue(), writer: writer, srContextPublisher: srContextPublisher) let viewTree = generateSimpleViewTree() // When @@ -250,6 +281,11 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecord.sessionID, expectedRUM.ids.sessionID) XCTAssertEqual(enrichedRecord.viewID, expectedRUM.ids.viewID) } + + XCTAssertEqual( + (core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64]), + ["abc": 4] + ) } // MARK: - `ViewTreeSnapshot` generation From e99825ab49ff594520469a1926e3c041d0c8751c Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 30 Jun 2023 10:30:25 +0100 Subject: [PATCH 52/87] REPLAY-1765 Add tests --- .../Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift | 2 +- Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift | 5 +++-- .../Integrations/SessionReplayDependencyTests.swift | 4 +++- .../RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift | 10 ++++++---- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift index 296bad9c2a..13fe5601c9 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift @@ -439,7 +439,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { documentVersion: version.toInt64, pageStates: nil, replayStats: .init( - recordsCount: context.srBaggage?.recordsCount[viewUUID.rawValue.uuidString], + recordsCount: context.srBaggage?.recordsCount[viewUUID.toRUMDataFormat], segmentsCount: nil, segmentsTotalRawSize: nil ), diff --git a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift index 2b642804e7..101971a6ba 100644 --- a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift @@ -1029,10 +1029,11 @@ class ContinuousVitalReaderMock: ContinuousVitalReader { // MARK: - Dependency on Session Replay extension Dictionary where Key == String, Value == FeatureBaggage { - static func mockSessionReplayAttributes(hasReplay: Bool?) -> Self { + static func mockSessionReplayAttributes(hasReplay: Bool?, recordsCount: [String: Int64]? = nil) -> Self { return [ SessionReplayDependency.srBaggageKey: [ - SessionReplayDependency.hasReplay: hasReplay + SessionReplayDependency.hasReplay: hasReplay, + SessionReplayDependency.recordsCount: recordsCount ] ] } diff --git a/Tests/DatadogTests/Datadog/RUM/Integrations/SessionReplayDependencyTests.swift b/Tests/DatadogTests/Datadog/RUM/Integrations/SessionReplayDependencyTests.swift index 4d53024cbd..b4e6cce481 100644 --- a/Tests/DatadogTests/Datadog/RUM/Integrations/SessionReplayDependencyTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/Integrations/SessionReplayDependencyTests.swift @@ -10,14 +10,16 @@ import XCTest class SessionReplayDependencyTests: XCTestCase { func testWhenSessionReplayIsConfigured_itReadsReplayBeingRecorded() { let hasReplay: Bool = .random() + let recordsCount: [String: Int64] = [.mockRandom(): .mockRandom()] // When let context: DatadogContext = .mockWith( - featuresAttributes: .mockSessionReplayAttributes(hasReplay: hasReplay) + featuresAttributes: .mockSessionReplayAttributes(hasReplay: hasReplay, recordsCount: recordsCount) ) // Then XCTAssertEqual(context.srBaggage?.isReplayBeingRecorded, hasReplay) + XCTAssertEqual(context.srBaggage?.recordsCount, recordsCount) } func testWhenSessionReplayIsNotConfigured_itReadsNoSRBaggage() { diff --git a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift index 0fd894b903..cdb2114f23 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift @@ -183,10 +183,6 @@ class RUMViewScopeTests: XCTestCase { } func testWhenInitialViewReceivesAnyCommand_itSendsViewUpdateEvent() throws { - let hasReplay: Bool = .mockRandom() - var context = self.context - context.featuresAttributes = .mockSessionReplayAttributes(hasReplay: hasReplay) - let currentTime: Date = .mockDecember15th2019At10AMUTC() let scope = RUMViewScope( isInitialView: true, @@ -200,6 +196,11 @@ class RUMViewScopeTests: XCTestCase { startTime: currentTime, serverTimeOffset: .zero ) + + let hasReplay: Bool = .mockRandom() + var context = self.context + context.featuresAttributes = .mockSessionReplayAttributes(hasReplay: hasReplay, recordsCount: [scope.viewUUID.toRUMDataFormat: 1]) + _ = scope.process( command: RUMCommandMock(time: currentTime), context: context, @@ -227,6 +228,7 @@ class RUMViewScopeTests: XCTestCase { XCTAssertEqual(event.service, "test-service") XCTAssertEqual(event.device?.name, "device-name") XCTAssertEqual(event.os?.name, "device-os") + XCTAssertEqual(event.dd.replayStats?.recordsCount, 1) } func testWhenInitialViewHasCconfiguredSource_itSendsViewUpdateEventWithConfiguredSource() throws { From 7468f47a095a4cba968e0e89bac64f083a56b6ab Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 30 Jun 2023 12:02:10 +0100 Subject: [PATCH 53/87] REPLAY-1765 Lint fix --- .../Tests/DatadogCoreIntegration/SRContextPublisherTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift b/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift index d7b5329c6c..baeecf4382 100644 --- a/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift +++ b/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift @@ -22,7 +22,7 @@ class SRContextPublisherTests: XCTestCase { let core = PassthroughCoreMock() let srContextPublisher = SRContextPublisher(core: core) - let recordsCount: [String: Int64] = ["view-id": 2] + let recordsCount: [String: Int64] = ["view-id": 2] srContextPublisher.setRecordsCount(recordsCount) XCTAssertEqual(core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64], recordsCount) From e150f39f5c902a99cc29e3179a54a7d5647f6baf Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Fri, 30 Jun 2023 12:11:18 +0100 Subject: [PATCH 54/87] REPLAY-1765 PR fixes --- DatadogSessionReplay/Sources/Processor/Processor.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DatadogSessionReplay/Sources/Processor/Processor.swift b/DatadogSessionReplay/Sources/Processor/Processor.swift index 03d34ac035..3f9c2fce4e 100644 --- a/DatadogSessionReplay/Sources/Processor/Processor.swift +++ b/DatadogSessionReplay/Sources/Processor/Processor.swift @@ -54,6 +54,8 @@ internal class Processor: Processing { private var srContextPublisher: SRContextPublisher + private var recordsCount: [String: Int64] = [:] + init( queue: Queue, writer: Writing, @@ -131,9 +133,7 @@ internal class Processor: Processing { lastWireframes = wireframes } - var recordsCount: [String: Int64] = [:] - - func trackRecord(key: String, value: Int64) { + private func trackRecord(key: String, value: Int64) { if let existingValue = recordsCount[key] { recordsCount[key] = existingValue + value } else { From eee95d9d3e61e0ef263c42581575554edb98d13f Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Wed, 5 Jul 2023 10:27:19 +0100 Subject: [PATCH 55/87] REPLAY-1765 PR fixes --- .../SRContextPublisher.swift | 10 ++--- .../Recorder/RecordingCoordinator.swift | 4 +- .../SRContextPublisherTests.swift | 38 +++++++++++++++++-- .../Tests/Processor/ProcessorTests.swift | 30 ++++++--------- Sources/Datadog/DatadogCore/DatadogCore.swift | 10 +++++ .../DatadogInternal/DatadogCoreProtocol.swift | 32 ++++++++++++++++ .../MessageBus/FeatureBaggage.swift | 7 ++++ TestUtilities/Mocks/PassthroughCoreMock.swift | 8 ++++ .../DatadogCore/DatadogCoreTests.swift | 31 +++++++++++++++ .../Context/FeatureBaggageTests.swift | 10 +++++ .../DatadogInternal/DatadogCoreProxy.swift | 4 ++ 11 files changed, 155 insertions(+), 29 deletions(-) diff --git a/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift b/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift index bd314fb051..ec2ab1720d 100644 --- a/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift +++ b/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift @@ -15,17 +15,17 @@ internal class SRContextPublisher { self.core = core } - /// Notifies other Features on the state of Session Replay recording. - func setRecordingIsPending(_ value: Bool) { - core?.set( + /// Notifies other Features if Session Replay is recording. + func setHasReplay(_ value: Bool) { + core?.update( feature: RUMDependency.srBaggageKey, attributes: { [RUMDependency.hasReplay: value] } ) } - /// Notifies other Features on the state of Session Replay recording. + /// Notifies other Features on the state of Session Replay records count. func setRecordsCount(_ value: [String: Int64]) { - core?.set( + core?.update( feature: RUMDependency.srBaggageKey, attributes: { [RUMDependency.recordsCount: value] } ) diff --git a/DatadogSessionReplay/Sources/Recorder/RecordingCoordinator.swift b/DatadogSessionReplay/Sources/Recorder/RecordingCoordinator.swift index f0e51164cc..12a8978757 100644 --- a/DatadogSessionReplay/Sources/Recorder/RecordingCoordinator.swift +++ b/DatadogSessionReplay/Sources/Recorder/RecordingCoordinator.swift @@ -24,7 +24,7 @@ internal class RecordingCoordinator { sampler: Sampler ) { self.recorder = recorder - srContextPublisher.setRecordingIsPending(false) + srContextPublisher.setHasReplay(false) scheduler.schedule { [weak self] in guard let rumContext = self?.currentRUMContext, @@ -56,7 +56,7 @@ internal class RecordingCoordinator { scheduler.stop() } - srContextPublisher.setRecordingIsPending( + srContextPublisher.setHasReplay( self?.isSampled == true && self?.currentRUMContext?.ids.viewID != nil ) } diff --git a/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift b/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift index baeecf4382..ef7226d6b5 100644 --- a/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift +++ b/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift @@ -9,13 +9,14 @@ import XCTest import TestUtilities class SRContextPublisherTests: XCTestCase { - func testItSetsHasReplayAccordingly() { + func testItSetsHasReplayAccordingly() throws { let core = PassthroughCoreMock() let srContextPublisher = SRContextPublisher(core: core) - srContextPublisher.setRecordingIsPending(true) + srContextPublisher.setHasReplay(true) - XCTAssertEqual(core.context.featuresAttributes["session-replay"]?.attributes["has_replay"] as? Bool, true) + let hasReplay = try XCTUnwrap(core.hasReplay) + XCTAssertTrue(hasReplay) } func testItSetsRecordsCountAccordingly() { @@ -25,6 +26,35 @@ class SRContextPublisherTests: XCTestCase { let recordsCount: [String: Int64] = ["view-id": 2] srContextPublisher.setRecordsCount(recordsCount) - XCTAssertEqual(core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64], recordsCount) + XCTAssertEqual(core.recordsCount, recordsCount) + } + + func testItDoesNotOverridePreviouslySetValue() throws { + let core = PassthroughCoreMock() + let srContextPublisher = SRContextPublisher(core: core) + let recordsCount: [String: Int64] = ["view-id": 2] + + srContextPublisher.setHasReplay(true) + srContextPublisher.setRecordsCount(recordsCount) + + XCTAssertEqual(core.recordsCount, recordsCount) + let hasReplay = try XCTUnwrap(core.hasReplay) + XCTAssertTrue(hasReplay) + + srContextPublisher.setHasReplay(false) + + let hasReplay2 = try XCTUnwrap(core.hasReplay) + XCTAssertFalse(hasReplay2) + XCTAssertEqual(core.recordsCount, recordsCount) + } +} + +fileprivate extension PassthroughCoreMock { + var hasReplay: Bool? { + return context.featuresAttributes["session-replay"]?.has_replay + } + + var recordsCount: [String: Int64]? { + return context.featuresAttributes["session-replay"]?.records_count } } diff --git a/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift b/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift index 00c4a01de4..8ccc212742 100644 --- a/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift +++ b/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift @@ -50,7 +50,7 @@ class ProcessorTests: XCTestCase { XCTAssertTrue(enrichedRecord.records[1].isFocusRecord) XCTAssertTrue(enrichedRecord.records[2].isFullSnapshotRecord && enrichedRecord.hasFullSnapshot) - XCTAssertEqual(core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64], ["abc": 3]) + XCTAssertEqual(core.recordsCount, ["abc": 3]) } func testWhenRUMContextDoesNotChangeInSucceedingViewTreeSnapshots_itWritesRecordsThatContinueCurrentSegment() { @@ -97,7 +97,7 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecord.latestTimestamp, expectedTime.timeIntervalSince1970.toInt64Milliseconds) } - XCTAssertEqual(core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64], ["abc": 5]) + XCTAssertEqual(core.recordsCount, ["abc": 5]) } func testWhenOrientationChanges_itWritesRecordsViewportResizeDataSegment() { @@ -135,10 +135,7 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecords[1].records[1].incrementalSnapshot?.viewportResizeData?.height, 100) XCTAssertEqual(enrichedRecords[1].records[1].incrementalSnapshot?.viewportResizeData?.width, 200) - XCTAssertEqual( - (core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64])?.values.first, - 5 - ) + XCTAssertEqual(core.recordsCount?.values.first, 5) } func testWhenRUMContextChangesInSucceedingViewTreeSnapshots_itWritesRecordsThatIndicateNextSegments() { @@ -189,10 +186,7 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecord.viewID, expectedRUM.ids.viewID) } - XCTAssertEqual( - (core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64])?.values.map { $0 }, - [4, 4] - ) + XCTAssertEqual(core.recordsCount?.values.map { $0 }, [4, 4]) } // MARK: - Processing `TouchSnapshots` @@ -240,10 +234,7 @@ class ProcessorTests: XCTestCase { XCTAssertLessThanOrEqual(record.timestamp, snapshotTime.timeIntervalSince1970.toInt64Milliseconds) } - XCTAssertEqual( - (core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64]), - ["abc": 13] - ) + XCTAssertEqual(core.recordsCount, ["abc": 13]) } func testWhenRUMContextTimeOffsetChangesInSucceedingViewTreeSnapshots_itWritesRecordsThatContinueCurrentSegment() { @@ -282,10 +273,7 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecord.viewID, expectedRUM.ids.viewID) } - XCTAssertEqual( - (core.context.featuresAttributes["session-replay"]?.attributes["records_count"] as? [String: Int64]), - ["abc": 4] - ) + XCTAssertEqual(core.recordsCount, ["abc": 4]) } // MARK: - `ViewTreeSnapshot` generation @@ -329,3 +317,9 @@ class ProcessorTests: XCTestCase { ) } } + +fileprivate extension PassthroughCoreMock { + var recordsCount: [String: Int64]? { + return context.featuresAttributes["session-replay"]?.records_count + } +} diff --git a/Sources/Datadog/DatadogCore/DatadogCore.swift b/Sources/Datadog/DatadogCore/DatadogCore.swift index 3451b1a6bd..8a07f3e428 100644 --- a/Sources/Datadog/DatadogCore/DatadogCore.swift +++ b/Sources/Datadog/DatadogCore/DatadogCore.swift @@ -373,6 +373,16 @@ extension DatadogCore: DatadogCoreProtocol { contextProvider.write { $0.featuresAttributes[feature] = attributes() } } + /* public */ func update(feature: String, attributes: @escaping () -> FeatureBaggage) { + contextProvider.write { + if $0.featuresAttributes[feature] != nil { + $0.featuresAttributes[feature]?.merge(with: attributes()) + } else { + $0.featuresAttributes[feature] = attributes() + } + } + } + /* public */ func send(message: FeatureMessage, sender: DatadogCoreProtocol, else fallback: @escaping () -> Void) { messageBusQueue.async { let receivers = self.messageBus.values.filter { diff --git a/Sources/Datadog/DatadogInternal/DatadogCoreProtocol.swift b/Sources/Datadog/DatadogInternal/DatadogCoreProtocol.swift index 63a233fcbe..a63a9ece59 100644 --- a/Sources/Datadog/DatadogInternal/DatadogCoreProtocol.swift +++ b/Sources/Datadog/DatadogInternal/DatadogCoreProtocol.swift @@ -97,6 +97,36 @@ public protocol DatadogCoreProtocol: AnyObject { /// - attributes: The Feature's attributes to set. func set(feature: String, attributes: @escaping () -> FeatureBaggage) + /// Updates given attributes for a given Feature for sharing data through `DatadogContext`. + /// + /// This method provides a passive communication chanel between Features of the Core. + /// For an active Feature-to-Feature communication, please use the `send(message:)` + /// method. + /// + /// Updating attributes will update the Core Context and will be shared across Features. + /// In the following examples, the Feature `foo` will update two attributes and a second + /// Feature `bar` will read them through the event write context. + /// This function does not remove item if `nil` is provided as a value. + /// + /// // Foo.swift + /// core.update(feature: "foo", attributes: [ + /// "id": 1 + /// ]) + /// core.update(feature: "foo", attributes: [ + /// "name": "bazz" + /// ]) + /// + /// // Bar.swift + /// core.scope(for: "bar").eventWriteContext { context, writer in + /// let fooID: Int? = context.featuresAttributes["foo"]?.id + /// let fooName: Int? = context.featuresAttributes["foo"]?.name + /// } + /// + /// - Parameters: + /// - feature: The Feature's name. + /// - attributes: The Feature's attributes to set. + func update(feature: String, attributes: @escaping () -> FeatureBaggage) + /// Sends a message on the bus shared by features registered in this core. /// /// If the message could not be processed by any registered feature, the fallback closure @@ -214,5 +244,7 @@ internal class NOPDatadogCore: DatadogCoreProtocol { /// no-op func set(feature: String, attributes: @escaping @autoclosure () -> FeatureBaggage) { } /// no-op + func update(feature: String, attributes: @escaping () -> FeatureBaggage) { } + /// no-op func send(message: FeatureMessage, sender: DatadogCoreProtocol, else fallback: @escaping () -> Void) { } } diff --git a/Sources/Datadog/DatadogInternal/MessageBus/FeatureBaggage.swift b/Sources/Datadog/DatadogInternal/MessageBus/FeatureBaggage.swift index e696fd31cc..925015ea20 100644 --- a/Sources/Datadog/DatadogInternal/MessageBus/FeatureBaggage.swift +++ b/Sources/Datadog/DatadogInternal/MessageBus/FeatureBaggage.swift @@ -252,6 +252,13 @@ public struct FeatureBaggage { get { try? value(forKey: key, type: T.self) } set { try? updateValue(newValue, forKey: key) } } + + /// Merges with the values of another FeatureBaggage. + /// + /// - Parameter baggage: The FeatureBaggage to merge. + public mutating func merge(with baggage: FeatureBaggage) { + attributes.merge(baggage.attributes) { $1 } + } } extension FeatureBaggage: ExpressibleByDictionaryLiteral { diff --git a/TestUtilities/Mocks/PassthroughCoreMock.swift b/TestUtilities/Mocks/PassthroughCoreMock.swift index 874f692943..9ff31413cb 100644 --- a/TestUtilities/Mocks/PassthroughCoreMock.swift +++ b/TestUtilities/Mocks/PassthroughCoreMock.swift @@ -101,6 +101,14 @@ public final class PassthroughCoreMock: DatadogV1CoreProtocol, FeatureScope { context.featuresAttributes[feature] = attributes() } + public func update(feature: String, attributes: @escaping () -> FeatureBaggage) { + if context.featuresAttributes[feature] != nil { + context.featuresAttributes[feature]?.merge(with: attributes()) + } else { + context.featuresAttributes[feature] = attributes() + } + } + public func send(message: FeatureMessage, sender: DatadogCoreProtocol, else fallback: () -> Void) { if !messageReceiver.receive(message: message, from: sender) { fallback() diff --git a/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift b/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift index f79c943fc0..6cb90343f6 100644 --- a/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift +++ b/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift @@ -221,4 +221,35 @@ class DatadogCoreTests: XCTestCase { XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.maxObjectSize, 456) XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.maxFileSize, 123) } + + func testItUpdatesTheFeatureBaggage() throws { + // Given + let contextProvider: DatadogContextProvider = .mockAny() + let core = DatadogCore( + directory: temporaryCoreDirectory, + dateProvider: SystemDateProvider(), + initialConsent: .mockRandom(), + userInfoProvider: .mockAny(), + performance: .mockRandom(), + httpClient: .mockAny(), + encryption: nil, + contextProvider: contextProvider, + applicationVersion: .mockAny() + ) + defer { core.flushAndTearDown() } + try core.register(feature: FeatureMock(name: "mock")) + + // When + core.update(feature: "mock") { + return ["foo": "bar"] + } + core.update(feature: "mock") { + return ["bizz": "bazz"] + } + + // Then + let context = contextProvider.read() + XCTAssertEqual(context.featuresAttributes["mock"]?.foo, "bar") + XCTAssertEqual(context.featuresAttributes["mock"]?.bizz, "bazz") + } } diff --git a/Tests/DatadogTests/Datadog/DatadogInternal/Context/FeatureBaggageTests.swift b/Tests/DatadogTests/Datadog/DatadogInternal/Context/FeatureBaggageTests.swift index 8b49944781..9e8505411f 100644 --- a/Tests/DatadogTests/Datadog/DatadogInternal/Context/FeatureBaggageTests.swift +++ b/Tests/DatadogTests/Datadog/DatadogInternal/Context/FeatureBaggageTests.swift @@ -47,4 +47,14 @@ class FeatureBaggageTests: XCTestCase { attributes.int = 2 XCTAssertEqual(attributes.int, 2) } + + func testMerge() { + var attributes = attributes + attributes.merge(with: ["string": "test2"]) + + XCTAssertEqual(attributes.int, 1) + XCTAssertEqual(attributes.double, 2.0) + XCTAssertEqual(attributes.string, "test2") + XCTAssertEqual(attributes.enum, EnumAttribute.test) + } } diff --git a/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift b/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift index ee363e7ef5..dd5a48acd5 100644 --- a/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift +++ b/Tests/DatadogTests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift @@ -87,6 +87,10 @@ internal class DatadogCoreProxy: DatadogCoreProtocol { core.set(feature: feature, attributes: attributes) } + func update(feature: String, attributes: @escaping () -> FeatureBaggage) { + core.update(feature: feature, attributes: attributes) + } + func send(message: FeatureMessage, sender: DatadogCoreProtocol, else fallback: @escaping () -> Void) { core.send(message: message, sender: self, else: fallback) } From adfc9d14e4c15b8b8f7915b7d4af90bd6945e4ec Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 13:57:33 +0200 Subject: [PATCH 56/87] Apply code review changes --- .../DebugLoggingViewController.swift | 3 +-- DatadogCore/Sources/Datadog.swift | 25 +++++++++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Datadog/Example/Debugging/DebugLoggingViewController.swift b/Datadog/Example/Debugging/DebugLoggingViewController.swift index 498eca828f..449a459259 100644 --- a/Datadog/Example/Debugging/DebugLoggingViewController.swift +++ b/Datadog/Example/Debugging/DebugLoggingViewController.swift @@ -94,8 +94,7 @@ class DebugLoggingViewController: UIViewController { return Logger.create( with: Logger.Configuration( name: "stress-logger-\(index)", - networkInfoEnabled - : true + networkInfoEnabled: true ) ) } diff --git a/DatadogCore/Sources/Datadog.swift b/DatadogCore/Sources/Datadog.swift index 8736c79357..209a4d7073 100644 --- a/DatadogCore/Sources/Datadog.swift +++ b/DatadogCore/Sources/Datadog.swift @@ -14,16 +14,20 @@ import DatadogInternal /// /// Initialize the core instance of the Datadog SDK prior to enabling any Product. /// -/// Datadog.initialize( -/// with: Datadog.Configuration(clientToken: "", env: ""), -/// trackingConsent: .pending -/// ) +/// ```swift +/// Datadog.initialize( +/// with: Datadog.Configuration(clientToken: "", env: ""), +/// trackingConsent: .pending +/// ) +/// ``` /// /// Once Datadog SDK is initialized, you can enable products, such as RUM: /// -/// RUM.enable( -/// with: RUM.Configuration(applicationID: "") -/// ) +/// ```swift +/// RUM.enable( +/// with: RUM.Configuration(applicationID: "") +/// ) +/// ``` /// public struct Datadog { /// Configuration of Datadog SDK. @@ -244,17 +248,20 @@ public struct Datadog { /// /// You **must** initialize the core instance of the Datadog SDK prior to enabling any Product. /// + /// ```swift /// Datadog.initialize( /// with: Datadog.Configuration(clientToken: "", env: ""), /// trackingConsent: .pending /// ) + /// ``` /// /// Once Datadog SDK is initialized, you can enable products, such as RUM: /// + /// ```swift /// RUM.enable( /// with: RUM.Configuration(applicationID: "") /// ) - /// + /// ``` /// It is possible to initialize multiple instances of the SDK, associating them with a name. /// Many methods of the SDK can optionally take a SDK instance as an argument. If not provided, /// the call will be associated with the default (nameless) SDK instance. @@ -262,6 +269,7 @@ public struct Datadog { /// To use a secondary instance of the SDK, provide a name to the ``initialize`` method /// and use the returned instance to enable products: /// + /// ```swift /// let core = Datadog.initialize( /// with: Datadog.Configuration(clientToken: "", env: ""), /// trackingConsent: .pending, @@ -272,6 +280,7 @@ public struct Datadog { /// with: RUM.Configuration(applicationID: ""), /// in: core /// ) + /// ``` /// /// - Parameters: /// - configuration: the SDK configuration. From 2ab269cdb4c51665230462a5e79ac2ad27c440ab Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 13:47:31 +0200 Subject: [PATCH 57/87] RUMM-3404 Update MIGRATION.md --- MIGRATION.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/MIGRATION.md b/MIGRATION.md index b4c0dc2dab..f065f617cb 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -16,6 +16,46 @@ In comparison with version 1.x where all products were in a single module `Datad These come in addition to the existing `DatadogCrashReporting` and `DatadogObjc`. +
+ SPM + + ```swift +let package = Package( + ... + dependencies: [ + .package(url: "https://github.com/DataDog/dd-sdk-ios", from: "2.0.0") + ], + targets: [ + .target( + ... + dependencies: [ + .product(name: "DatadogCore", package: "dd-sdk-ios"), + .product(name: "DatadogLogs", package: "dd-sdk-ios"), + .product(name: "DatadogTrace", package: "dd-sdk-ios"), + .product(name: "DatadogRUM", package: "dd-sdk-ios"), + .product(name: "DatadogCrashReporting", package: "dd-sdk-ios"), + .product(name: "DatadogWebViewTracking", package: "dd-sdk-ios"), + ] + ), + ] +) + ``` +
+ +
+ CocoaPods + + ```ruby + pod 'DatadogCore' + pod 'DatadogLogs' + pod 'DatadogTrace' + pod 'DatadogRUM' + pod 'DatadogCrashReporting' + pod 'DatadogWebViewTracking' + pod 'DatadogObjc' + ``` +
+ **NOTE**: In case of Crash Reporting and WebView Tracking usage it's also needed to add RUM and/or Logs modules to be able to report events to RUM and/or Logs respectively. The `2.0` version of the iOS SDK also exposes unified API layouts and naming between iOS and Android SDKs and with other Datadog products. From fa13af1fcccbd97fd083c0fe27eecc24fcd55317 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 14:47:00 +0200 Subject: [PATCH 58/87] RUMM-3404 Add Carthage to migration guide --- MIGRATION.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/MIGRATION.md b/MIGRATION.md index f065f617cb..6c7ce57287 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -56,6 +56,31 @@ let package = Package( ``` +
+ Carthage + + The `Cartfile` stays the same: + ``` + github "DataDog/dd-sdk-ios" + ``` + + In Xcode, you **must** link the following frameworks: + ``` + DatadogInternal.xcframework + DatadogCore.xcframework + ``` + + Then you can select the modules you want to use: + ``` + DatadogLogs.xcframework + DatadogTrace.xcframework + DatadogRUM.xcframework + DatadogCrashReporting.xcframework + CrashReporter.xcframework + DatadogWebViewTracking.xcframework + DatadogObjc.xcframework + ``` +
+ **NOTE**: In case of Crash Reporting and WebView Tracking usage it's also needed to add RUM and/or Logs modules to be able to report events to RUM and/or Logs respectively. The `2.0` version of the iOS SDK also exposes unified API layouts and naming between iOS and Android SDKs and with other Datadog products. From 924143d9414013a1f8154227479357b4321f49b0 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 3 Jul 2023 15:53:00 +0200 Subject: [PATCH 59/87] RUMM-3387 Align webview tracking public api --- Datadog/Datadog.xcodeproj/project.pbxproj | 66 ++++---- .../DebugWebviewViewController.swift | 5 +- .../Sources/DDScriptMessageHandler.swift | 43 +++++ .../Sources/MessageEmitter.swift | 56 +++++++ .../WKUserContentController+Datadog.swift | 142 ----------------- ...kingMessage.swift => WebViewMessage.swift} | 20 +-- .../Sources/WebViewTracking.swift | 149 +++++++++++++----- ...ts.swift => MessageEmitterCoreTests.swift} | 14 +- ...Tests.swift => WebViewTrackingTests.swift} | 52 +++--- ...WebViewTrackingFixtureViewController.swift | 7 +- 10 files changed, 301 insertions(+), 253 deletions(-) create mode 100644 DatadogWebViewTracking/Sources/DDScriptMessageHandler.swift create mode 100644 DatadogWebViewTracking/Sources/MessageEmitter.swift delete mode 100644 DatadogWebViewTracking/Sources/WKUserContentController+Datadog.swift rename DatadogWebViewTracking/Sources/{WebViewTrackingMessage.swift => WebViewMessage.swift} (71%) rename DatadogWebViewTracking/Tests/{WebViewTrackingCoreTests.swift => MessageEmitterCoreTests.swift} (93%) rename DatadogWebViewTracking/Tests/{WKUserContentController+DatadogTests.swift => WebViewTrackingTests.swift} (88%) diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index 60e6666874..69b9a6f0f1 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -10,16 +10,14 @@ 3C41693C29FBF4D50042B9D2 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; }; 3C41694729FBF8CC0042B9D2 /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2DA2385298D57AA00C6C7E6 /* DatadogInternal.framework */; }; 3C74305C29FBC0480053B80F /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2DA2385298D57AA00C6C7E6 /* DatadogInternal.framework */; }; - 3C85D41B29F7C5C300AFF894 /* WKUserContentController+DatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */; }; - 3C85D41C29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */; }; - 3C85D41D29F7C5C400AFF894 /* WKUserContentController+DatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */; }; - 3C85D41E29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */; }; - 3C85D41F29F7C5C900AFF894 /* WebViewTrackingMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */; }; - 3C85D42029F7C5C900AFF894 /* WKUserContentController+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */; }; - 3C85D42129F7C5C900AFF894 /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */; }; - 3C85D42229F7C5CA00AFF894 /* WebViewTrackingMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */; }; - 3C85D42329F7C5CA00AFF894 /* WKUserContentController+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */; }; - 3C85D42429F7C5CA00AFF894 /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */; }; + 3C85D41B29F7C5C300AFF894 /* WebViewTrackingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WebViewTrackingTests.swift */; }; + 3C85D41C29F7C5C400AFF894 /* MessageEmitterCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* MessageEmitterCoreTests.swift */; }; + 3C85D41D29F7C5C400AFF894 /* WebViewTrackingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WebViewTrackingTests.swift */; }; + 3C85D41E29F7C5C400AFF894 /* MessageEmitterCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* MessageEmitterCoreTests.swift */; }; + 3C85D41F29F7C5C900AFF894 /* WebViewMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewMessage.swift */; }; + 3C85D42129F7C5C900AFF894 /* MessageEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* MessageEmitter.swift */; }; + 3C85D42229F7C5CA00AFF894 /* WebViewMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewMessage.swift */; }; + 3C85D42429F7C5CA00AFF894 /* MessageEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* MessageEmitter.swift */; }; 3C85D42929F7C6FD00AFF894 /* TestUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D257958B298ABB83008A1BE5 /* TestUtilities.framework */; }; 3C85D42A29F7C70300AFF894 /* TestUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D257953E298ABA65008A1BE5 /* TestUtilities.framework */; }; 3C85D42C29F7C87D00AFF894 /* HostsSanitizerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */; }; @@ -865,6 +863,10 @@ D2A7841029A53B2F003B03BB /* Directory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BAB2423979B00786299 /* Directory.swift */; }; D2A7841129A53B2F003B03BB /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BAC2423979B00786299 /* File.swift */; }; D2A7841229A53B2F003B03BB /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BAC2423979B00786299 /* File.swift */; }; + D2ADE2E52A52EA5D001A0FFB /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E42A52EA5D001A0FFB /* WebViewTracking.swift */; }; + D2ADE2E62A52EA5D001A0FFB /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E42A52EA5D001A0FFB /* WebViewTracking.swift */; }; + D2ADE2E82A52ECB4001A0FFB /* DDScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E72A52ECB4001A0FFB /* DDScriptMessageHandler.swift */; }; + D2ADE2E92A52ECB4001A0FFB /* DDScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E72A52ECB4001A0FFB /* DDScriptMessageHandler.swift */; }; D2B249942A4598FE00DD4F9F /* LoggerProtocol+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B249932A4598FE00DD4F9F /* LoggerProtocol+Internal.swift */; }; D2B249952A4598FE00DD4F9F /* LoggerProtocol+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B249932A4598FE00DD4F9F /* LoggerProtocol+Internal.swift */; }; D2B249972A45E10500DD4F9F /* LoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B249962A45E10500DD4F9F /* LoggerTests.swift */; }; @@ -1668,11 +1670,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewTracking.swift; sourceTree = ""; }; - 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewTrackingMessage.swift; sourceTree = ""; }; - 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WKUserContentController+Datadog.swift"; sourceTree = ""; }; - 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewTrackingCoreTests.swift; sourceTree = ""; }; - 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "WKUserContentController+DatadogTests.swift"; sourceTree = ""; }; + 3C85D41429F7C59C00AFF894 /* MessageEmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageEmitter.swift; sourceTree = ""; }; + 3C85D41529F7C59C00AFF894 /* WebViewMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewMessage.swift; sourceTree = ""; }; + 3C85D41729F7C5BE00AFF894 /* MessageEmitterCoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageEmitterCoreTests.swift; sourceTree = ""; }; + 3C85D41829F7C5BE00AFF894 /* WebViewTrackingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewTrackingTests.swift; sourceTree = ""; }; 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HostsSanitizerMock.swift; sourceTree = ""; }; 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogWebViewTracking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DatadogWebViewTrackingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2245,6 +2246,8 @@ D2A38DDA29C37E1B007C6900 /* TracingURLSessionHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingURLSessionHandlerTests.swift; sourceTree = ""; }; D2A7840129A534F9003B03BB /* DatadogLogsTests tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "DatadogLogsTests tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D2A7840229A536AD003B03BB /* PrintFunctionMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrintFunctionMock.swift; sourceTree = ""; }; + D2ADE2E42A52EA5D001A0FFB /* WebViewTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewTracking.swift; sourceTree = ""; }; + D2ADE2E72A52ECB4001A0FFB /* DDScriptMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDScriptMessageHandler.swift; sourceTree = ""; }; D2B249932A4598FE00DD4F9F /* LoggerProtocol+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoggerProtocol+Internal.swift"; sourceTree = ""; }; D2B249962A45E10500DD4F9F /* LoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggerTests.swift; sourceTree = ""; }; D2B3F0432823EE8300C2B5EE /* DataBlockTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBlockTests.swift; sourceTree = ""; }; @@ -2683,9 +2686,10 @@ 3CE11A3B29F7BEE700202522 /* DatadogWebViewTracking */ = { isa = PBXGroup; children = ( - 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */, - 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */, - 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */, + D2ADE2E42A52EA5D001A0FFB /* WebViewTracking.swift */, + 3C85D41429F7C59C00AFF894 /* MessageEmitter.swift */, + 3C85D41529F7C59C00AFF894 /* WebViewMessage.swift */, + D2ADE2E72A52ECB4001A0FFB /* DDScriptMessageHandler.swift */, ); name = DatadogWebViewTracking; path = ../DatadogWebViewTracking/Sources; @@ -2694,8 +2698,8 @@ 3CE11A3C29F7BEF300202522 /* DatadogWebViewTrackingTests */ = { isa = PBXGroup; children = ( - 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */, - 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */, + 3C85D41829F7C5BE00AFF894 /* WebViewTrackingTests.swift */, + 3C85D41729F7C5BE00AFF894 /* MessageEmitterCoreTests.swift */, ); name = DatadogWebViewTrackingTests; path = ../DatadogWebViewTracking/Tests; @@ -6351,9 +6355,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3C85D42129F7C5C900AFF894 /* WebViewTracking.swift in Sources */, - 3C85D41F29F7C5C900AFF894 /* WebViewTrackingMessage.swift in Sources */, - 3C85D42029F7C5C900AFF894 /* WKUserContentController+Datadog.swift in Sources */, + D2ADE2E82A52ECB4001A0FFB /* DDScriptMessageHandler.swift in Sources */, + D2ADE2E52A52EA5D001A0FFB /* WebViewTracking.swift in Sources */, + 3C85D42129F7C5C900AFF894 /* MessageEmitter.swift in Sources */, + 3C85D41F29F7C5C900AFF894 /* WebViewMessage.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6361,8 +6366,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3C85D41B29F7C5C300AFF894 /* WKUserContentController+DatadogTests.swift in Sources */, - 3C85D41C29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */, + 3C85D41B29F7C5C300AFF894 /* WebViewTrackingTests.swift in Sources */, + 3C85D41C29F7C5C400AFF894 /* MessageEmitterCoreTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6370,9 +6375,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3C85D42429F7C5CA00AFF894 /* WebViewTracking.swift in Sources */, - 3C85D42229F7C5CA00AFF894 /* WebViewTrackingMessage.swift in Sources */, - 3C85D42329F7C5CA00AFF894 /* WKUserContentController+Datadog.swift in Sources */, + D2ADE2E92A52ECB4001A0FFB /* DDScriptMessageHandler.swift in Sources */, + D2ADE2E62A52EA5D001A0FFB /* WebViewTracking.swift in Sources */, + 3C85D42429F7C5CA00AFF894 /* MessageEmitter.swift in Sources */, + 3C85D42229F7C5CA00AFF894 /* WebViewMessage.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6380,8 +6386,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3C85D41D29F7C5C400AFF894 /* WKUserContentController+DatadogTests.swift in Sources */, - 3C85D41E29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */, + 3C85D41D29F7C5C400AFF894 /* WebViewTrackingTests.swift in Sources */, + 3C85D41E29F7C5C400AFF894 /* MessageEmitterCoreTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Datadog/Example/Debugging/DebugWebviewViewController.swift b/Datadog/Example/Debugging/DebugWebviewViewController.swift index 0e1d514abb..4fc885c7da 100644 --- a/Datadog/Example/Debugging/DebugWebviewViewController.swift +++ b/Datadog/Example/Debugging/DebugWebviewViewController.swift @@ -89,11 +89,12 @@ class WebviewViewController: UIViewController { super.viewDidLoad() let controller = WKUserContentController() - controller.startTrackingDatadogEvents(core: CoreRegistry.default) let config = WKWebViewConfiguration() config.userContentController = controller - webView = WKWebView(frame: UIScreen.main.bounds, configuration: config) + + WebViewTracking.enable(webview: webView) + view.addSubview(webView) } diff --git a/DatadogWebViewTracking/Sources/DDScriptMessageHandler.swift b/DatadogWebViewTracking/Sources/DDScriptMessageHandler.swift new file mode 100644 index 0000000000..fe36c1d2ef --- /dev/null +++ b/DatadogWebViewTracking/Sources/DDScriptMessageHandler.swift @@ -0,0 +1,43 @@ +/* + * 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 2019-Present Datadog, Inc. + */ + +#if !os(tvOS) + +import Foundation +import WebKit +import DatadogInternal + +internal class DDScriptMessageHandler: NSObject, WKScriptMessageHandler { + static let name = "DatadogEventBridge" + + private let emitter: MessageEmitter + + let queue = DispatchQueue( + label: "com.datadoghq.JSEventBridge", + target: .global(qos: .userInteractive) + ) + + init(emitter: MessageEmitter) { + self.emitter = emitter + } + + func userContentController( + _ userContentController: WKUserContentController, + didReceive message: WKScriptMessage + ) { + // message.body must be called within UI thread + let messageBody = message.body + queue.async { + do { + try self.emitter.send(body: messageBody) + } catch { + DD.logger.error("Encountered an error when receiving web view event", error: error) + } + } + } +} + +#endif diff --git a/DatadogWebViewTracking/Sources/MessageEmitter.swift b/DatadogWebViewTracking/Sources/MessageEmitter.swift new file mode 100644 index 0000000000..5c3d1d10e9 --- /dev/null +++ b/DatadogWebViewTracking/Sources/MessageEmitter.swift @@ -0,0 +1,56 @@ +/* + * 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 2019-Present Datadog, Inc. + */ + +import DatadogInternal + +/// Defines methods to send WebView related messages +public protocol MessageEmitter { + /// Sends a web-view message. + /// + /// - Parameter message: The message to send + func send(message: WebViewMessage) throws +} + +/// Datadog implementation of `MessageEmitter`. +internal struct MessageEmitterCore: MessageEmitter { + enum MessageKeys { + static let browserLog = "browser-log" + static let browserRUMEvent = "browser-rum-event" + } + + private weak var core: DatadogCoreProtocol? + + internal init(core: DatadogCoreProtocol) { + self.core = core + } + + /// Sends a message to the message bus + /// - Parameter message: The message to send + internal func send(message: WebViewMessage) throws { + if core == nil { + DD.logger.debug("Core must not be nil when using WebViewTracking") + } + switch message { + case let .log(event): + core?.send(message: .custom(key: MessageKeys.browserLog, baggage: .init(event)), else: { + DD.logger.warn("A WebView log is lost because Logging is disabled in the SDK") + }) + case let .rum(event): + core?.send(message: .custom(key: MessageKeys.browserRUMEvent, baggage: .init(event)), else: { + DD.logger.warn("A WebView RUM event is lost because RUM is disabled in the SDK") + }) + } + } +} + +extension MessageEmitter { + /// Sends a bag of data to the message bus + /// - Parameter body: The data to send, it must be parsable to `WebViewMessage` + internal func send(body: Any) throws { + let message = try WebViewMessage(body: body) + try send(message: message) + } +} diff --git a/DatadogWebViewTracking/Sources/WKUserContentController+Datadog.swift b/DatadogWebViewTracking/Sources/WKUserContentController+Datadog.swift deleted file mode 100644 index a90d7e9a0a..0000000000 --- a/DatadogWebViewTracking/Sources/WKUserContentController+Datadog.swift +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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 2019-Present Datadog, Inc. - */ - -#if !os(tvOS) - -import Foundation -import WebKit -import DatadogInternal - -public extension WKUserContentController { - private static let jsCodePrefix = "/* DatadogEventBridge */" - - private var isTracking: Bool { - return userScripts.contains { - return $0.source.starts(with: Self.jsCodePrefix) - } - } - - /// Enables SDK to correlate Datadog RUM events and Logs from the WebView with native RUM session. - /// - /// If the content loaded in WebView uses Datadog Browser SDK (`v4.2.0+`) and matches specified `hosts`, web events will be correlated - /// with the RUM session from native SDK. - /// - /// - Parameter core: Datadog SDK core to use for tracking - /// - Parameter hosts: a set of hosts instrumented with Browser SDK to capture Datadog events from - func startTrackingDatadogEvents(core: DatadogCoreProtocol = CoreRegistry.default, hosts: Set = []) { - do { - try startTrackingDatadogEventsOrThrow(core: core, hosts: hosts) - } catch { - consolePrint("\(error)") - } - } - - private func startTrackingDatadogEventsOrThrow(core: DatadogCoreProtocol, hosts: Set) throws { - addDatadogMessageHandler( - core: core, - allowedWebViewHosts: hosts, - hostsSanitizer: HostsSanitizer() - ) - } - - /// Disables Datadog iOS SDK and Datadog Browser SDK integration. - /// - /// Removes Datadog's ScriptMessageHandler and UserScript from the caller. - /// - Note: This method **must** be called when the webview can be deinitialized. - func stopTrackingDatadogEvents() { - removeScriptMessageHandler(forName: DatadogMessageHandler.name) - - let nonDatadogUserScripts = userScripts.filter { - return !$0.source.starts(with: Self.jsCodePrefix) - } - removeAllUserScripts() - nonDatadogUserScripts.forEach { - addUserScript($0) - } - } - - internal func addDatadogMessageHandler( - core: DatadogCoreProtocol, - allowedWebViewHosts: Set, - hostsSanitizer: HostsSanitizing - ) { - guard !isTracking else { - DD.logger.warn("`startTrackingDatadogEvents(core:hosts:)` was called more than once for the same WebView. Second call will be ignored. Make sure you call it only once.") - return - } - - let bridgeName = DatadogMessageHandler.name - - let messageHandler = DatadogMessageHandler( - eventBridge: WebViewTrackingCore(core: core) - ) - - add(messageHandler, name: bridgeName) - - // WebKit installs message handlers with the given name format below - // We inject a user script to forward `window.{bridgeName}` to WebKit's format - let webkitMethodName = "window.webkit.messageHandlers.\(bridgeName).postMessage" - // `WKScriptMessageHandlerWithReply` returns `Promise` and `browser-sdk` expects immediate values. - // We inject a user script to return `allowedWebViewHosts` instead of using `WKScriptMessageHandlerWithReply` - let sanitizedHosts = hostsSanitizer.sanitized( - hosts: allowedWebViewHosts, - warningMessage: "The allowed WebView host configured for Datadog SDK is not valid" - ) - let allowedWebViewHostsString = sanitizedHosts - .map { return "\"\($0)\"" } - .joined(separator: ",") - - let js = """ - \(Self.jsCodePrefix) - window.\(bridgeName) = { - send(msg) { - \(webkitMethodName)(msg) - }, - getAllowedWebViewHosts() { - return '[\(allowedWebViewHostsString)]' - } - } - """ - - addUserScript( - WKUserScript( - source: js, - injectionTime: .atDocumentStart, - forMainFrameOnly: false - ) - ) - } -} - -internal class DatadogMessageHandler: NSObject, WKScriptMessageHandler { - static let name = "DatadogEventBridge" - private let eventBridge: WebViewTracking - let queue = DispatchQueue( - label: "com.datadoghq.JSEventBridge", - target: .global(qos: .userInteractive) - ) - - init(eventBridge: WebViewTracking) { - self.eventBridge = eventBridge - } - - func userContentController( - _ userContentController: WKUserContentController, - didReceive message: WKScriptMessage - ) { - // message.body must be called within UI thread - let messageBody = message.body - queue.async { - do { - try self.eventBridge.send(body: messageBody) - } catch { - DD.logger.error("Encountered an error when receiving web view event", error: error) - } - } - } -} - -#endif diff --git a/DatadogWebViewTracking/Sources/WebViewTrackingMessage.swift b/DatadogWebViewTracking/Sources/WebViewMessage.swift similarity index 71% rename from DatadogWebViewTracking/Sources/WebViewTrackingMessage.swift rename to DatadogWebViewTracking/Sources/WebViewMessage.swift index 64140a9adc..c8f25c9ee9 100644 --- a/DatadogWebViewTracking/Sources/WebViewTrackingMessage.swift +++ b/DatadogWebViewTracking/Sources/WebViewMessage.swift @@ -6,10 +6,10 @@ import Foundation -internal typealias JSON = [String: Any] +public typealias JSON = [String: Any] /// Intermediate type to parse WebView messages and send them to the message bus -internal enum WebViewTrackingMessage { +public enum WebViewMessage { /// A log message with a JSON payload case log(JSON) @@ -18,14 +18,14 @@ internal enum WebViewTrackingMessage { } /// Errors that can be thrown when parsing a WebView message -internal enum WebViewTrackingMessageError: Error, Equatable { +internal enum WebViewMessageError: Error, Equatable { case dataSerialization(message: String) case JSONDeserialization(rawJSONDescription: String) case invalidMessage(description: String) case missingKey(key: String) } -extension WebViewTrackingMessage { +extension WebViewMessage { internal enum Keys { static let eventType = "eventType" static let event = "event" @@ -39,17 +39,17 @@ extension WebViewTrackingMessage { /// - Parameter body: Unstructured bag of data internal init(body: Any) throws { guard let message = body as? String else { - throw WebViewTrackingMessageError.invalidMessage(description: String(describing: body)) + throw WebViewMessageError.invalidMessage(description: String(describing: body)) } - let eventJSON = try WebViewTrackingMessage.parse(message) + let eventJSON = try WebViewMessage.parse(message) guard let type = eventJSON[Keys.eventType] as? String else { - throw WebViewTrackingMessageError.missingKey(key: Keys.eventType) + throw WebViewMessageError.missingKey(key: Keys.eventType) } guard let event = eventJSON[Keys.event] as? JSON else { - throw WebViewTrackingMessageError.missingKey(key: Keys.event) + throw WebViewMessageError.missingKey(key: Keys.event) } switch type { @@ -62,11 +62,11 @@ extension WebViewTrackingMessage { private static func parse(_ message: String) throws -> JSON { guard let data = message.data(using: .utf8) else { - throw WebViewTrackingMessageError.dataSerialization(message: message) + throw WebViewMessageError.dataSerialization(message: message) } let rawJSON = try JSONSerialization.jsonObject(with: data, options: []) guard let json = rawJSON as? JSON else { - throw WebViewTrackingMessageError.JSONDeserialization(rawJSONDescription: String(describing: rawJSON)) + throw WebViewMessageError.JSONDeserialization(rawJSONDescription: String(describing: rawJSON)) } return json } diff --git a/DatadogWebViewTracking/Sources/WebViewTracking.swift b/DatadogWebViewTracking/Sources/WebViewTracking.swift index 40028adec4..cb23da403e 100644 --- a/DatadogWebViewTracking/Sources/WebViewTracking.swift +++ b/DatadogWebViewTracking/Sources/WebViewTracking.swift @@ -4,55 +4,126 @@ * Copyright 2019-Present Datadog, Inc. */ +import Foundation import DatadogInternal -/// Defines methods to send WebView related information -internal protocol WebViewTracking { - /// Sends a message - /// - Parameter message: The message to send - func send(message: WebViewTrackingMessage) throws -} +#if !os(tvOS) +import WebKit +#endif -/// Datadog implementation of `WebViewTracking` -/// - Note: -/// Cross platform SDKs should instantiate this type with a `DatadogCoreProtocol` implementation -/// and pass WebView related messages using the message bus of the core. -internal struct WebViewTrackingCore: WebViewTracking { - enum MessageKeys { - static let browserLog = "browser-log" - static let browserRUMEvent = "browser-rum-event" +/// Real User Monitoring allows you to monitor web views and eliminate blind spots in your hybrid iOS applications. +/// +/// # Prerequisites: +/// Set up the web page you want rendered on your mobile iOS and tvOS application with the RUM Browser SDK +/// first. For more information, see [RUM Browser Monitoring](https://docs.datadoghq.com/real_user_monitoring/browser/#npm). +/// +/// You can perform the following: +/// - Track user journeys across web and native components in mobile applications +/// - Scope the root cause of latency to web pages or native components in mobile applications +/// - Support users that have difficulty loading web pages on mobile devices +public final class WebViewTracking { +#if !os(tvOS) + /// Enables SDK to correlate Datadog RUM events and Logs from the WebView with native RUM session. + /// + /// If the content loaded in WebView uses Datadog Browser SDK (`v4.2.0+`) and matches specified + /// `hosts`, web events will be correlated with the RUM session from native SDK. + /// + /// - Parameters: + /// - webview: The web-view to track. + /// - hosts: A set of hosts instrumented with Browser SDK to capture Datadog events from. + /// - core: Datadog SDK core to use for tracking. + public static func enable( + webview: WKWebView, + hosts: Set = [], + in core: DatadogCoreProtocol = CoreRegistry.default + ) { + enable( + tracking: webview.configuration.userContentController, + hosts: hosts, + hostsSanitizer: HostsSanitizer(), + in: core + ) } - private weak var core: DatadogCoreProtocol? - - internal init(core: DatadogCoreProtocol) { - self.core = core + /// Disables Datadog iOS SDK and Datadog Browser SDK integration. + /// + /// Removes Datadog's ScriptMessageHandler and UserScript from the caller. + /// - Note: This method **must** be called when the webview can be deinitialized. + /// + /// - Parameter webview: The web-view to stop tracking. + public static func disable(webview: WKWebView) { + let controller = webview.configuration.userContentController + controller.removeScriptMessageHandler(forName: DDScriptMessageHandler.name) + let others = controller.userScripts.filter { !$0.source.starts(with: Self.jsCodePrefix) } + controller.removeAllUserScripts() + others.forEach(controller.addUserScript) } - /// Sends a message to the message bus - /// - Parameter message: The message to send - internal func send(message: WebViewTrackingMessage) throws { - if core == nil { - DD.logger.debug("Core must not be nil when using WebViewTracking") - } - switch message { - case let .log(event): - core?.send(message: .custom(key: MessageKeys.browserLog, baggage: .init(event)), else: { - DD.logger.warn("A WebView log is lost because Logging is disabled in the SDK") - }) - case let .rum(event): - core?.send(message: .custom(key: MessageKeys.browserRUMEvent, baggage: .init(event)), else: { - DD.logger.warn("A WebView RUM event is lost because RUM is disabled in the SDK") - }) + // MARK: Internal + + static let jsCodePrefix = "/* DatadogEventBridge */" + + static func enable(tracking controller: WKUserContentController, hosts: Set, hostsSanitizer: HostsSanitizing, in core: DatadogCoreProtocol) { + let isTracking = controller.userScripts.contains { $0.source.starts(with: Self.jsCodePrefix) } + guard !isTracking else { + DD.logger.warn("`startTrackingDatadogEvents(core:hosts:)` was called more than once for the same WebView. Second call will be ignored. Make sure you call it only once.") + return + } + + let bridgeName = DDScriptMessageHandler.name + + let messageHandler = DDScriptMessageHandler( + emitter: MessageEmitterCore(core: core) + ) + + controller.add(messageHandler, name: bridgeName) + + // WebKit installs message handlers with the given name format below + // We inject a user script to forward `window.{bridgeName}` to WebKit's format + let webkitMethodName = "window.webkit.messageHandlers.\(bridgeName).postMessage" + // `WKScriptMessageHandlerWithReply` returns `Promise` and `browser-sdk` expects immediate values. + // We inject a user script to return `allowedWebViewHosts` instead of using `WKScriptMessageHandlerWithReply` + let sanitizedHosts = hostsSanitizer.sanitized( + hosts: hosts, + warningMessage: "The allowed WebView host configured for Datadog SDK is not valid" + ) + let allowedWebViewHostsString = sanitizedHosts + .map { return "\"\($0)\"" } + .joined(separator: ",") + + let js = """ + \(Self.jsCodePrefix) + window.\(bridgeName) = { + send(msg) { + \(webkitMethodName)(msg) + }, + getAllowedWebViewHosts() { + return '[\(allowedWebViewHostsString)]' + } } + """ + + controller.addUserScript( + WKUserScript( + source: js, + injectionTime: .atDocumentStart, + forMainFrameOnly: false + ) + ) } +#endif } -extension WebViewTracking { - /// Sends a bag of data to the message bus - /// - Parameter body: The data to send, it must be parsable to `WebViewTrackingMessage` - internal func send(body: Any) throws { - let message = try WebViewTrackingMessage(body: body) - try send(message: message) +extension WebViewTracking: InternalExtended { } +extension InternalExtension where ExtendedType: WebViewTracking { + /// Creates a web-view message emitter for cross-platform. + /// + /// Cross platform SDKs should instantiate a `MessageEmitter` implementation from + /// this method and pass WebView related messages using the message bus of the core. + /// + /// - Parameter core: The Datadog SDK core instance + /// - Returns: A `MessageEmitter` instance + public static func messageEmitter(in core: DatadogCoreProtocol) -> MessageEmitter { + return MessageEmitterCore(core: core) } } diff --git a/DatadogWebViewTracking/Tests/WebViewTrackingCoreTests.swift b/DatadogWebViewTracking/Tests/MessageEmitterCoreTests.swift similarity index 93% rename from DatadogWebViewTracking/Tests/WebViewTrackingCoreTests.swift rename to DatadogWebViewTracking/Tests/MessageEmitterCoreTests.swift index 3e88ab89e4..b12d49994d 100644 --- a/DatadogWebViewTracking/Tests/WebViewTrackingCoreTests.swift +++ b/DatadogWebViewTracking/Tests/MessageEmitterCoreTests.swift @@ -10,11 +10,11 @@ import DatadogInternal @testable import DatadogWebViewTracking -class WebViewTrackingCoreTests: XCTestCase { +class MessageEmitterCoreTests: XCTestCase { // MARK: - Parsing func testWhenMessageIsInvalid_itFailsParsing() { - let bridge = WebViewTrackingCore(core: PassthroughCoreMock()) + let bridge = MessageEmitterCore(core: PassthroughCoreMock()) let messageInvalidJSON = """ { 123: foobar } @@ -29,7 +29,7 @@ class WebViewTrackingCoreTests: XCTestCase { // MARK: - Routing func testWhenEventTypeIsMissing_itThrows() { - let bridge = WebViewTrackingCore(core: PassthroughCoreMock()) + let bridge = MessageEmitterCore(core: PassthroughCoreMock()) let messageMissingEventType = """ { @@ -46,8 +46,8 @@ class WebViewTrackingCoreTests: XCTestCase { "Missing eventType should throw" ) { error in XCTAssertEqual( - error as? WebViewTrackingMessageError, - .missingKey(key: WebViewTrackingMessage.Keys.eventType) + error as? WebViewMessageError, + .missingKey(key: WebViewMessage.Keys.eventType) ) } } @@ -79,7 +79,7 @@ class WebViewTrackingCoreTests: XCTestCase { } ) - let bridge = WebViewTrackingCore(core: core) + let bridge = MessageEmitterCore(core: core) let messageLog = """ { @@ -125,7 +125,7 @@ class WebViewTrackingCoreTests: XCTestCase { } ) - let bridge = WebViewTrackingCore(core: core) + let bridge = MessageEmitterCore(core: core) let messageRUM = """ { diff --git a/DatadogWebViewTracking/Tests/WKUserContentController+DatadogTests.swift b/DatadogWebViewTracking/Tests/WebViewTrackingTests.swift similarity index 88% rename from DatadogWebViewTracking/Tests/WKUserContentController+DatadogTests.swift rename to DatadogWebViewTracking/Tests/WebViewTrackingTests.swift index 4e337eada8..cd536eb526 100644 --- a/DatadogWebViewTracking/Tests/WKUserContentController+DatadogTests.swift +++ b/DatadogWebViewTracking/Tests/WebViewTrackingTests.swift @@ -41,17 +41,18 @@ final class MockScriptMessage: WKScriptMessage { override var body: Any { return mockBody } } -class WKUserContentController_DatadogTests: XCTestCase { +class WebViewTrackingTests: XCTestCase { func testItAddsUserScriptAndMessageHandler() throws { let mockSanitizer = HostsSanitizerMock() let controller = DDUserContentController() let initialUserScriptCount = controller.userScripts.count - controller.addDatadogMessageHandler( - core: PassthroughCoreMock(), - allowedWebViewHosts: ["datadoghq.com"], - hostsSanitizer: mockSanitizer + WebViewTracking.enable( + tracking: controller, + hosts: ["datadoghq.com"], + hostsSanitizer: mockSanitizer, + in: PassthroughCoreMock() ) XCTAssertEqual(controller.userScripts.count, initialUserScriptCount + 1) @@ -74,10 +75,11 @@ class WKUserContentController_DatadogTests: XCTestCase { let multipleTimes = 5 (0.. Date: Tue, 4 Jul 2023 13:20:33 +0200 Subject: [PATCH 60/87] RUMM-3387 rename webview to webView --- .../Debugging/DebugWebviewViewController.swift | 2 +- DatadogWebViewTracking/Sources/WebViewTracking.swift | 12 ++++++------ .../Tests/WebViewTrackingTests.swift | 4 ++-- .../WebViewTrackingFixtureViewController.swift | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Datadog/Example/Debugging/DebugWebviewViewController.swift b/Datadog/Example/Debugging/DebugWebviewViewController.swift index 4fc885c7da..9130c59ec3 100644 --- a/Datadog/Example/Debugging/DebugWebviewViewController.swift +++ b/Datadog/Example/Debugging/DebugWebviewViewController.swift @@ -93,7 +93,7 @@ class WebviewViewController: UIViewController { config.userContentController = controller webView = WKWebView(frame: UIScreen.main.bounds, configuration: config) - WebViewTracking.enable(webview: webView) + WebViewTracking.enable(webView: webView) view.addSubview(webView) } diff --git a/DatadogWebViewTracking/Sources/WebViewTracking.swift b/DatadogWebViewTracking/Sources/WebViewTracking.swift index cb23da403e..90d643b6e1 100644 --- a/DatadogWebViewTracking/Sources/WebViewTracking.swift +++ b/DatadogWebViewTracking/Sources/WebViewTracking.swift @@ -29,16 +29,16 @@ public final class WebViewTracking { /// `hosts`, web events will be correlated with the RUM session from native SDK. /// /// - Parameters: - /// - webview: The web-view to track. + /// - webView: The web-view to track. /// - hosts: A set of hosts instrumented with Browser SDK to capture Datadog events from. /// - core: Datadog SDK core to use for tracking. public static func enable( - webview: WKWebView, + webView: WKWebView, hosts: Set = [], in core: DatadogCoreProtocol = CoreRegistry.default ) { enable( - tracking: webview.configuration.userContentController, + tracking: webView.configuration.userContentController, hosts: hosts, hostsSanitizer: HostsSanitizer(), in: core @@ -50,9 +50,9 @@ public final class WebViewTracking { /// Removes Datadog's ScriptMessageHandler and UserScript from the caller. /// - Note: This method **must** be called when the webview can be deinitialized. /// - /// - Parameter webview: The web-view to stop tracking. - public static func disable(webview: WKWebView) { - let controller = webview.configuration.userContentController + /// - Parameter webView: The web-view to stop tracking. + public static func disable(webView: WKWebView) { + let controller = webView.configuration.userContentController controller.removeScriptMessageHandler(forName: DDScriptMessageHandler.name) let others = controller.userScripts.filter { !$0.source.starts(with: Self.jsCodePrefix) } controller.removeAllUserScripts() diff --git a/DatadogWebViewTracking/Tests/WebViewTrackingTests.swift b/DatadogWebViewTracking/Tests/WebViewTrackingTests.swift index cd536eb526..5288c5eae5 100644 --- a/DatadogWebViewTracking/Tests/WebViewTrackingTests.swift +++ b/DatadogWebViewTracking/Tests/WebViewTrackingTests.swift @@ -105,7 +105,7 @@ class WebViewTrackingTests: XCTestCase { let webview = WKWebView(frame: .zero, configuration: configuration) WebViewTracking.enable( - webview: webview, + webView: webview, in: core ) @@ -123,7 +123,7 @@ class WebViewTrackingTests: XCTestCase { XCTAssertEqual(controller.userScripts.count, componentCount + 1) XCTAssertEqual(controller.messageHandlers.count, componentCount + 1) - WebViewTracking.disable(webview: webview) + WebViewTracking.disable(webView: webview) XCTAssertEqual(controller.userScripts.count, componentCount) XCTAssertEqual(controller.messageHandlers.count, componentCount) diff --git a/IntegrationTests/Runner/Scenarios/WebView/WebViewTrackingFixtureViewController.swift b/IntegrationTests/Runner/Scenarios/WebView/WebViewTrackingFixtureViewController.swift index d548daf166..9f22d0e80c 100644 --- a/IntegrationTests/Runner/Scenarios/WebView/WebViewTrackingFixtureViewController.swift +++ b/IntegrationTests/Runner/Scenarios/WebView/WebViewTrackingFixtureViewController.swift @@ -36,14 +36,14 @@ class ShopistWebviewViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) WebViewTracking.enable( - webview: webView, + webView: webView, hosts: ["shopist.io"] ) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - WebViewTracking.disable(webview: webView) + WebViewTracking.disable(webView: webView) } override func viewDidAppear(_ animated: Bool) { From ff439559dda19f10e13af0caade530f7a7dbea80 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 11:44:28 +0200 Subject: [PATCH 61/87] RUMM-3387 Only ship WebView Tracking with iOS --- DatadogWebViewTracking.podspec | 1 - DatadogWebViewTracking/Sources/WebViewTracking.swift | 4 +++- tools/distribution/build-xcframework.sh | 7 ++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/DatadogWebViewTracking.podspec b/DatadogWebViewTracking.podspec index 0c3a2c2900..8f0c2c8522 100644 --- a/DatadogWebViewTracking.podspec +++ b/DatadogWebViewTracking.podspec @@ -16,7 +16,6 @@ Pod::Spec.new do |s| s.swift_version = '5.5' s.ios.deployment_target = '11.0' - s.tvos.deployment_target = '11.0' s.source = { :git => "https://github.com/DataDog/dd-sdk-ios.git", :tag => s.version.to_s } diff --git a/DatadogWebViewTracking/Sources/WebViewTracking.swift b/DatadogWebViewTracking/Sources/WebViewTracking.swift index 90d643b6e1..85652f7159 100644 --- a/DatadogWebViewTracking/Sources/WebViewTracking.swift +++ b/DatadogWebViewTracking/Sources/WebViewTracking.swift @@ -7,7 +7,9 @@ import Foundation import DatadogInternal -#if !os(tvOS) +#if os(tvOS) +#warning("Datadog WebView Tracking does not support tvOS") +#else import WebKit #endif diff --git a/tools/distribution/build-xcframework.sh b/tools/distribution/build-xcframework.sh index b8f843f0e9..2c97318684 100755 --- a/tools/distribution/build-xcframework.sh +++ b/tools/distribution/build-xcframework.sh @@ -98,4 +98,9 @@ bundle DatadogTrace bundle DatadogRUM bundle DatadogObjc bundle DatadogCrashReporting -bundle DatadogWebViewTracking + +# Build DatadogWebViewTracking for iOS only +if [[ $PLATFORM == *"iOS"* ]]; then + PLATFORM="iOS" + bundle DatadogWebViewTracking +fi \ No newline at end of file From 0e1944d69b0dba8aa9ed0b2a0d82a32cf964f4b1 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 11:49:44 +0200 Subject: [PATCH 62/87] RUMM-3387 WebViewTracking as enum --- DatadogWebViewTracking/Sources/WebViewTracking.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DatadogWebViewTracking/Sources/WebViewTracking.swift b/DatadogWebViewTracking/Sources/WebViewTracking.swift index 85652f7159..3d958d510c 100644 --- a/DatadogWebViewTracking/Sources/WebViewTracking.swift +++ b/DatadogWebViewTracking/Sources/WebViewTracking.swift @@ -23,7 +23,7 @@ import WebKit /// - Track user journeys across web and native components in mobile applications /// - Scope the root cause of latency to web pages or native components in mobile applications /// - Support users that have difficulty loading web pages on mobile devices -public final class WebViewTracking { +public enum WebViewTracking { #if !os(tvOS) /// Enables SDK to correlate Datadog RUM events and Logs from the WebView with native RUM session. /// From 7446049b16561d801355491f4e3fb866b852c0e9 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 13:19:42 +0200 Subject: [PATCH 63/87] RUMM-3387 Hide internal interfaces --- .../Sources/MessageEmitter.swift | 30 +++++++------------ .../Sources/WebViewMessage.swift | 4 +-- .../Sources/WebViewTracking.swift | 16 +++++++--- .../Tests/MessageEmitterCoreTests.swift | 8 ++--- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/DatadogWebViewTracking/Sources/MessageEmitter.swift b/DatadogWebViewTracking/Sources/MessageEmitter.swift index 5c3d1d10e9..a9ffb5a90e 100644 --- a/DatadogWebViewTracking/Sources/MessageEmitter.swift +++ b/DatadogWebViewTracking/Sources/MessageEmitter.swift @@ -6,16 +6,8 @@ import DatadogInternal -/// Defines methods to send WebView related messages -public protocol MessageEmitter { - /// Sends a web-view message. - /// - /// - Parameter message: The message to send - func send(message: WebViewMessage) throws -} - /// Datadog implementation of `MessageEmitter`. -internal struct MessageEmitterCore: MessageEmitter { +internal final class MessageEmitter: InternalExtension.AbstractMessageEmitter { enum MessageKeys { static let browserLog = "browser-log" static let browserRUMEvent = "browser-rum-event" @@ -23,13 +15,20 @@ internal struct MessageEmitterCore: MessageEmitter { private weak var core: DatadogCoreProtocol? - internal init(core: DatadogCoreProtocol) { + init(core: DatadogCoreProtocol) { self.core = core } + /// Sends a bag of data to the message bus + /// - Parameter body: The data to send, it must be parsable to `WebViewMessage` + override func send(body: Any) throws { + let message = try WebViewMessage(body: body) + try send(message: message) + } + /// Sends a message to the message bus /// - Parameter message: The message to send - internal func send(message: WebViewMessage) throws { + func send(message: WebViewMessage) throws { if core == nil { DD.logger.debug("Core must not be nil when using WebViewTracking") } @@ -45,12 +44,3 @@ internal struct MessageEmitterCore: MessageEmitter { } } } - -extension MessageEmitter { - /// Sends a bag of data to the message bus - /// - Parameter body: The data to send, it must be parsable to `WebViewMessage` - internal func send(body: Any) throws { - let message = try WebViewMessage(body: body) - try send(message: message) - } -} diff --git a/DatadogWebViewTracking/Sources/WebViewMessage.swift b/DatadogWebViewTracking/Sources/WebViewMessage.swift index c8f25c9ee9..6501b924fd 100644 --- a/DatadogWebViewTracking/Sources/WebViewMessage.swift +++ b/DatadogWebViewTracking/Sources/WebViewMessage.swift @@ -6,10 +6,10 @@ import Foundation -public typealias JSON = [String: Any] +internal typealias JSON = [String: Any] /// Intermediate type to parse WebView messages and send them to the message bus -public enum WebViewMessage { +internal enum WebViewMessage { /// A log message with a JSON payload case log(JSON) diff --git a/DatadogWebViewTracking/Sources/WebViewTracking.swift b/DatadogWebViewTracking/Sources/WebViewTracking.swift index 3d958d510c..488a9f9fa4 100644 --- a/DatadogWebViewTracking/Sources/WebViewTracking.swift +++ b/DatadogWebViewTracking/Sources/WebViewTracking.swift @@ -75,7 +75,7 @@ public enum WebViewTracking { let bridgeName = DDScriptMessageHandler.name let messageHandler = DDScriptMessageHandler( - emitter: MessageEmitterCore(core: core) + emitter: MessageEmitter(core: core) ) controller.add(messageHandler, name: bridgeName) @@ -117,7 +117,15 @@ public enum WebViewTracking { } extension WebViewTracking: InternalExtended { } -extension InternalExtension where ExtendedType: WebViewTracking { +extension InternalExtension where ExtendedType == WebViewTracking { + /// Abstract Message Emitter definition. + public class AbstractMessageEmitter { + /// Sends a web-view message. + /// + /// - Parameter message: The message to send + public func send(body: Any) throws {} + } + /// Creates a web-view message emitter for cross-platform. /// /// Cross platform SDKs should instantiate a `MessageEmitter` implementation from @@ -125,7 +133,7 @@ extension InternalExtension where ExtendedType: WebViewTracking { /// /// - Parameter core: The Datadog SDK core instance /// - Returns: A `MessageEmitter` instance - public static func messageEmitter(in core: DatadogCoreProtocol) -> MessageEmitter { - return MessageEmitterCore(core: core) + public static func messageEmitter(in core: DatadogCoreProtocol) -> AbstractMessageEmitter { + return MessageEmitter(core: core) } } diff --git a/DatadogWebViewTracking/Tests/MessageEmitterCoreTests.swift b/DatadogWebViewTracking/Tests/MessageEmitterCoreTests.swift index b12d49994d..c2f24defb5 100644 --- a/DatadogWebViewTracking/Tests/MessageEmitterCoreTests.swift +++ b/DatadogWebViewTracking/Tests/MessageEmitterCoreTests.swift @@ -14,7 +14,7 @@ class MessageEmitterCoreTests: XCTestCase { // MARK: - Parsing func testWhenMessageIsInvalid_itFailsParsing() { - let bridge = MessageEmitterCore(core: PassthroughCoreMock()) + let bridge = MessageEmitter(core: PassthroughCoreMock()) let messageInvalidJSON = """ { 123: foobar } @@ -29,7 +29,7 @@ class MessageEmitterCoreTests: XCTestCase { // MARK: - Routing func testWhenEventTypeIsMissing_itThrows() { - let bridge = MessageEmitterCore(core: PassthroughCoreMock()) + let bridge = MessageEmitter(core: PassthroughCoreMock()) let messageMissingEventType = """ { @@ -79,7 +79,7 @@ class MessageEmitterCoreTests: XCTestCase { } ) - let bridge = MessageEmitterCore(core: core) + let bridge = MessageEmitter(core: core) let messageLog = """ { @@ -125,7 +125,7 @@ class MessageEmitterCoreTests: XCTestCase { } ) - let bridge = MessageEmitterCore(core: core) + let bridge = MessageEmitter(core: core) let messageRUM = """ { From 67d75640c40f8790255a3302b09b30ee46d18e1b Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 13:50:13 +0200 Subject: [PATCH 64/87] Remove WebView Tracking tvOS target Remove WebView Tracking tvOS target --- Datadog/Datadog.xcodeproj/project.pbxproj | 392 ------------------ .../xcschemes/DatadogCore tvOS.xcscheme | 10 - .../CTProject.xcodeproj/project.pbxproj | 2 - .../cocoapods/Podfile.src | 3 +- .../SPMProject.xcodeproj.src/project.pbxproj | 8 - .../XCProject.xcodeproj/project.pbxproj | 4 - 6 files changed, 2 insertions(+), 417 deletions(-) diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index 69b9a6f0f1..0149bbaec7 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -8,25 +8,17 @@ /* Begin PBXBuildFile section */ 3C41693C29FBF4D50042B9D2 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; }; - 3C41694729FBF8CC0042B9D2 /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2DA2385298D57AA00C6C7E6 /* DatadogInternal.framework */; }; 3C74305C29FBC0480053B80F /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2DA2385298D57AA00C6C7E6 /* DatadogInternal.framework */; }; 3C85D41B29F7C5C300AFF894 /* WebViewTrackingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WebViewTrackingTests.swift */; }; 3C85D41C29F7C5C400AFF894 /* MessageEmitterCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* MessageEmitterCoreTests.swift */; }; - 3C85D41D29F7C5C400AFF894 /* WebViewTrackingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WebViewTrackingTests.swift */; }; - 3C85D41E29F7C5C400AFF894 /* MessageEmitterCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* MessageEmitterCoreTests.swift */; }; 3C85D41F29F7C5C900AFF894 /* WebViewMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewMessage.swift */; }; 3C85D42129F7C5C900AFF894 /* MessageEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* MessageEmitter.swift */; }; - 3C85D42229F7C5CA00AFF894 /* WebViewMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewMessage.swift */; }; - 3C85D42429F7C5CA00AFF894 /* MessageEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* MessageEmitter.swift */; }; - 3C85D42929F7C6FD00AFF894 /* TestUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D257958B298ABB83008A1BE5 /* TestUtilities.framework */; }; 3C85D42A29F7C70300AFF894 /* TestUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D257953E298ABA65008A1BE5 /* TestUtilities.framework */; }; 3C85D42C29F7C87D00AFF894 /* HostsSanitizerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */; }; 3C85D42D29F7C87D00AFF894 /* HostsSanitizerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */; }; 3C9C6BB429F7C0C000581C43 /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D23039A5298D513C001A1FA3 /* DatadogInternal.framework */; }; 3CE11A1129F7BE0900202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; }; 3CE11A1229F7BE0900202522 /* DatadogWebViewTracking.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3CE11A2829F7BE1E00202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */; }; - 3CE11A3729F7BE6B00202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */; }; 49274906288048B500ECD49B /* InternalTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49274903288048AA00ECD49B /* InternalTelemetryTests.swift */; }; 49274907288048B800ECD49B /* InternalTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49274903288048AA00ECD49B /* InternalTelemetryTests.swift */; }; 61020C2A2757AD91005EEAEA /* BackgroundLocationMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61020C292757AD91005EEAEA /* BackgroundLocationMonitor.swift */; }; @@ -864,9 +856,7 @@ D2A7841129A53B2F003B03BB /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BAC2423979B00786299 /* File.swift */; }; D2A7841229A53B2F003B03BB /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BAC2423979B00786299 /* File.swift */; }; D2ADE2E52A52EA5D001A0FFB /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E42A52EA5D001A0FFB /* WebViewTracking.swift */; }; - D2ADE2E62A52EA5D001A0FFB /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E42A52EA5D001A0FFB /* WebViewTracking.swift */; }; D2ADE2E82A52ECB4001A0FFB /* DDScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E72A52ECB4001A0FFB /* DDScriptMessageHandler.swift */; }; - D2ADE2E92A52ECB4001A0FFB /* DDScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E72A52ECB4001A0FFB /* DDScriptMessageHandler.swift */; }; D2B249942A4598FE00DD4F9F /* LoggerProtocol+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B249932A4598FE00DD4F9F /* LoggerProtocol+Internal.swift */; }; D2B249952A4598FE00DD4F9F /* LoggerProtocol+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B249932A4598FE00DD4F9F /* LoggerProtocol+Internal.swift */; }; D2B249972A45E10500DD4F9F /* LoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B249962A45E10500DD4F9F /* LoggerTests.swift */; }; @@ -1253,27 +1243,6 @@ remoteGlobalIDString = D23039A4298D513C001A1FA3; remoteInfo = "DatadogInternal iOS"; }; - 3C41694329FBF7EE0042B9D2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 61133B79242393DE00786299 /* Project object */; - proxyType = 1; - remoteGlobalIDString = D2DA2355298D57AA00C6C7E6; - remoteInfo = "DatadogInternal tvOS"; - }; - 3C41694529FBF7F50042B9D2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 61133B79242393DE00786299 /* Project object */; - proxyType = 1; - remoteGlobalIDString = D2579571298ABB83008A1BE5; - remoteInfo = "TestUtilities tvOS"; - }; - 3C41694929FBF8CC0042B9D2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 61133B79242393DE00786299 /* Project object */; - proxyType = 1; - remoteGlobalIDString = D2DA2355298D57AA00C6C7E6; - remoteInfo = "DatadogInternal tvOS"; - }; 3C4D5FEE2A0115C600F1FF78 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 61133B79242393DE00786299 /* Project object */; @@ -1302,13 +1271,6 @@ remoteGlobalIDString = 3CE119FD29F7BE0000202522; remoteInfo = "DatadogWebViewTracking iOS"; }; - 3CE11A2929F7BE1E00202522 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 61133B79242393DE00786299 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 3CE11A1F29F7BE1800202522; - remoteInfo = "DatadogWebViewTracking tvOS"; - }; 61133C722423993200786299 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 61133B79242393DE00786299 /* Project object */; @@ -1677,8 +1639,6 @@ 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HostsSanitizerMock.swift; sourceTree = ""; }; 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogWebViewTracking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DatadogWebViewTrackingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogWebViewTracking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3CE11A2729F7BE1B00202522 /* DatadogWebViewTrackingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DatadogWebViewTrackingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49274903288048AA00ECD49B /* InternalTelemetryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InternalTelemetryTests.swift; sourceTree = ""; }; 49274908288048F400ECD49B /* RUMInternalProxyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RUMInternalProxyTests.swift; sourceTree = ""; }; 61020C292757AD91005EEAEA /* BackgroundLocationMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundLocationMonitor.swift; sourceTree = ""; }; @@ -2334,23 +2294,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3CE11A1D29F7BE1800202522 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3C41694729FBF8CC0042B9D2 /* DatadogInternal.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 3CE11A2429F7BE1B00202522 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3C85D42929F7C6FD00AFF894 /* TestUtilities.framework in Frameworks */, - 3CE11A2829F7BE1E00202522 /* DatadogWebViewTracking.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 61133B88242393DE00786299 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2513,12 +2456,10 @@ buildActionMask = 2147483647; files = ( 61A2CC342A44A6030000FF25 /* DatadogRUM.framework in Frameworks */, - 3CE11A3729F7BE6B00202522 /* DatadogWebViewTracking.framework in Frameworks */, D25CFA9D29C4FC6E00E3A43D /* DatadogTrace.framework in Frameworks */, 9E5BD8062819742C00CB568E /* SwiftUI.framework in Frameworks */, D240687027CF971C00C04F44 /* CrashReporter.xcframework in Frameworks */, D240687127CF971C00C04F44 /* DatadogCore.framework in Frameworks */, - 3CE11A3729F7BE6B00202522 /* DatadogWebViewTracking.framework in Frameworks */, D240687227CF971C00C04F44 /* DatadogCrashReporting.framework in Frameworks */, D24C9C4629A7A520002057CF /* DatadogLogs.framework in Frameworks */, D240687327CF971C00C04F44 /* DatadogObjc.framework in Frameworks */, @@ -2801,8 +2742,6 @@ D23F8ECD29DDCD38001CFAE8 /* DatadogRUMTests tvOS.xctest */, 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */, 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */, - 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */, - 3CE11A2729F7BE1B00202522 /* DatadogWebViewTrackingTests.xctest */, ); name = Products; sourceTree = ""; @@ -4850,13 +4789,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3CE11A1B29F7BE1800202522 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 61133B7D242393DE00786299 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -5025,45 +4957,6 @@ productReference = 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - 3CE11A1F29F7BE1800202522 /* DatadogWebViewTracking tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3CE11A2F29F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTracking tvOS" */; - buildPhases = ( - 3CE11A1B29F7BE1800202522 /* Headers */, - 3CE11A1C29F7BE1800202522 /* Sources */, - 3CE11A1D29F7BE1800202522 /* Frameworks */, - 3CE11A1E29F7BE1800202522 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 3C41694A29FBF8CC0042B9D2 /* PBXTargetDependency */, - ); - name = "DatadogWebViewTracking tvOS"; - productName = "DatadogWebViewTracking tvOS"; - productReference = 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */; - productType = "com.apple.product-type.framework"; - }; - 3CE11A2629F7BE1B00202522 /* DatadogWebViewTrackingTests tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3CE11A3329F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTrackingTests tvOS" */; - buildPhases = ( - 3CE11A2329F7BE1B00202522 /* Sources */, - 3CE11A2429F7BE1B00202522 /* Frameworks */, - 3CE11A2529F7BE1B00202522 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 3C41694629FBF7F50042B9D2 /* PBXTargetDependency */, - 3C41694429FBF7EE0042B9D2 /* PBXTargetDependency */, - 3CE11A2A29F7BE1E00202522 /* PBXTargetDependency */, - ); - name = "DatadogWebViewTrackingTests tvOS"; - productName = "DatadogWebViewTracking tvOSTests"; - productReference = 3CE11A2729F7BE1B00202522 /* DatadogWebViewTrackingTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; 61133B81242393DE00786299 /* DatadogCore iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 61133B96242393DE00786299 /* Build configuration list for PBXNativeTarget "DatadogCore iOS" */; @@ -5740,13 +5633,6 @@ CreatedOnToolsVersion = 14.0.1; LastSwiftMigration = 1400; }; - 3CE11A1F29F7BE1800202522 = { - CreatedOnToolsVersion = 14.0.1; - }; - 3CE11A2629F7BE1B00202522 = { - CreatedOnToolsVersion = 14.0.1; - LastSwiftMigration = 1400; - }; 61133B81242393DE00786299 = { CreatedOnToolsVersion = 11.3.1; }; @@ -5867,8 +5753,6 @@ D2579571298ABB83008A1BE5 /* TestUtilities tvOS */, 3CE119FD29F7BE0000202522 /* DatadogWebViewTracking iOS */, 3CE11A0429F7BE0300202522 /* DatadogWebViewTrackingTests iOS */, - 3CE11A1F29F7BE1800202522 /* DatadogWebViewTracking tvOS */, - 3CE11A2629F7BE1B00202522 /* DatadogWebViewTrackingTests tvOS */, ); }; /* End PBXProject section */ @@ -5888,20 +5772,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3CE11A1E29F7BE1800202522 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 3CE11A2529F7BE1B00202522 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 61133B80242393DE00786299 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -6371,26 +6241,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3CE11A1C29F7BE1800202522 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D2ADE2E92A52ECB4001A0FFB /* DDScriptMessageHandler.swift in Sources */, - D2ADE2E62A52EA5D001A0FFB /* WebViewTracking.swift in Sources */, - 3C85D42429F7C5CA00AFF894 /* MessageEmitter.swift in Sources */, - 3C85D42229F7C5CA00AFF894 /* WebViewMessage.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 3CE11A2329F7BE1B00202522 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3C85D41D29F7C5C400AFF894 /* WebViewTrackingTests.swift in Sources */, - 3C85D41E29F7C5C400AFF894 /* MessageEmitterCoreTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 61133B7E242393DE00786299 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -7722,21 +7572,6 @@ target = D23039A4298D513C001A1FA3 /* DatadogInternal iOS */; targetProxy = 3C41694129FBF6100042B9D2 /* PBXContainerItemProxy */; }; - 3C41694429FBF7EE0042B9D2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = D2DA2355298D57AA00C6C7E6 /* DatadogInternal tvOS */; - targetProxy = 3C41694329FBF7EE0042B9D2 /* PBXContainerItemProxy */; - }; - 3C41694629FBF7F50042B9D2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = D2579571298ABB83008A1BE5 /* TestUtilities tvOS */; - targetProxy = 3C41694529FBF7F50042B9D2 /* PBXContainerItemProxy */; - }; - 3C41694A29FBF8CC0042B9D2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = D2DA2355298D57AA00C6C7E6 /* DatadogInternal tvOS */; - targetProxy = 3C41694929FBF8CC0042B9D2 /* PBXContainerItemProxy */; - }; 3C4D5FEF2A0115C600F1FF78 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D2C1A53329C4F2DF00946C31 /* DatadogTrace tvOS */; @@ -7757,11 +7592,6 @@ target = 3CE119FD29F7BE0000202522 /* DatadogWebViewTracking iOS */; targetProxy = 3CE11A0729F7BE0500202522 /* PBXContainerItemProxy */; }; - 3CE11A2A29F7BE1E00202522 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 3CE11A1F29F7BE1800202522 /* DatadogWebViewTracking tvOS */; - targetProxy = 3CE11A2929F7BE1E00202522 /* PBXContainerItemProxy */; - }; 61133C732423993200786299 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 61133B81242393DE00786299 /* DatadogCore iOS */; @@ -8178,208 +8008,6 @@ }; name = Integration; }; - 3CE11A3029F7BE2100202522 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 61569894256D0E9A00C6AADA /* Base.xcconfig */; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Datadog. All rights reserved."; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTracking; - PRODUCT_NAME = DatadogWebViewTracking; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Debug; - }; - 3CE11A3129F7BE2100202522 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 61569894256D0E9A00C6AADA /* Base.xcconfig */; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Datadog. All rights reserved."; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTracking; - PRODUCT_NAME = DatadogWebViewTracking; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Release; - }; - 3CE11A3229F7BE2100202522 /* Integration */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 61569894256D0E9A00C6AADA /* Base.xcconfig */; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Datadog. All rights reserved."; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTracking; - PRODUCT_NAME = DatadogWebViewTracking; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Integration; - }; - 3CE11A3429F7BE2100202522 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTrackingTests; - PRODUCT_NAME = DatadogWebViewTrackingTests; - SDKROOT = appletvos; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Debug; - }; - 3CE11A3529F7BE2100202522 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTrackingTests; - PRODUCT_NAME = DatadogWebViewTrackingTests; - SDKROOT = appletvos; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Release; - }; - 3CE11A3629F7BE2100202522 /* Integration */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTrackingTests; - PRODUCT_NAME = DatadogWebViewTrackingTests; - SDKROOT = appletvos; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Integration; - }; 61133B94242393DE00786299 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -11475,26 +11103,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 3CE11A2F29F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTracking tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3CE11A3029F7BE2100202522 /* Debug */, - 3CE11A3129F7BE2100202522 /* Release */, - 3CE11A3229F7BE2100202522 /* Integration */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 3CE11A3329F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTrackingTests tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3CE11A3429F7BE2100202522 /* Debug */, - 3CE11A3529F7BE2100202522 /* Release */, - 3CE11A3629F7BE2100202522 /* Integration */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 61133B7C242393DE00786299 /* Build configuration list for PBXProject "Datadog" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Datadog/Datadog.xcodeproj/xcshareddata/xcschemes/DatadogCore tvOS.xcscheme b/Datadog/Datadog.xcodeproj/xcshareddata/xcschemes/DatadogCore tvOS.xcscheme index 6dad8afdb9..069f3c2735 100644 --- a/Datadog/Datadog.xcodeproj/xcshareddata/xcschemes/DatadogCore tvOS.xcscheme +++ b/Datadog/Datadog.xcodeproj/xcshareddata/xcschemes/DatadogCore tvOS.xcscheme @@ -224,16 +224,6 @@ ReferencedContainer = "container:Datadog.xcodeproj"> - - - - 'GIT_REMOTE', :GIT_REFERENCE pod 'DatadogAlamofireExtension', :git => 'GIT_REMOTE', :GIT_REFERENCE pod 'DatadogCrashReporting', :git => 'GIT_REMOTE', :GIT_REFERENCE - pod 'DatadogWebViewTracking', :git => 'GIT_REMOTE', :GIT_REFERENCE pod 'Alamofire' target 'App Dynamic iOS' do platform :ios, '13.0' use_frameworks! pod 'DatadogSessionReplay', :git => 'GIT_REMOTE', :GIT_REFERENCE + pod 'DatadogWebViewTracking', :git => 'GIT_REMOTE', :GIT_REFERENCE end target 'App Static iOS' do platform :ios, '13.0' pod 'DatadogSessionReplay', :git => 'GIT_REMOTE', :GIT_REFERENCE + pod 'DatadogWebViewTracking', :git => 'GIT_REMOTE', :GIT_REFERENCE target 'App Static iOS Tests' do inherit! :search_paths diff --git a/dependency-manager-tests/spm/SPMProject.xcodeproj.src/project.pbxproj b/dependency-manager-tests/spm/SPMProject.xcodeproj.src/project.pbxproj index b6bf6d7ec2..f548981942 100644 --- a/dependency-manager-tests/spm/SPMProject.xcodeproj.src/project.pbxproj +++ b/dependency-manager-tests/spm/SPMProject.xcodeproj.src/project.pbxproj @@ -15,7 +15,6 @@ 61C363F124374D6100C4D4E6 /* AppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C363F024374D6100C4D4E6 /* AppTests.swift */; }; 61C363FC24374D6100C4D4E6 /* AppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C363FB24374D6100C4D4E6 /* AppUITests.swift */; }; 9E73374026B0123500917C24 /* DatadogCrashReporting in Frameworks */ = {isa = PBXBuildFile; productRef = 9E73373F26B0123500917C24 /* DatadogCrashReporting */; }; - D20594FE2A019041002D0845 /* DatadogWebViewTracking in Frameworks */ = {isa = PBXBuildFile; productRef = D20594FD2A019041002D0845 /* DatadogWebViewTracking */; }; D2344E1F29ACDE61007F5BD2 /* DatadogLogs in Frameworks */ = {isa = PBXBuildFile; productRef = D2344E1E29ACDE61007F5BD2 /* DatadogLogs */; }; D2344E2129ACDE68007F5BD2 /* DatadogLogs in Frameworks */ = {isa = PBXBuildFile; productRef = D2344E2029ACDE68007F5BD2 /* DatadogLogs */; }; D23BF5F327CCCC3300BB4CCD /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C363DD24374D5F00C4D4E6 /* ViewController.swift */; }; @@ -138,7 +137,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D20594FE2A019041002D0845 /* DatadogWebViewTracking in Frameworks */, D2966C3029CA1F3300FC6B3C /* DatadogTrace in Frameworks */, D2344E2129ACDE68007F5BD2 /* DatadogLogs in Frameworks */, D2CE76BA29F6B9E300D79713 /* DatadogRUM in Frameworks */, @@ -322,7 +320,6 @@ D2344E2029ACDE68007F5BD2 /* DatadogLogs */, D2966C2F29CA1F3300FC6B3C /* DatadogTrace */, D2CE76B929F6B9E300D79713 /* DatadogRUM */, - D20594FD2A019041002D0845 /* DatadogWebViewTracking */, D26A32D82A4C893300903514 /* DatadogCore */, ); productName = SPMProject; @@ -1086,11 +1083,6 @@ package = 9E73373E26B0123500917C24 /* XCRemoteSwiftPackageReference "dd-sdk-ios" */; productName = DatadogCrashReporting; }; - D20594FD2A019041002D0845 /* DatadogWebViewTracking */ = { - isa = XCSwiftPackageProductDependency; - package = 9E73373E26B0123500917C24 /* XCRemoteSwiftPackageReference "dd-sdk-ios" */; - productName = DatadogWebViewTracking; - }; D2344E1E29ACDE61007F5BD2 /* DatadogLogs */ = { isa = XCSwiftPackageProductDependency; package = 9E73373E26B0123500917C24 /* XCRemoteSwiftPackageReference "dd-sdk-ios" */; diff --git a/dependency-manager-tests/xcframeworks/XCProject.xcodeproj/project.pbxproj b/dependency-manager-tests/xcframeworks/XCProject.xcodeproj/project.pbxproj index b2ed2a5b2b..36bcbc2683 100644 --- a/dependency-manager-tests/xcframeworks/XCProject.xcodeproj/project.pbxproj +++ b/dependency-manager-tests/xcframeworks/XCProject.xcodeproj/project.pbxproj @@ -12,8 +12,6 @@ 61C3641D243752A500C4D4E6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C3641C243752A500C4D4E6 /* ViewController.swift */; }; 61C36430243752A600C4D4E6 /* AppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C3642F243752A600C4D4E6 /* AppTests.swift */; }; 61C3643B243752A600C4D4E6 /* AppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C3643A243752A600C4D4E6 /* AppUITests.swift */; }; - D2675BFB2A019F6A00190669 /* DatadogWebViewTracking.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C4C2BB629F6B9C100152C4B /* DatadogWebViewTracking.xcframework */; }; - D2675BFC2A019F6A00190669 /* DatadogWebViewTracking.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3C4C2BB629F6B9C100152C4B /* DatadogWebViewTracking.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D2675BFD2A019F7500190669 /* DatadogWebViewTracking.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C4C2BB629F6B9C100152C4B /* DatadogWebViewTracking.xcframework */; }; D2675BFE2A019F7500190669 /* DatadogWebViewTracking.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3C4C2BB629F6B9C100152C4B /* DatadogWebViewTracking.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D2675BFF2A01A03300190669 /* DatadogCrashReporting.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2F9244929A4B9A3006733B2 /* DatadogCrashReporting.xcframework */; }; @@ -118,7 +116,6 @@ D2966C2C29CA1E1C00FC6B3C /* DatadogTrace.xcframework in Embed Frameworks */, D2F09A2829F6C6610036B910 /* DatadogRUM.xcframework in Embed Frameworks */, D2F9245429A4B9D8006733B2 /* CrashReporter.xcframework in Embed Frameworks */, - D2675BFC2A019F6A00190669 /* DatadogWebViewTracking.xcframework in Embed Frameworks */, D2675C022A01A03D00190669 /* DatadogCrashReporting.xcframework in Embed Frameworks */, D2EBEDB129B7867D00B15732 /* DatadogInternal.xcframework in Embed Frameworks */, ); @@ -196,7 +193,6 @@ D2966C2B29CA1E1C00FC6B3C /* DatadogTrace.xcframework in Frameworks */, D2F09A2729F6C6610036B910 /* DatadogRUM.xcframework in Frameworks */, D2F9245329A4B9D8006733B2 /* CrashReporter.xcframework in Frameworks */, - D2675BFB2A019F6A00190669 /* DatadogWebViewTracking.xcframework in Frameworks */, D2675C012A01A03D00190669 /* DatadogCrashReporting.xcframework in Frameworks */, D2EBEDB029B7867D00B15732 /* DatadogInternal.xcframework in Frameworks */, ); From 5ac3945c10ac79b5c5bde4fcd95873c4d9e7832a Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 15:56:04 +0200 Subject: [PATCH 65/87] Update MIGRATION.md --- MIGRATION.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 6c7ce57287..e3d6adeee8 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -176,10 +176,9 @@ All the classes related to Trace are now strictly in the `DatadogTrace` module. ```swift import DatadogTrace -// Using the default SDK core instance Trace.enable( with: Trace.Configuration(...) - ) +) ``` Then, you can access the shared Tracer instance: @@ -187,7 +186,6 @@ Then, you can access the shared Tracer instance: ```swift import DatadogTrace -// Using the default SDK core instance let tracer = Tracer.shared() ``` @@ -322,7 +320,6 @@ let core = Datadog.sdkInstance(named: "my-instance") ```swift import DatadogLogs -Logs.enable(in: core) let logger = Logger.create(in: core) ``` @@ -330,7 +327,6 @@ let logger = Logger.create(in: core) ```swift import DatadogRUM -RUM.enable(in: core) let monitor = RUMMonitor.shared(in: core) ``` @@ -338,6 +334,5 @@ let monitor = RUMMonitor.shared(in: core) ```swift import DatadogRUM -RUM.enable(in: core) let monitor = RUMMonitor.shared(in: core) ``` From 2b4d9b08e38a1a79ec24af76330e9371453f3ff0 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 16:09:51 +0200 Subject: [PATCH 66/87] Bumped version to 2.0.0-beta1 --- DatadogAlamofireExtension.podspec | 2 +- DatadogCore.podspec | 2 +- DatadogCore/Sources/Versioning.swift | 2 +- DatadogCrashReporting.podspec | 2 +- DatadogInternal.podspec | 2 +- DatadogLogs.podspec | 2 +- DatadogObjc.podspec | 2 +- DatadogRUM.podspec | 2 +- DatadogSDK.podspec | 2 +- DatadogSDKAlamofireExtension.podspec | 2 +- DatadogSDKCrashReporting.podspec | 2 +- DatadogSDKObjc.podspec | 2 +- DatadogSessionReplay.podspec | 2 +- DatadogTrace.podspec | 2 +- DatadogWebViewTracking.podspec | 2 +- TestUtilities.podspec | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/DatadogAlamofireExtension.podspec b/DatadogAlamofireExtension.podspec index f9acebe053..b1cc0984b2 100644 --- a/DatadogAlamofireExtension.podspec +++ b/DatadogAlamofireExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogAlamofireExtension" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "An Official Extensions of Datadog Swift SDK for Alamofire." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogCore.podspec b/DatadogCore.podspec index 05c0b96cb5..3905adedef 100644 --- a/DatadogCore.podspec +++ b/DatadogCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogCore" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Official Datadog Swift SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogCore/Sources/Versioning.swift b/DatadogCore/Sources/Versioning.swift index 9877a16315..e4226099bd 100644 --- a/DatadogCore/Sources/Versioning.swift +++ b/DatadogCore/Sources/Versioning.swift @@ -1,3 +1,3 @@ // GENERATED FILE: Do not edit directly -internal let __sdkVersion = "2.0.0-alpha1" +internal let __sdkVersion = "2.0.0-beta1" diff --git a/DatadogCrashReporting.podspec b/DatadogCrashReporting.podspec index 1e0e1b70db..6e081964cf 100644 --- a/DatadogCrashReporting.podspec +++ b/DatadogCrashReporting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogCrashReporting" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Official Datadog Crash Reporting SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogInternal.podspec b/DatadogInternal.podspec index 532be94dc6..61aad4975f 100644 --- a/DatadogInternal.podspec +++ b/DatadogInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogInternal" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Datadog Internal Package. This module is not for public use." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogLogs.podspec b/DatadogLogs.podspec index ee0760e1f6..5b545a7122 100644 --- a/DatadogLogs.podspec +++ b/DatadogLogs.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogLogs" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Datadog Logs Module." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogObjc.podspec b/DatadogObjc.podspec index c806e8d81d..5a1aedd2d4 100644 --- a/DatadogObjc.podspec +++ b/DatadogObjc.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogObjc" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Official Datadog Objective-C SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogRUM.podspec b/DatadogRUM.podspec index 1d0ef07f7a..453a1545d6 100644 --- a/DatadogRUM.podspec +++ b/DatadogRUM.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogRUM" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Datadog Real User Monitoring Module." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSDK.podspec b/DatadogSDK.podspec index 2d56211d57..79095880f3 100644 --- a/DatadogSDK.podspec +++ b/DatadogSDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogSDK" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Official Datadog Swift SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSDKAlamofireExtension.podspec b/DatadogSDKAlamofireExtension.podspec index 4e28a3ab26..148b68b594 100644 --- a/DatadogSDKAlamofireExtension.podspec +++ b/DatadogSDKAlamofireExtension.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "DatadogSDKAlamofireExtension" s.module_name = "DatadogAlamofireExtension" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "An Official Extensions of Datadog Swift SDK for Alamofire." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSDKCrashReporting.podspec b/DatadogSDKCrashReporting.podspec index 91ca5c5852..a44ee1002b 100644 --- a/DatadogSDKCrashReporting.podspec +++ b/DatadogSDKCrashReporting.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "DatadogSDKCrashReporting" s.module_name = "DatadogCrashReporting" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Official Datadog Crash Reporting SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSDKObjc.podspec b/DatadogSDKObjc.podspec index 4039d8be68..9d92a75488 100644 --- a/DatadogSDKObjc.podspec +++ b/DatadogSDKObjc.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "DatadogSDKObjc" s.module_name = "DatadogObjc" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Official Datadog Objective-C SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSessionReplay.podspec b/DatadogSessionReplay.podspec index 85ced3a750..5ee2328ff0 100644 --- a/DatadogSessionReplay.podspec +++ b/DatadogSessionReplay.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogSessionReplay" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Official Datadog Session Replay SDK for iOS. This module is currently in beta - contact Datadog to request a try." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogTrace.podspec b/DatadogTrace.podspec index f561a16379..f7c3d69799 100644 --- a/DatadogTrace.podspec +++ b/DatadogTrace.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogTrace" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Datadog Trace Module." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogWebViewTracking.podspec b/DatadogWebViewTracking.podspec index 8f0c2c8522..e1e51d536c 100644 --- a/DatadogWebViewTracking.podspec +++ b/DatadogWebViewTracking.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogWebViewTracking" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Datadog WebView Tracking Module." s.homepage = "https://www.datadoghq.com" diff --git a/TestUtilities.podspec b/TestUtilities.podspec index 637955e4fc..6d1e94ca07 100644 --- a/TestUtilities.podspec +++ b/TestUtilities.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "TestUtilities" - s.version = "2.0.0-alpha1" + s.version = "2.0.0-beta1" s.summary = "Datadog Testing Utilities. This module is for internal testing and should not be published." s.homepage = "https://www.datadoghq.com" From 41df11d742902d79cb9131e64d88c3323d0ff1a3 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 16:22:09 +0200 Subject: [PATCH 67/87] Remove session replay from library --- Package.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Package.swift b/Package.swift index 23e9a42ae3..f167d4b41e 100644 --- a/Package.swift +++ b/Package.swift @@ -29,10 +29,6 @@ let package = Package( name: "DatadogRUM", targets: ["DatadogRUM"] ), - .library( - name: "DatadogSessionReplay", - targets: ["DatadogSessionReplay"] - ), .library( name: "DatadogCrashReporting", targets: ["DatadogCrashReporting"] From 9104ba6f0d4b001f6be327e8354cfcea9f377f5d Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 5 Jul 2023 16:22:19 +0200 Subject: [PATCH 68/87] Fix CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2457070207..1d5f031aa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Unreleased -# 1.21.0 / 27-07-2023 +# 1.21.0 / 27-06-2023 - [BUGFIX] Fix TracingUUID string format. See [#1311][] (Thanks [@changm4n][]) - [BUGFIX] Rename _Datadog_Private to DatadogPrivate. See [#1331] (Thanks [@alexfanatics][]) - [IMPROVEMENT] Add context to crash when there's an active view. See [#1315][] From 4028b60b504948b052eecb87bf755598f99f365f Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Thu, 6 Jul 2023 09:45:59 +0200 Subject: [PATCH 69/87] Apply changes from doc team Co-authored-by: Rosa Trieu <107086888+rtrieu@users.noreply.github.com> --- MIGRATION.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index e3d6adeee8..c50eafbb2d 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -4,9 +4,9 @@ This document describes the main changes introduced in SDK `2.0` compared to `1. ### Product Modules -All the products (RUM, Trace, Logs, etc.) are now extracted into different modules. That allows you to integrate only what is needed into your application. +All relevant products (RUM, Trace, Logs, etc.) are now extracted into different modules. That allows you to integrate only what is needed into your application. -In comparison with version 1.x where all products were in a single module `Datadog`, now you need to adopt the following libraries instead: +Whereas all products in version 1.x were contained in the single module, `Datadog`, you now need to adopt the following libraries: - `DatadogCore` - `DatadogLogs` @@ -81,7 +81,7 @@ let package = Package( ``` -**NOTE**: In case of Crash Reporting and WebView Tracking usage it's also needed to add RUM and/or Logs modules to be able to report events to RUM and/or Logs respectively. +**Note**: In case of Crash Reporting and WebView Tracking usage it's also needed to add RUM and/or Logs modules to be able to report events to RUM and/or Logs respectively. The `2.0` version of the iOS SDK also exposes unified API layouts and naming between iOS and Android SDKs and with other Datadog products. @@ -136,7 +136,7 @@ API changes: ## Logs Product Changes -All the classes related to Logs are now strictly in the `DatadogLogs` module. You will first need to enable the product: +All the classes related to Logs are now strictly in the `DatadogLogs` module. You first need to enable the product: ```swift import DatadogLogs @@ -171,7 +171,7 @@ API changes: ## APM Trace Product Changes -All the classes related to Trace are now strictly in the `DatadogTrace` module. You will first need to enable the product: +All the classes related to Trace are now strictly in the `DatadogTrace` module. You first need to enable the product: ```swift import DatadogTrace @@ -306,7 +306,7 @@ Logs.enable(in: core) Trace.enable(in: core) ``` -**NOTE**: SDK instance name should have the same value between application runs. Storage paths for SDK events are associated with it. +**Note**: The SDK instance name should have the same value between application runs. Storage paths for SDK events are associated with it. Once initialized, you can retrieve the named SDK instance by calling `Datadog.sdkInstance(named: "")` and use it for accessing the products. From a635662b8de6ac9cdf2702350a102a130cc52f79 Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Thu, 6 Jul 2023 12:05:17 +0100 Subject: [PATCH 70/87] REPLAY-1765 PR fixes --- .../DatadogCoreIntegration/RUMDependency.swift | 2 +- .../SRContextPublisher.swift | 4 ++-- .../Sources/Processor/Processor.swift | 10 +++++----- .../SRContextPublisherTests.swift | 18 +++++++++--------- .../Tests/Processor/ProcessorTests.swift | 16 ++++++++-------- .../DatadogInternal/DatadogCoreProtocol.swift | 2 +- .../Integrations/SessionReplayDependency.swift | 8 ++++---- .../RUM/RUMMonitor/Scopes/RUMViewScope.swift | 2 +- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/DatadogSessionReplay/Sources/DatadogCoreIntegration/RUMDependency.swift b/DatadogSessionReplay/Sources/DatadogCoreIntegration/RUMDependency.swift index 8299cce9ec..6223030181 100644 --- a/DatadogSessionReplay/Sources/DatadogCoreIntegration/RUMDependency.swift +++ b/DatadogSessionReplay/Sources/DatadogCoreIntegration/RUMDependency.swift @@ -43,5 +43,5 @@ internal enum RUMDependency { static let hasReplay = "has_replay" /// They key referencing a `[String: Int64]` dictionary of viewIDs and associated records count. - static let recordsCount = "records_count" + static let recordsCountByViewID = "records_count_by_view_id" } diff --git a/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift b/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift index ec2ab1720d..b521a1cbf9 100644 --- a/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift +++ b/DatadogSessionReplay/Sources/DatadogCoreIntegration/SRContextPublisher.swift @@ -24,10 +24,10 @@ internal class SRContextPublisher { } /// Notifies other Features on the state of Session Replay records count. - func setRecordsCount(_ value: [String: Int64]) { + func setRecordsCountByViewID(_ value: [String: Int64]) { core?.update( feature: RUMDependency.srBaggageKey, - attributes: { [RUMDependency.recordsCount: value] } + attributes: { [RUMDependency.recordsCountByViewID: value] } ) } } diff --git a/DatadogSessionReplay/Sources/Processor/Processor.swift b/DatadogSessionReplay/Sources/Processor/Processor.swift index 3f9c2fce4e..f3ccde323c 100644 --- a/DatadogSessionReplay/Sources/Processor/Processor.swift +++ b/DatadogSessionReplay/Sources/Processor/Processor.swift @@ -54,7 +54,7 @@ internal class Processor: Processing { private var srContextPublisher: SRContextPublisher - private var recordsCount: [String: Int64] = [:] + private var recordsCountByViewID: [String: Int64] = [:] init( queue: Queue, @@ -134,11 +134,11 @@ internal class Processor: Processing { } private func trackRecord(key: String, value: Int64) { - if let existingValue = recordsCount[key] { - recordsCount[key] = existingValue + value + if let existingValue = recordsCountByViewID[key] { + recordsCountByViewID[key] = existingValue + value } else { - recordsCount[key] = value + recordsCountByViewID[key] = value } - srContextPublisher.setRecordsCount(recordsCount) + srContextPublisher.setRecordsCountByViewID(recordsCountByViewID) } } diff --git a/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift b/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift index ef7226d6b5..50151925d5 100644 --- a/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift +++ b/DatadogSessionReplay/Tests/DatadogCoreIntegration/SRContextPublisherTests.swift @@ -23,21 +23,21 @@ class SRContextPublisherTests: XCTestCase { let core = PassthroughCoreMock() let srContextPublisher = SRContextPublisher(core: core) - let recordsCount: [String: Int64] = ["view-id": 2] - srContextPublisher.setRecordsCount(recordsCount) + let recordsCountByViewID: [String: Int64] = ["view-id": 2] + srContextPublisher.setRecordsCountByViewID(recordsCountByViewID) - XCTAssertEqual(core.recordsCount, recordsCount) + XCTAssertEqual(core.recordsCountByViewID, recordsCountByViewID) } func testItDoesNotOverridePreviouslySetValue() throws { let core = PassthroughCoreMock() let srContextPublisher = SRContextPublisher(core: core) - let recordsCount: [String: Int64] = ["view-id": 2] + let recordsCountByViewID: [String: Int64] = ["view-id": 2] srContextPublisher.setHasReplay(true) - srContextPublisher.setRecordsCount(recordsCount) + srContextPublisher.setRecordsCountByViewID(recordsCountByViewID) - XCTAssertEqual(core.recordsCount, recordsCount) + XCTAssertEqual(core.recordsCountByViewID, recordsCountByViewID) let hasReplay = try XCTUnwrap(core.hasReplay) XCTAssertTrue(hasReplay) @@ -45,7 +45,7 @@ class SRContextPublisherTests: XCTestCase { let hasReplay2 = try XCTUnwrap(core.hasReplay) XCTAssertFalse(hasReplay2) - XCTAssertEqual(core.recordsCount, recordsCount) + XCTAssertEqual(core.recordsCountByViewID, recordsCountByViewID) } } @@ -54,7 +54,7 @@ fileprivate extension PassthroughCoreMock { return context.featuresAttributes["session-replay"]?.has_replay } - var recordsCount: [String: Int64]? { - return context.featuresAttributes["session-replay"]?.records_count + var recordsCountByViewID: [String: Int64]? { + return context.featuresAttributes["session-replay"]?.records_count_by_view_id } } diff --git a/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift b/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift index 8ccc212742..7f5add5608 100644 --- a/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift +++ b/DatadogSessionReplay/Tests/Processor/ProcessorTests.swift @@ -50,7 +50,7 @@ class ProcessorTests: XCTestCase { XCTAssertTrue(enrichedRecord.records[1].isFocusRecord) XCTAssertTrue(enrichedRecord.records[2].isFullSnapshotRecord && enrichedRecord.hasFullSnapshot) - XCTAssertEqual(core.recordsCount, ["abc": 3]) + XCTAssertEqual(core.recordsCountByViewID, ["abc": 3]) } func testWhenRUMContextDoesNotChangeInSucceedingViewTreeSnapshots_itWritesRecordsThatContinueCurrentSegment() { @@ -97,7 +97,7 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecord.latestTimestamp, expectedTime.timeIntervalSince1970.toInt64Milliseconds) } - XCTAssertEqual(core.recordsCount, ["abc": 5]) + XCTAssertEqual(core.recordsCountByViewID, ["abc": 5]) } func testWhenOrientationChanges_itWritesRecordsViewportResizeDataSegment() { @@ -135,7 +135,7 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecords[1].records[1].incrementalSnapshot?.viewportResizeData?.height, 100) XCTAssertEqual(enrichedRecords[1].records[1].incrementalSnapshot?.viewportResizeData?.width, 200) - XCTAssertEqual(core.recordsCount?.values.first, 5) + XCTAssertEqual(core.recordsCountByViewID?.values.first, 5) } func testWhenRUMContextChangesInSucceedingViewTreeSnapshots_itWritesRecordsThatIndicateNextSegments() { @@ -186,7 +186,7 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecord.viewID, expectedRUM.ids.viewID) } - XCTAssertEqual(core.recordsCount?.values.map { $0 }, [4, 4]) + XCTAssertEqual(core.recordsCountByViewID?.values.map { $0 }, [4, 4]) } // MARK: - Processing `TouchSnapshots` @@ -234,7 +234,7 @@ class ProcessorTests: XCTestCase { XCTAssertLessThanOrEqual(record.timestamp, snapshotTime.timeIntervalSince1970.toInt64Milliseconds) } - XCTAssertEqual(core.recordsCount, ["abc": 13]) + XCTAssertEqual(core.recordsCountByViewID, ["abc": 13]) } func testWhenRUMContextTimeOffsetChangesInSucceedingViewTreeSnapshots_itWritesRecordsThatContinueCurrentSegment() { @@ -273,7 +273,7 @@ class ProcessorTests: XCTestCase { XCTAssertEqual(enrichedRecord.viewID, expectedRUM.ids.viewID) } - XCTAssertEqual(core.recordsCount, ["abc": 4]) + XCTAssertEqual(core.recordsCountByViewID, ["abc": 4]) } // MARK: - `ViewTreeSnapshot` generation @@ -319,7 +319,7 @@ class ProcessorTests: XCTestCase { } fileprivate extension PassthroughCoreMock { - var recordsCount: [String: Int64]? { - return context.featuresAttributes["session-replay"]?.records_count + var recordsCountByViewID: [String: Int64]? { + return context.featuresAttributes["session-replay"]?.records_count_by_view_id } } diff --git a/Sources/Datadog/DatadogInternal/DatadogCoreProtocol.swift b/Sources/Datadog/DatadogInternal/DatadogCoreProtocol.swift index a63a9ece59..6d1d099039 100644 --- a/Sources/Datadog/DatadogInternal/DatadogCoreProtocol.swift +++ b/Sources/Datadog/DatadogInternal/DatadogCoreProtocol.swift @@ -119,7 +119,7 @@ public protocol DatadogCoreProtocol: AnyObject { /// // Bar.swift /// core.scope(for: "bar").eventWriteContext { context, writer in /// let fooID: Int? = context.featuresAttributes["foo"]?.id - /// let fooName: Int? = context.featuresAttributes["foo"]?.name + /// let fooName: String? = context.featuresAttributes["foo"]?.name /// } /// /// - Parameters: diff --git a/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift b/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift index e42274dca8..65b1b0705f 100644 --- a/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift +++ b/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift @@ -20,7 +20,7 @@ internal struct SessionReplayDependency { static let hasReplay = "has_replay" /// The key referencing a `[String: Int64]` value that indicates number of records recorded for a given viewID. - static let recordsCount = "records_count" + static let recordsCountByViewID = "records_count_by_view_id" } // MARK: - Extracting SR context from `DatadogContext` @@ -42,10 +42,10 @@ extension FeatureBaggage { } /// The value of `[String: Int64]` that indicates number of records recorded for a given viewID. - var recordsCount: [String: Int64] { - guard let recordsCount: [String: Int64] = self[SessionReplayDependency.recordsCount] else { + var recordsCountByViewID: [String: Int64] { + guard let recordsCountByViewID: [String: Int64] = self[SessionReplayDependency.recordsCountByViewID] else { return [:] } - return recordsCount + return recordsCountByViewID } } diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift index 13fe5601c9..19d0436519 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift @@ -439,7 +439,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { documentVersion: version.toInt64, pageStates: nil, replayStats: .init( - recordsCount: context.srBaggage?.recordsCount[viewUUID.toRUMDataFormat], + recordsCount: context.srBaggage?.recordsCountByViewID[viewUUID.toRUMDataFormat], segmentsCount: nil, segmentsTotalRawSize: nil ), From a4199febbb75d66f8ed729fcfdc3c56c502a0b99 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Thu, 6 Jul 2023 13:33:20 +0200 Subject: [PATCH 71/87] REPLAY-1868 Make Session Replay uploader more eager --- .../Sources/Drafts/SessionReplayFeature.swift | 4 +- .../WindowObserver/KeyWindowObserver.swift | 1 - Sources/Datadog/Core/PerformancePreset.swift | 24 ++++--- .../PerformancePresetOverride.swift | 62 +++++++++++++++++-- .../Datadog/Core/PerformancePresetTests.swift | 15 ++++- .../DatadogCore/DatadogCoreTests.swift | 9 ++- 6 files changed, 93 insertions(+), 22 deletions(-) diff --git a/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift b/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift index 20e7e1bfd2..cd5283ec7d 100644 --- a/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift +++ b/DatadogSessionReplay/Sources/Drafts/SessionReplayFeature.swift @@ -62,7 +62,9 @@ internal class SessionReplayFeature: DatadogFeature, SessionReplayController { self.requestBuilder = RequestBuilder(customUploadURL: configuration.customUploadURL) self.performanceOverride = PerformancePresetOverride( maxFileSize: UInt64(10).MB, - maxObjectSize: UInt64(10).MB + maxObjectSize: UInt64(10).MB, + meanFileAge: 5, // equivalent of `batchSize: .small` - see `DatadogCore.PerformancePreset` + minUploadDelay: 1 // equivalent of `uploadFrequency: .frequent` - see `DatadogCore.PerformancePreset` ) } diff --git a/DatadogSessionReplay/Sources/Recorder/WindowObserver/KeyWindowObserver.swift b/DatadogSessionReplay/Sources/Recorder/WindowObserver/KeyWindowObserver.swift index c0eeaf7805..9ee438bf63 100644 --- a/DatadogSessionReplay/Sources/Recorder/WindowObserver/KeyWindowObserver.swift +++ b/DatadogSessionReplay/Sources/Recorder/WindowObserver/KeyWindowObserver.swift @@ -17,7 +17,6 @@ internal class KeyWindowObserver: AppWindowObserver { if #available(iOS 13.0, tvOS 13.0, *) { return findONiOS13AndLater() } else { - assertionFailure("TODO: RUMM-2409 `AppWindowObserver` isn't yet ready for this version of OS") return nil } } diff --git a/Sources/Datadog/Core/PerformancePreset.swift b/Sources/Datadog/Core/PerformancePreset.swift index e13322235d..1eb168c4cf 100644 --- a/Sources/Datadog/Core/PerformancePreset.swift +++ b/Sources/Datadog/Core/PerformancePreset.swift @@ -80,12 +80,11 @@ internal extension PerformancePreset { } }() - let uploadDelayFactors: (initial: Double, default: Double, min: Double, max: Double, changeRate: Double) = { + let uploadDelayFactors: (initial: Double, min: Double, max: Double, changeRate: Double) = { switch bundleType { case .iOSApp: return ( initial: 5, - default: 5, min: 1, max: 10, changeRate: 0.1 @@ -93,7 +92,6 @@ internal extension PerformancePreset { case .iOSAppExtension: return ( initial: 0.5, // ensures the the first upload is checked quickly after starting the short-lived app extension - default: 3, min: 1, max: 5, changeRate: 0.5 // if batches are found, reduces interval significantly for more uploads in short-lived app extension @@ -111,7 +109,7 @@ internal extension PerformancePreset { init( meanFileAge: TimeInterval, minUploadDelay: TimeInterval, - uploadDelayFactors: (initial: Double, default: Double, min: Double, max: Double, changeRate: Double) + uploadDelayFactors: (initial: Double, min: Double, max: Double, changeRate: Double) ) { self.maxFileSize = UInt64(4).MB self.maxDirectorySize = UInt64(512).MB @@ -126,19 +124,19 @@ internal extension PerformancePreset { self.uploadDelayChangeRate = uploadDelayFactors.changeRate } - func updated(with: PerformancePresetOverride) -> PerformancePreset { + func updated(with override: PerformancePresetOverride) -> PerformancePreset { return PerformancePreset( - maxFileSize: with.maxFileSize ?? maxFileSize, + maxFileSize: override.maxFileSize ?? maxFileSize, maxDirectorySize: maxDirectorySize, - maxFileAgeForWrite: maxFileAgeForWrite, - minFileAgeForRead: minFileAgeForRead, + maxFileAgeForWrite: override.maxFileAgeForWrite ?? maxFileAgeForWrite, + minFileAgeForRead: override.minFileAgeForRead ?? minFileAgeForRead, maxFileAgeForRead: maxFileAgeForRead, maxObjectsInFile: maxObjectsInFile, - maxObjectSize: with.maxObjectSize ?? maxObjectSize, - initialUploadDelay: initialUploadDelay, - minUploadDelay: minUploadDelay, - maxUploadDelay: maxUploadDelay, - uploadDelayChangeRate: uploadDelayChangeRate + maxObjectSize: override.maxObjectSize ?? maxObjectSize, + initialUploadDelay: override.initialUploadDelay ?? initialUploadDelay, + minUploadDelay: override.minUploadDelay ?? minUploadDelay, + maxUploadDelay: override.maxUploadDelay ?? maxUploadDelay, + uploadDelayChangeRate: override.uploadDelayChangeRate ?? uploadDelayChangeRate ) } } diff --git a/Sources/Datadog/DatadogInternal/PerformancePresetOverride.swift b/Sources/Datadog/DatadogInternal/PerformancePresetOverride.swift index 426f974fc3..653a155c7d 100644 --- a/Sources/Datadog/DatadogInternal/PerformancePresetOverride.swift +++ b/Sources/Datadog/DatadogInternal/PerformancePresetOverride.swift @@ -10,22 +10,74 @@ import Foundation /// performance presets by setting optional limits. If the limits are not provided, the default values from /// the `PerformancePreset` object will be used. public struct PerformancePresetOverride { - /// An optional value representing the maximum allowed file size in bytes. + /// Overrides the the maximum allowed file size in bytes. /// If not provided, the default value from the `PerformancePreset` object is used. let maxFileSize: UInt64? - /// An optional value representing the maximum allowed object size in bytes. + /// Overrides the maximum allowed object size in bytes. /// If not provided, the default value from the `PerformancePreset` object is used. let maxObjectSize: UInt64? - /// Initializes a new `PerformancePresetOverride` instance with the provided - /// maximum file size and maximum object size limits. + /// Overrides the maximum age qualifying given file for reuse (in seconds). + /// If recently used file is younger than this, it is reused - otherwise: new file is created. + let maxFileAgeForWrite: TimeInterval? + + /// Minimum age qualifying given file for upload (in seconds). + /// If the file is older than this, it is uploaded (and then deleted if upload succeeded). + /// It has an arbitrary offset (~0.5s) over `maxFileAgeForWrite` to ensure that no upload can start for the file being currently written. + let minFileAgeForRead: TimeInterval? + + /// Overrides the initial upload delay (in seconds). + /// At runtime, the upload interval starts with `initialUploadDelay` and then ranges from `minUploadDelay` to `maxUploadDelay` depending + /// on delivery success or failure. + let initialUploadDelay: TimeInterval? + + /// Overrides the mininum interval of data upload (in seconds). + let minUploadDelay: TimeInterval? + + /// Overrides the maximum interval of data upload (in seconds). + let maxUploadDelay: TimeInterval? + + /// Overrides the current interval is change on successful upload. Should be less or equal `1.0`. + /// E.g: if rate is `0.1` then `delay` will be changed by `delay * 0.1`. + let uploadDelayChangeRate: Double? + + /// Initializes a new `PerformancePresetOverride` instance with the provided overrides. /// /// - Parameters: /// - maxFileSize: The maximum allowed file size in bytes, or `nil` to use the default value from `PerformancePreset`. /// - maxObjectSize: The maximum allowed object size in bytes, or `nil` to use the default value from `PerformancePreset`. - public init(maxFileSize: UInt64?, maxObjectSize: UInt64?) { + /// - meanFileAge: The mean age qualifying a file for reuse, or `nil` to use the default value from `PerformancePreset`. + /// - minUploadDelay: The mininum interval of data uploads, or `nil` to use the default value from `PerformancePreset`. + public init( + maxFileSize: UInt64?, + maxObjectSize: UInt64?, + meanFileAge: TimeInterval?, + minUploadDelay: TimeInterval? + ) { self.maxFileSize = maxFileSize self.maxObjectSize = maxObjectSize + + if let meanFileAge { + // Following constants are the same as in `DatadogCore.PerformancePreset` + self.maxFileAgeForWrite = meanFileAge * 0.95 // 5% below the mean age + self.minFileAgeForRead = meanFileAge * 1.05 // 5% above the mean age + } else { + self.maxFileAgeForWrite = nil + self.minFileAgeForRead = nil + } + + if let minUploadDelay { + // Following constants are the same as in `DatadogCore.PerformancePreset` + self.initialUploadDelay = minUploadDelay * 5 + self.minUploadDelay = minUploadDelay + self.maxUploadDelay = minUploadDelay * 10 + self.uploadDelayChangeRate = 0.1 + } else { + self.initialUploadDelay = nil + self.minUploadDelay = nil + self.maxUploadDelay = nil + self.uploadDelayChangeRate = nil + } } } diff --git a/Tests/DatadogTests/Datadog/Core/PerformancePresetTests.swift b/Tests/DatadogTests/Datadog/Core/PerformancePresetTests.swift index f761f9a789..b696368a6b 100644 --- a/Tests/DatadogTests/Datadog/Core/PerformancePresetTests.swift +++ b/Tests/DatadogTests/Datadog/Core/PerformancePresetTests.swift @@ -140,8 +140,21 @@ class PerformancePresetTests: XCTestCase { func testPresetsUpdate() { let preset = PerformancePreset(batchSize: .mockRandom(), uploadFrequency: .mockRandom(), bundleType: .mockRandom()) - let updatedPreset = preset.updated(with: PerformancePresetOverride(maxFileSize: .mockRandom(), maxObjectSize: .mockRandom())) + let updatedPreset = preset.updated( + with: PerformancePresetOverride( + maxFileSize: .mockRandom(), + maxObjectSize: .mockRandom(), + meanFileAge: .mockRandom(), + minUploadDelay: .mockRandom() + ) + ) XCTAssertNotEqual(preset.maxFileSize, updatedPreset.maxFileSize) XCTAssertNotEqual(preset.maxObjectSize, updatedPreset.maxObjectSize) + XCTAssertNotEqual(preset.maxFileAgeForWrite, updatedPreset.maxFileAgeForWrite) + XCTAssertNotEqual(preset.minFileAgeForRead, updatedPreset.minFileAgeForRead) + XCTAssertNotEqual(preset.initialUploadDelay, updatedPreset.initialUploadDelay) + XCTAssertNotEqual(preset.minUploadDelay, updatedPreset.minUploadDelay) + XCTAssertNotEqual(preset.maxUploadDelay, updatedPreset.maxUploadDelay) + XCTAssertNotEqual(preset.uploadDelayChangeRate, updatedPreset.uploadDelayChangeRate) } } diff --git a/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift b/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift index f79c943fc0..a6399cad2d 100644 --- a/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift +++ b/Tests/DatadogTests/Datadog/DatadogCore/DatadogCoreTests.swift @@ -214,11 +214,18 @@ class DatadogCoreTests: XCTestCase { try core.register( feature: FeatureMock( name: name, - performanceOverride: PerformancePresetOverride(maxFileSize: 123, maxObjectSize: 456) + performanceOverride: PerformancePresetOverride( + maxFileSize: 123, + maxObjectSize: 456, + meanFileAge: 100, + minUploadDelay: nil + ) ) ) feature = core.v2Features.values.first XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.maxObjectSize, 456) XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.maxFileSize, 123) + XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.maxFileAgeForWrite, 95) + XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.minFileAgeForRead, 105) } } From acd37130bfdd00d6743a9f19dfdf40a7d2b1b63e Mon Sep 17 00:00:00 2001 From: Maciej Burda Date: Thu, 6 Jul 2023 12:42:03 +0100 Subject: [PATCH 72/87] REPLAY-1765 Update tests --- .../RUM/Integrations/SessionReplayDependency.swift | 2 +- .../RUM/RUMMonitor/Scopes/RUMApplicationScope.swift | 4 ++-- .../Datadog/RUM/RUMMonitor/Scopes/RUMResourceScope.swift | 4 ++-- .../Datadog/RUM/RUMMonitor/Scopes/RUMSessionScope.swift | 6 +++--- .../RUM/RUMMonitor/Scopes/RUMUserActionScope.swift | 2 +- Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift | 8 ++++---- Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift | 8 ++++---- .../RUM/Integrations/SessionReplayDependencyTests.swift | 8 ++++---- .../RUM/RUMMonitor/Scopes/RUMSessionScopeTests.swift | 4 ++-- .../Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift | 5 ++++- 10 files changed, 27 insertions(+), 24 deletions(-) diff --git a/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift b/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift index 65b1b0705f..dfccc80626 100644 --- a/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift +++ b/Sources/Datadog/RUM/Integrations/SessionReplayDependency.swift @@ -34,7 +34,7 @@ extension DatadogContext { extension FeatureBaggage { /// The value indicating if replay is being performed by Session Replay. - var isReplayBeingRecorded: Bool { + var hasReplay: Bool { guard let hasReplay: Bool = self[SessionReplayDependency.hasReplay] else { return false } diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMApplicationScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMApplicationScope.swift index e7938762d3..fd1e28b934 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMApplicationScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMApplicationScope.swift @@ -117,7 +117,7 @@ internal class RUMApplicationScope: RUMScope, RUMContextProvider { parent: self, startTime: context.sdkInitDate, dependencies: dependencies, - isReplayBeingRecorded: context.srBaggage?.isReplayBeingRecorded + hasReplay: context.srBaggage?.hasReplay ) sessionScopes.append(initialSession) @@ -149,7 +149,7 @@ internal class RUMApplicationScope: RUMScope, RUMContextProvider { parent: self, startTime: command.time, dependencies: dependencies, - isReplayBeingRecorded: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, resumingViewScope: resumingViewScope ) lastActiveView = nil diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScope.swift index 4583be071b..c01787e241 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMResourceScope.swift @@ -200,7 +200,7 @@ internal class RUMResourceScope: RUMScope { ), service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), @@ -260,7 +260,7 @@ internal class RUMResourceScope: RUMScope { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMSessionScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMSessionScope.swift index b7a4fcb4bd..1b2812b404 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMSessionScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMSessionScope.swift @@ -63,7 +63,7 @@ internal class RUMSessionScope: RUMScope, RUMContextProvider { parent: RUMContextProvider, startTime: Date, dependencies: RUMScopeDependencies, - isReplayBeingRecorded: Bool?, + hasReplay: Bool?, resumingViewScope: RUMViewScope? = nil ) { self.parent = parent @@ -79,7 +79,7 @@ internal class RUMSessionScope: RUMScope, RUMContextProvider { sessionUUID: sessionUUID.rawValue, isInitialSession: isInitialSession, hasTrackedAnyView: false, - didStartWithReplay: isReplayBeingRecorded + didStartWithReplay: hasReplay ) if let viewScope = resumingViewScope, @@ -115,7 +115,7 @@ internal class RUMSessionScope: RUMScope, RUMContextProvider { parent: expiredSession.parent, startTime: startTime, dependencies: expiredSession.dependencies, - isReplayBeingRecorded: context.srBaggage?.isReplayBeingRecorded + hasReplay: context.srBaggage?.hasReplay ) // Transfer active Views by creating new `RUMViewScopes` for their identity objects: diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScope.swift index 221b3e551f..3ec078de00 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMUserActionScope.swift @@ -163,7 +163,7 @@ internal class RUMUserActionScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift index 19d0436519..e9a6f64b85 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift @@ -390,7 +390,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), @@ -457,7 +457,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { privacy: nil, service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, isActive: self.context.isSessionActive, sampledForReplay: nil, @@ -563,7 +563,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), @@ -614,7 +614,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), diff --git a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift index 101971a6ba..5ae978c36c 100644 --- a/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift +++ b/Tests/DatadogTests/Datadog/Mocks/RUMFeatureMocks.swift @@ -759,14 +759,14 @@ extension RUMSessionScope { parent: RUMContextProvider = RUMContextProviderMock(), startTime: Date = .mockAny(), dependencies: RUMScopeDependencies = .mockAny(), - isReplayBeingRecorded: Bool? = .mockAny() + hasReplay: Bool? = .mockAny() ) -> RUMSessionScope { return RUMSessionScope( isInitialSession: isInitialSession, parent: parent, startTime: startTime, dependencies: dependencies, - isReplayBeingRecorded: isReplayBeingRecorded + hasReplay: hasReplay ) } } @@ -1029,11 +1029,11 @@ class ContinuousVitalReaderMock: ContinuousVitalReader { // MARK: - Dependency on Session Replay extension Dictionary where Key == String, Value == FeatureBaggage { - static func mockSessionReplayAttributes(hasReplay: Bool?, recordsCount: [String: Int64]? = nil) -> Self { + static func mockSessionReplayAttributes(hasReplay: Bool?, recordsCountByViewID: [String: Int64]? = nil) -> Self { return [ SessionReplayDependency.srBaggageKey: [ SessionReplayDependency.hasReplay: hasReplay, - SessionReplayDependency.recordsCount: recordsCount + SessionReplayDependency.recordsCountByViewID: recordsCountByViewID ] ] } diff --git a/Tests/DatadogTests/Datadog/RUM/Integrations/SessionReplayDependencyTests.swift b/Tests/DatadogTests/Datadog/RUM/Integrations/SessionReplayDependencyTests.swift index b4e6cce481..9231b8d074 100644 --- a/Tests/DatadogTests/Datadog/RUM/Integrations/SessionReplayDependencyTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/Integrations/SessionReplayDependencyTests.swift @@ -10,16 +10,16 @@ import XCTest class SessionReplayDependencyTests: XCTestCase { func testWhenSessionReplayIsConfigured_itReadsReplayBeingRecorded() { let hasReplay: Bool = .random() - let recordsCount: [String: Int64] = [.mockRandom(): .mockRandom()] + let recordsCountByViewID: [String: Int64] = [.mockRandom(): .mockRandom()] // When let context: DatadogContext = .mockWith( - featuresAttributes: .mockSessionReplayAttributes(hasReplay: hasReplay, recordsCount: recordsCount) + featuresAttributes: .mockSessionReplayAttributes(hasReplay: hasReplay, recordsCountByViewID: recordsCountByViewID) ) // Then - XCTAssertEqual(context.srBaggage?.isReplayBeingRecorded, hasReplay) - XCTAssertEqual(context.srBaggage?.recordsCount, recordsCount) + XCTAssertEqual(context.srBaggage?.hasReplay, hasReplay) + XCTAssertEqual(context.srBaggage?.recordsCountByViewID, recordsCountByViewID) } func testWhenSessionReplayIsNotConfigured_itReadsNoSRBaggage() { diff --git a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMSessionScopeTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMSessionScopeTests.swift index 6a637f6209..de1fd6c1b7 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMSessionScopeTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMSessionScopeTests.swift @@ -317,7 +317,7 @@ class RUMSessionScopeTests: XCTestCase { core: core, sessionSampler: .mockRandom() // no matter if sampled or not ), - isReplayBeingRecorded: randomIsReplayBeingRecorded + hasReplay: randomIsReplayBeingRecorded ) // Then @@ -352,7 +352,7 @@ class RUMSessionScopeTests: XCTestCase { parent: parent, startTime: sessionStartTime, dependencies: .mockWith(core: core), - isReplayBeingRecorded: randomIsReplayBeingRecorded + hasReplay: randomIsReplayBeingRecorded ) // When diff --git a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift index cdb2114f23..1853086286 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift @@ -199,7 +199,10 @@ class RUMViewScopeTests: XCTestCase { let hasReplay: Bool = .mockRandom() var context = self.context - context.featuresAttributes = .mockSessionReplayAttributes(hasReplay: hasReplay, recordsCount: [scope.viewUUID.toRUMDataFormat: 1]) + context.featuresAttributes = .mockSessionReplayAttributes( + hasReplay: hasReplay, + recordsCountByViewID: [scope.viewUUID.toRUMDataFormat: 1] + ) _ = scope.process( command: RUMCommandMock(time: currentTime), From ecb11fac9606ad7c331be3c5c4a78f8efee65955 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Thu, 6 Jul 2023 13:26:20 +0200 Subject: [PATCH 73/87] Remove session replay from library --- .../spm/App/ViewController.swift | 14 +++++++------- .../spm/SPMProject.xcodeproj.src/project.pbxproj | 8 -------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/dependency-manager-tests/spm/App/ViewController.swift b/dependency-manager-tests/spm/App/ViewController.swift index 0444307b84..227b388398 100644 --- a/dependency-manager-tests/spm/App/ViewController.swift +++ b/dependency-manager-tests/spm/App/ViewController.swift @@ -10,9 +10,9 @@ import DatadogLogs import DatadogTrace import DatadogRUM import DatadogCrashReporting -#if os(iOS) -import DatadogSessionReplay -#endif +//#if os(iOS) +//import DatadogSessionReplay +//#endif internal class ViewController: UIViewController { private var logger: LoggerProtocol! // swiftlint:disable:this implicitly_unwrapped_optional @@ -53,10 +53,10 @@ internal class ViewController: UIViewController { logger.info("It works") _ = Tracer.shared().startSpan(operationName: "this too") - #if os(iOS) - // Session Replay API must be visible: - SessionReplay.enable(with: .init(replaySampleRate: 0)) - #endif +// #if os(iOS) +// // Session Replay API must be visible: +// SessionReplay.enable(with: .init(replaySampleRate: 0)) +// #endif addLabel() } diff --git a/dependency-manager-tests/spm/SPMProject.xcodeproj.src/project.pbxproj b/dependency-manager-tests/spm/SPMProject.xcodeproj.src/project.pbxproj index f548981942..9c70ae2c4c 100644 --- a/dependency-manager-tests/spm/SPMProject.xcodeproj.src/project.pbxproj +++ b/dependency-manager-tests/spm/SPMProject.xcodeproj.src/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 3CB7A04C29F6ABDA007A27ED /* DatadogWebViewTracking in Frameworks */ = {isa = PBXBuildFile; productRef = 3CB7A04B29F6ABDA007A27ED /* DatadogWebViewTracking */; }; - 618291CF2A4619C600100CA0 /* DatadogSessionReplay in Frameworks */ = {isa = PBXBuildFile; productRef = 618291CE2A4619C600100CA0 /* DatadogSessionReplay */; }; 61C363DA24374D5F00C4D4E6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C363D924374D5F00C4D4E6 /* AppDelegate.swift */; }; 61C363DC24374D5F00C4D4E6 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C363DB24374D5F00C4D4E6 /* SceneDelegate.swift */; }; 61C363DE24374D5F00C4D4E6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C363DD24374D5F00C4D4E6 /* ViewController.swift */; }; @@ -113,7 +112,6 @@ D2966C2E29CA1F2D00FC6B3C /* DatadogTrace in Frameworks */, D2344E1F29ACDE61007F5BD2 /* DatadogLogs in Frameworks */, D2CE76BC29F6B9EE00D79713 /* DatadogRUM in Frameworks */, - 618291CF2A4619C600100CA0 /* DatadogSessionReplay in Frameworks */, 3CB7A04C29F6ABDA007A27ED /* DatadogWebViewTracking in Frameworks */, 9E73374026B0123500917C24 /* DatadogCrashReporting in Frameworks */, ); @@ -257,7 +255,6 @@ D2966C2D29CA1F2D00FC6B3C /* DatadogTrace */, D2CE76BB29F6B9EE00D79713 /* DatadogRUM */, 3CB7A04B29F6ABDA007A27ED /* DatadogWebViewTracking */, - 618291CE2A4619C600100CA0 /* DatadogSessionReplay */, D26A32D62A4C892A00903514 /* DatadogCore */, ); productName = SPMProject; @@ -1073,11 +1070,6 @@ package = 9E73373E26B0123500917C24 /* XCRemoteSwiftPackageReference "dd-sdk-ios" */; productName = DatadogWebViewTracking; }; - 618291CE2A4619C600100CA0 /* DatadogSessionReplay */ = { - isa = XCSwiftPackageProductDependency; - package = 9E73373E26B0123500917C24 /* XCRemoteSwiftPackageReference "dd-sdk-ios" */; - productName = DatadogSessionReplay; - }; 9E73373F26B0123500917C24 /* DatadogCrashReporting */ = { isa = XCSwiftPackageProductDependency; package = 9E73373E26B0123500917C24 /* XCRemoteSwiftPackageReference "dd-sdk-ios" */; From 5efc70e66cbfbc83862a64bcbf197067f3da343c Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Thu, 6 Jul 2023 22:36:47 +0200 Subject: [PATCH 74/87] Fix assets validator for v2 --- .../src/release/assets/gh_asset.py | 63 ++++++++++++++++--- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/tools/distribution/src/release/assets/gh_asset.py b/tools/distribution/src/release/assets/gh_asset.py index 52380fad7f..92c91c9c01 100644 --- a/tools/distribution/src/release/assets/gh_asset.py +++ b/tools/distribution/src/release/assets/gh_asset.py @@ -25,12 +25,14 @@ def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool class DatadogXCFrameworkValidator(XCFrameworkValidator): - name = 'DatadogCore.xcframework' + name = 'Datadog.xcframework' def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool: - # always expect `DatadogCore.xcframework` + max_version = Version.parse('2.0.0-beta1') + if in_version.is_newer_than_or_equal(max_version): + return False # Datadog.xcframework no longer exist in `2.0` - dir = zip_directory.get('DatadogCore.xcframework') + dir = zip_directory.get('Datadog.xcframework') # above 1.12.1: framework includes arm64e slices min_arm64e_version = Version.parse('1.12.1') @@ -203,9 +205,9 @@ def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool return False zip_directory.get('Kronos.xcframework').assert_it_has_files([ - 'ios-arm64_armv7', - 'ios-arm64_armv7/dSYMs/*.dSYM', - 'ios-arm64_armv7/**/*.swiftinterface', + 'ios-arm64_arm64e', + 'ios-arm64_arm64e/dSYMs/*.dSYM', + 'ios-arm64_arm64e/**/*.swiftinterface', 'ios-arm64_i386_x86_64-simulator', 'ios-arm64_i386_x86_64-simulator/dSYMs/*.dSYM', @@ -213,17 +215,62 @@ def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool ]) return True + +class DatadogModuleXCFrameworkValidator(XCFrameworkValidator): + def __init__(self, name, platforms = ["ios", "tvos"]): + self.name = f"{name}.xcframework" + self.platforms = platforms + + def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool: + min_version = Version.parse('2.0.0-beta1') + if in_version.is_older_than(min_version): + return False # introduced in 2.0 + + directory = zip_directory.get(self.name) + + if "ios" in self.platforms : + directory.assert_it_has_files([ + 'ios-arm64_arm64e', + 'ios-arm64_arm64e/dSYMs/*.dSYM', + 'ios-arm64_arm64e/**/*.swiftinterface', + + 'ios-arm64_x86_64-simulator', + 'ios-arm64_x86_64-simulator/dSYMs/*.dSYM', + 'ios-arm64_x86_64-simulator/**/*.swiftinterface', + ]) + if "tvos" in self.platforms : + directory.assert_it_has_files([ + + 'tvos-arm64', + 'tvos-arm64/dSYMs/*.dSYM', + 'tvos-arm64/**/*.swiftinterface', + + 'tvos-arm64_x86_64-simulator', + 'tvos-arm64_x86_64-simulator/dSYMs/*.dSYM', + 'tvos-arm64_x86_64-simulator/**/*.swiftinterface', + ]) + + return True + xcframeworks_validators: [XCFrameworkValidator] = [ DatadogXCFrameworkValidator(), + KronosXCFrameworkValidator(), + + # 2.0 + DatadogModuleXCFrameworkValidator("DatadogInternal"), + DatadogModuleXCFrameworkValidator("DatadogCore"), + DatadogModuleXCFrameworkValidator("DatadogLogs"), + DatadogModuleXCFrameworkValidator("DatadogTrace"), + DatadogModuleXCFrameworkValidator("DatadogRUM"), + DatadogModuleXCFrameworkValidator("DatadogWebViewTracking", platforms=["ios"]), + DatadogObjcXCFrameworkValidator(), DatadogCrashReportingXCFrameworkValidator(), CrashReporterXCFrameworkValidator(), - KronosXCFrameworkValidator(), ] - class GHAsset: """ The release asset attached to GH Release tag - a `.zip` archive with XCFrameworks found recursively in SDK repo From e1a45e3b1336ee9345adf966f5a6964b2be97366 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Thu, 6 Jul 2023 22:37:11 +0200 Subject: [PATCH 75/87] Fix DatadogSDK.podspec --- DatadogSDK.podspec | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DatadogSDK.podspec b/DatadogSDK.podspec index 79095880f3..af87c7c5d9 100644 --- a/DatadogSDK.podspec +++ b/DatadogSDK.podspec @@ -21,12 +21,11 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/DataDog/dd-sdk-ios.git", :tag => s.version.to_s } s.deprecated_in_favor_of = - 'DatadogCore, DatadogLogs, DatadogRUM, DatadogTrace, and DatadogWebViewTracking' + 'DatadogCore, DatadogLogs, DatadogRUM, and DatadogTrace' s.dependency 'DatadogCore', s.version.to_s s.dependency 'DatadogLogs', s.version.to_s s.dependency 'DatadogRUM', s.version.to_s s.dependency 'DatadogTrace', s.version.to_s - s.dependency 'DatadogWebViewTracking', s.version.to_s end From 7adf22c421db3d6bf1428bfa4fd13481602b0e1e Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Fri, 7 Jul 2023 08:23:01 +0200 Subject: [PATCH 76/87] REPLAY-1868 Fix flaky assertion --- Tests/DatadogTests/Datadog/Core/PerformancePresetTests.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/DatadogTests/Datadog/Core/PerformancePresetTests.swift b/Tests/DatadogTests/Datadog/Core/PerformancePresetTests.swift index b696368a6b..f09166669e 100644 --- a/Tests/DatadogTests/Datadog/Core/PerformancePresetTests.swift +++ b/Tests/DatadogTests/Datadog/Core/PerformancePresetTests.swift @@ -148,6 +148,7 @@ class PerformancePresetTests: XCTestCase { minUploadDelay: .mockRandom() ) ) + XCTAssertNotEqual(preset.maxFileSize, updatedPreset.maxFileSize) XCTAssertNotEqual(preset.maxObjectSize, updatedPreset.maxObjectSize) XCTAssertNotEqual(preset.maxFileAgeForWrite, updatedPreset.maxFileAgeForWrite) @@ -155,6 +156,6 @@ class PerformancePresetTests: XCTestCase { XCTAssertNotEqual(preset.initialUploadDelay, updatedPreset.initialUploadDelay) XCTAssertNotEqual(preset.minUploadDelay, updatedPreset.minUploadDelay) XCTAssertNotEqual(preset.maxUploadDelay, updatedPreset.maxUploadDelay) - XCTAssertNotEqual(preset.uploadDelayChangeRate, updatedPreset.uploadDelayChangeRate) + XCTAssertEqual(0.1, updatedPreset.uploadDelayChangeRate) } } From 467c4e7cc651403043c02c181c139c984f9c1b85 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Fri, 7 Jul 2023 09:58:38 +0200 Subject: [PATCH 77/87] Update gh_asset.py --- tools/distribution/src/release/assets/gh_asset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/distribution/src/release/assets/gh_asset.py b/tools/distribution/src/release/assets/gh_asset.py index 92c91c9c01..606ac46605 100644 --- a/tools/distribution/src/release/assets/gh_asset.py +++ b/tools/distribution/src/release/assets/gh_asset.py @@ -206,8 +206,8 @@ def validate(self, zip_directory: DirectoryMatcher, in_version: Version) -> bool zip_directory.get('Kronos.xcframework').assert_it_has_files([ 'ios-arm64_arm64e', - 'ios-arm64_arm64e/dSYMs/*.dSYM', - 'ios-arm64_arm64e/**/*.swiftinterface', + 'ios-arm64_arm64e/dSYMs/*.dSYM', + 'ios-arm64_arm64e/**/*.swiftinterface', 'ios-arm64_i386_x86_64-simulator', 'ios-arm64_i386_x86_64-simulator/dSYMs/*.dSYM', From 5b18842b33aea20ae04c704b0c462c0287223be5 Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Mon, 10 Jul 2023 09:58:04 +0200 Subject: [PATCH 78/87] REPLAY-1616 Fix flaky execution of sub-process commands --- .../Sources/Shell/CommandLine.swift | 20 +- .../Sources/Shell/ProcessCommandLine.swift | 188 +++++++++++------- .../ShellTests/ProcessCommandLineTests.swift | 33 ++- 3 files changed, 151 insertions(+), 90 deletions(-) diff --git a/tools/sr-snapshots/Sources/Shell/CommandLine.swift b/tools/sr-snapshots/Sources/Shell/CommandLine.swift index 18bea92162..4d66aba4eb 100644 --- a/tools/sr-snapshots/Sources/Shell/CommandLine.swift +++ b/tools/sr-snapshots/Sources/Shell/CommandLine.swift @@ -6,8 +6,10 @@ import Foundation -public struct CommandLineError: Error, CustomStringConvertible { - let result: CommandLineResult +/// An error thrown when shell command exited with non-zero code. +public struct CommandError: Error, CustomStringConvertible { + /// The full result of command. + let result: CommandResult public var description: String { return """ @@ -19,10 +21,10 @@ public struct CommandLineError: Error, CustomStringConvertible { } /// Result of executing shell command. -public struct CommandLineResult { - /// Command's STDOUT value. +public struct CommandResult { + /// Command's STDOUT. public let output: String? - /// Command's STDERR value. + /// Command's STDERR. public let error: String? /// Exit code of the command. public let status: Int32 @@ -31,9 +33,9 @@ public struct CommandLineResult { /// Protocol for running command line commands public protocol CommandLine { /// Executes given shell command. - /// - Parameter command: command to run - /// - Returns: result of the command - func shellResult(_ command: String) throws -> CommandLineResult + /// - Parameter command: The command to run. + /// - Returns: The result of the command. + func shellResult(_ command: String) throws -> CommandResult } public extension CommandLine { @@ -45,7 +47,7 @@ public extension CommandLine { func shell(_ command: String) throws -> String { let result = try shellResult(command) if result.status != 0 { - throw CommandLineError(result: result) + throw CommandError(result: result) } else if let output = result.output, !output.isEmpty { return output } else if let error = result.error, !error.isEmpty { diff --git a/tools/sr-snapshots/Sources/Shell/ProcessCommandLine.swift b/tools/sr-snapshots/Sources/Shell/ProcessCommandLine.swift index 0b15ae8ba8..4c4ac3e598 100644 --- a/tools/sr-snapshots/Sources/Shell/ProcessCommandLine.swift +++ b/tools/sr-snapshots/Sources/Shell/ProcessCommandLine.swift @@ -5,96 +5,138 @@ */ import Foundation +import Dispatch +/// Runs a child process with capturing standard output and standard error. +/// +/// Inspired by https://developer.apple.com/forums/thread/690310 public class ProcessCommandLine: CommandLine { - private var output: [String] = [] - private var error: [String] = [] + public init() {} - private let notificationCenter: NotificationCenter - - public init(notificationCenter: NotificationCenter = .default) { - self.notificationCenter = notificationCenter - } - - @discardableResult - public func shellResult(_ command: String) throws -> CommandLineResult { - output = [] - error = [] + /// Executes given shell command. + /// - Parameter command: The command to run. + /// - Returns: The result of the command. + public func shellResult(_ command: String) throws -> CommandResult { + var result: Result? = nil + let queue = DispatchQueue(label: "com.datadoghq.cli-\(UUID().uuidString)") print("🐚 → \(command)") - let outpipe = Pipe() - let outfh = outpipe.fileHandleForReading - outfh.waitForDataInBackgroundAndNotify() - notificationCenter.addObserver(self, selector: #selector(readOutput), name: NSNotification.Name.NSFileHandleDataAvailable, object: outfh) - - let errpipe = Pipe() - let errfh = errpipe.fileHandleForReading - errfh.waitForDataInBackgroundAndNotify() - notificationCenter.addObserver(self, selector: #selector(readError), name: NSNotification.Name.NSFileHandleDataAvailable, object: errfh) - - let task = Process() - task.launchPath = "/bin/bash" - task.arguments = ["-c", command] - task.standardOutput = outpipe - task.standardError = errpipe - task.launch() - task.waitUntilExit() - - if task.isRunning { - fatalError() + let semaphore = DispatchSemaphore(value: 0) + shellWithCompletion(command, on: queue) { callbackResult in + result = callbackResult + semaphore.signal() } + _ = semaphore.wait(timeout: .distantFuture) - return CommandLineResult( - output: output.joined(separator: "\n"), - error: error.joined(separator: "\n"), - status: task.terminationStatus - ) - } - - @objc - private func readOutput(notification: Notification) { - guard let handle = notification.object as? FileHandle else { - return + switch result! { + case .success(let result): return result + case .failure(let error): throw error } + } - let data = handle.availableData - if let str = String(data: data, encoding: .utf8) { - if let sanitized = sanitize(line: str) { - print(sanitized) - output.append(sanitized) + internal func shellWithCompletion( + _ command: String, + on queue: DispatchQueue, + completion: @escaping (Result) -> Void + ) { + queue.async { + let processGroup = DispatchGroup() + let stdoutPipe = Pipe() + let stderrPipe = Pipe() + var stdoutData = Data() + var stderrData = Data() + var posixError: Error? = nil + + let task = Process() + task.launchPath = "/bin/bash" + task.arguments = ["-c", command] + task.standardOutput = stdoutPipe + task.standardError = stderrPipe + + processGroup.enter() + task.terminationHandler = { _ in + // In case the latter `try task.run()` throws, bouncing the group leave() + // on queue here ensures it is properly teared down. + queue.async { processGroup.leave() } } - } - - handle.waitForDataInBackgroundAndNotify() - } - @objc - private func readError(notification: Notification) { - guard let handle = notification.object as? FileHandle else { - return - } + // This runs the supplied block when all three events have completed (task + // termination and the end of both STDOUT and STDERR reads). + processGroup.notify(queue: queue) { + if let error = posixError { + completion(.failure(error)) + } else { + let result = CommandResult( + stdoutData: stdoutData, + stderrData: stderrData, + terminationStatus: task.terminationStatus + ) + completion(.success(result)) + } + } - let data = handle.availableData - if let str = String(data: data, encoding: .utf8) { - if let sanitized = sanitize(line: str) { - print(sanitized) - error.append(sanitized) + do { + func posixErr(_ error: Int32) -> Error { + NSError(domain: NSPOSIXErrorDomain, code: Int(error), userInfo: nil) + } + + try task.run() + + // Enter the process group and leaver it only after STDOUT buffer is read. + processGroup.enter() + let stdoutFile = stdoutPipe.fileHandleForReading + let stdoutReadIO = DispatchIO(type: .stream, fileDescriptor: stdoutFile.fileDescriptor, queue: queue) { _ in + try! stdoutFile.close() + } + stdoutReadIO.read(offset: 0, length: .max, queue: queue) { isDone, chunk, error in + stdoutData.append(contentsOf: chunk ?? .empty) + if isDone || error != 0 { + stdoutReadIO.close() + if posixError == nil && error != 0 { posixError = posixErr(error) } + processGroup.leave() + } + } + + // Enter the process group and leaver it only after STDERR buffer is read. + processGroup.enter() + let stderrFile = stderrPipe.fileHandleForReading + let stderrReadIO = DispatchIO(type: .stream, fileDescriptor: stderrFile.fileDescriptor, queue: queue) { _ in + try! stderrFile.close() + } + stderrReadIO.read(offset: 0, length: .max, queue: queue) { isDone, chunk, error in + stderrData.append(contentsOf: chunk ?? .empty) + if isDone || error != 0 { + stderrReadIO.close() + if posixError == nil && error != 0 { posixError = posixErr(error) } + processGroup.leave() + } + } + } catch { + posixError = error + // We’ve only entered the group once at this point, so the single leave done by the + // termination handler is enough to run the notify block and call the + // client’s completion handler. + task.terminationHandler!(task) } } - handle.waitForDataInBackgroundAndNotify() } +} - /// Removes new lines and trailing spaces from a string - private func sanitize(line: String) -> String? { - var trimmed = line.trimmingCharacters(in: .whitespacesAndNewlines) - guard trimmed.count > 0 else { - return nil - } - - // replace tabs with space - trimmed = trimmed.replacingOccurrences(of: "\t", with: " ") +private extension CommandResult { + init(stdoutData: Data, stderrData: Data, terminationStatus: Int32) { + self.output = String(data: stdoutData, encoding: .utf8).flatMap(sanitize(output:)) + self.error = String(data: stderrData, encoding: .utf8).flatMap(sanitize(output:)) + self.status = terminationStatus + } +} - return trimmed +/// Removes new lines and trailing spaces from a string +private func sanitize(output: String) -> String? { + var trimmed = output.trimmingCharacters(in: .whitespacesAndNewlines) + guard trimmed.count > 0 else { + return nil } + trimmed = trimmed.replacingOccurrences(of: "\t", with: " ") + return trimmed } diff --git a/tools/sr-snapshots/Tests/ShellTests/ProcessCommandLineTests.swift b/tools/sr-snapshots/Tests/ShellTests/ProcessCommandLineTests.swift index 78e9eda3f1..49e446a94f 100644 --- a/tools/sr-snapshots/Tests/ShellTests/ProcessCommandLineTests.swift +++ b/tools/sr-snapshots/Tests/ShellTests/ProcessCommandLineTests.swift @@ -10,23 +10,40 @@ import XCTest class ShellCommandTests: XCTestCase { private let cli = ProcessCommandLine() - func testWhenCommandExitsWithCode0_itReturnsOutput() throws { - let output = try cli.shell("echo 'foo bar' && exit 0") - XCTAssertEqual(output, "foo bar") + func testWhenCommandPrintsToStandardOutputAndExitsWith0() throws { + let output = try cli.shell("echo 'STDOUT foo' && exit 0") + XCTAssertEqual(output, "STDOUT foo") } - func testWhenCommandExitsWithCodeOtherThan0_itThrowsErrorAndReturnsOutput() throws { - XCTAssertThrowsError(try cli.shell("echo 'foo bar' && exit 1")) { error in + func testWhenCommandPrintsToStandardErrorAndExitsWith0() throws { + let output = try cli.shell("echo 'STDERR foo' 1>&2 && exit 0") + XCTAssertEqual(output, "STDERR foo") + } + + func testWhenCommandPrintsToBothOutputsAndExitsWith0() throws { + let output = try cli.shell("echo 'STDERR foo' 1>&2 && echo 'STDOUT foo' && exit 0") + XCTAssertEqual(output, "STDOUT foo") + } + + func testWhenCommandExitsWithOtherCode() throws { + XCTAssertThrowsError(try cli.shell("echo 'STDERR foo' 1>&2 && echo 'STDOUT foo' && exit 1")) { error in // swiftlint:disable trailing_whitespace XCTAssertEqual( - (error as? CommandLineError)?.description, + (error as? CommandError)?.description, """ status: 1 - output: foo bar - error: + output: STDOUT foo + error: STDERR foo """ ) // swiftlint:enable trailing_whitespace } } + + func testCallingMultipleCommandsFromDifferentThreads() throws { + DispatchQueue.concurrentPerform(iterations: 100) { _ in + let output = try? cli.shell("echo 'STDOUT foo' && exit 0") + XCTAssertEqual(output, "STDOUT foo") + } + } } From 9f679f120ecf3d1d258b0725ccfa91021bf730d0 Mon Sep 17 00:00:00 2001 From: Ganesh Jangir Date: Fri, 30 Jun 2023 16:24:41 +0200 Subject: [PATCH 79/87] RUMM-3151 feat: reduce number of view updates by filtering events from payload --- Datadog/Datadog.xcodeproj/project.pbxproj | 476 +++++++++++++++++- .../Sources/Core/Storage/DataBlock.swift | 1 + .../Sources/Core/Storage/EventGenerator.swift | 60 +++ .../Sources/Core/Storage/Reading/Reader.swift | 1 + .../Core/Storage/Writing/AsyncWriter.swift | 21 +- .../Persistence/EventGeneratorTests.swift | 2 +- .../Persistence/Reading/FileReaderTests.swift | 3 - .../Persistence/Writing/FileWriterTests.swift | 12 +- .../Tests/Datadog/Mocks/CoreMocks.swift | 2 +- DatadogInternal/Sources/Storage/Writer.swift | 17 +- DatadogInternal/Sources/Upload/Event.swift | 52 -- .../Tests/Upload/DataFormatTests.swift | 28 ++ .../Sources/Feature/RequestBuilder.swift | 4 +- DatadogRUM/Sources/Feature/RUMFeature.swift | 5 +- .../Sources/Feature/RUMViewEventsFilter.swift | 52 ++ .../Sources/Feature/RequestBuilder.swift | 8 +- .../RUMMonitor/Scopes/RUMViewScope.swift | 28 +- .../Tests/Feature/RequestBuilderTests.swift | 22 +- .../Tests/RUMViewEventsFilterTests.swift | 17 +- .../Sources/Feature/RequestBuilder.swift | 4 +- TestUtilities/Mocks/EventMocks.swift | 19 + 21 files changed, 679 insertions(+), 155 deletions(-) create mode 100644 DatadogCore/Sources/Core/Storage/EventGenerator.swift create mode 100644 DatadogInternal/Tests/Upload/DataFormatTests.swift create mode 100644 DatadogRUM/Sources/Feature/RUMViewEventsFilter.swift create mode 100644 TestUtilities/Mocks/EventMocks.swift diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index 0149bbaec7..b56c31fcfa 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -7,18 +7,42 @@ objects = { /* Begin PBXBuildFile section */ + 3C0D5DD72A543B3B00446CF9 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DD62A543B3B00446CF9 /* Event.swift */; }; + 3C0D5DD82A543B3B00446CF9 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DD62A543B3B00446CF9 /* Event.swift */; }; + 3C0D5DE22A543DC400446CF9 /* EventGeneratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DDF2A543DAE00446CF9 /* EventGeneratorTests.swift */; }; + 3C0D5DE32A543DC900446CF9 /* EventGeneratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DDF2A543DAE00446CF9 /* EventGeneratorTests.swift */; }; + 3C0D5DE42A543E3400446CF9 /* EventGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DDC2A543D5D00446CF9 /* EventGenerator.swift */; }; + 3C0D5DE52A543E3500446CF9 /* EventGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DDC2A543D5D00446CF9 /* EventGenerator.swift */; }; + 3C0D5DE92A543EA200446CF9 /* RUMViewEventsFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DE62A543E9700446CF9 /* RUMViewEventsFilterTests.swift */; }; + 3C0D5DEA2A543EA300446CF9 /* RUMViewEventsFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DE62A543E9700446CF9 /* RUMViewEventsFilterTests.swift */; }; + 3C0D5DEC2A54405A00446CF9 /* RUMViewEventsFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DEB2A54405A00446CF9 /* RUMViewEventsFilter.swift */; }; + 3C0D5DED2A54405A00446CF9 /* RUMViewEventsFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DEB2A54405A00446CF9 /* RUMViewEventsFilter.swift */; }; + 3C0D5DEF2A5442A900446CF9 /* EventMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DEE2A5442A900446CF9 /* EventMocks.swift */; }; + 3C0D5DF02A5442A900446CF9 /* EventMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DEE2A5442A900446CF9 /* EventMocks.swift */; }; + 3C0D5DF52A5443B100446CF9 /* DataFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DF42A5443B100446CF9 /* DataFormatTests.swift */; }; + 3C0D5DF62A5443B100446CF9 /* DataFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DF42A5443B100446CF9 /* DataFormatTests.swift */; }; 3C41693C29FBF4D50042B9D2 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; }; + 3C41694729FBF8CC0042B9D2 /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2DA2385298D57AA00C6C7E6 /* DatadogInternal.framework */; }; 3C74305C29FBC0480053B80F /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2DA2385298D57AA00C6C7E6 /* DatadogInternal.framework */; }; - 3C85D41B29F7C5C300AFF894 /* WebViewTrackingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WebViewTrackingTests.swift */; }; - 3C85D41C29F7C5C400AFF894 /* MessageEmitterCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* MessageEmitterCoreTests.swift */; }; - 3C85D41F29F7C5C900AFF894 /* WebViewMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewMessage.swift */; }; - 3C85D42129F7C5C900AFF894 /* MessageEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* MessageEmitter.swift */; }; + 3C85D41B29F7C5C300AFF894 /* WKUserContentController+DatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */; }; + 3C85D41C29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */; }; + 3C85D41D29F7C5C400AFF894 /* WKUserContentController+DatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */; }; + 3C85D41E29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */; }; + 3C85D41F29F7C5C900AFF894 /* WebViewTrackingMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */; }; + 3C85D42029F7C5C900AFF894 /* WKUserContentController+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */; }; + 3C85D42129F7C5C900AFF894 /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */; }; + 3C85D42229F7C5CA00AFF894 /* WebViewTrackingMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */; }; + 3C85D42329F7C5CA00AFF894 /* WKUserContentController+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */; }; + 3C85D42429F7C5CA00AFF894 /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */; }; + 3C85D42929F7C6FD00AFF894 /* TestUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D257958B298ABB83008A1BE5 /* TestUtilities.framework */; }; 3C85D42A29F7C70300AFF894 /* TestUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D257953E298ABA65008A1BE5 /* TestUtilities.framework */; }; 3C85D42C29F7C87D00AFF894 /* HostsSanitizerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */; }; 3C85D42D29F7C87D00AFF894 /* HostsSanitizerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */; }; 3C9C6BB429F7C0C000581C43 /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D23039A5298D513C001A1FA3 /* DatadogInternal.framework */; }; 3CE11A1129F7BE0900202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; }; 3CE11A1229F7BE0900202522 /* DatadogWebViewTracking.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 3CE11A2829F7BE1E00202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */; }; + 3CE11A3729F7BE6B00202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */; }; 49274906288048B500ECD49B /* InternalTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49274903288048AA00ECD49B /* InternalTelemetryTests.swift */; }; 49274907288048B800ECD49B /* InternalTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49274903288048AA00ECD49B /* InternalTelemetryTests.swift */; }; 61020C2A2757AD91005EEAEA /* BackgroundLocationMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61020C292757AD91005EEAEA /* BackgroundLocationMonitor.swift */; }; @@ -855,8 +879,6 @@ D2A7841029A53B2F003B03BB /* Directory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BAB2423979B00786299 /* Directory.swift */; }; D2A7841129A53B2F003B03BB /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BAC2423979B00786299 /* File.swift */; }; D2A7841229A53B2F003B03BB /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BAC2423979B00786299 /* File.swift */; }; - D2ADE2E52A52EA5D001A0FFB /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E42A52EA5D001A0FFB /* WebViewTracking.swift */; }; - D2ADE2E82A52ECB4001A0FFB /* DDScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ADE2E72A52ECB4001A0FFB /* DDScriptMessageHandler.swift */; }; D2B249942A4598FE00DD4F9F /* LoggerProtocol+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B249932A4598FE00DD4F9F /* LoggerProtocol+Internal.swift */; }; D2B249952A4598FE00DD4F9F /* LoggerProtocol+Internal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B249932A4598FE00DD4F9F /* LoggerProtocol+Internal.swift */; }; D2B249972A45E10500DD4F9F /* LoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B249962A45E10500DD4F9F /* LoggerTests.swift */; }; @@ -1243,6 +1265,27 @@ remoteGlobalIDString = D23039A4298D513C001A1FA3; remoteInfo = "DatadogInternal iOS"; }; + 3C41694329FBF7EE0042B9D2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 61133B79242393DE00786299 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2DA2355298D57AA00C6C7E6; + remoteInfo = "DatadogInternal tvOS"; + }; + 3C41694529FBF7F50042B9D2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 61133B79242393DE00786299 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2579571298ABB83008A1BE5; + remoteInfo = "TestUtilities tvOS"; + }; + 3C41694929FBF8CC0042B9D2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 61133B79242393DE00786299 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2DA2355298D57AA00C6C7E6; + remoteInfo = "DatadogInternal tvOS"; + }; 3C4D5FEE2A0115C600F1FF78 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 61133B79242393DE00786299 /* Project object */; @@ -1271,6 +1314,13 @@ remoteGlobalIDString = 3CE119FD29F7BE0000202522; remoteInfo = "DatadogWebViewTracking iOS"; }; + 3CE11A2929F7BE1E00202522 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 61133B79242393DE00786299 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3CE11A1F29F7BE1800202522; + remoteInfo = "DatadogWebViewTracking tvOS"; + }; 61133C722423993200786299 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 61133B79242393DE00786299 /* Project object */; @@ -1632,13 +1682,23 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 3C85D41429F7C59C00AFF894 /* MessageEmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageEmitter.swift; sourceTree = ""; }; - 3C85D41529F7C59C00AFF894 /* WebViewMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewMessage.swift; sourceTree = ""; }; - 3C85D41729F7C5BE00AFF894 /* MessageEmitterCoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageEmitterCoreTests.swift; sourceTree = ""; }; - 3C85D41829F7C5BE00AFF894 /* WebViewTrackingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewTrackingTests.swift; sourceTree = ""; }; + 3C0D5DD62A543B3B00446CF9 /* Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = ""; }; + 3C0D5DDC2A543D5D00446CF9 /* EventGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventGenerator.swift; sourceTree = ""; }; + 3C0D5DDF2A543DAE00446CF9 /* EventGeneratorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventGeneratorTests.swift; sourceTree = ""; }; + 3C0D5DE62A543E9700446CF9 /* RUMViewEventsFilterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RUMViewEventsFilterTests.swift; sourceTree = ""; }; + 3C0D5DEB2A54405A00446CF9 /* RUMViewEventsFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewEventsFilter.swift; sourceTree = ""; }; + 3C0D5DEE2A5442A900446CF9 /* EventMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventMocks.swift; sourceTree = ""; }; + 3C0D5DF42A5443B100446CF9 /* DataFormatTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataFormatTests.swift; sourceTree = ""; }; + 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewTracking.swift; sourceTree = ""; }; + 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewTrackingMessage.swift; sourceTree = ""; }; + 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WKUserContentController+Datadog.swift"; sourceTree = ""; }; + 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewTrackingCoreTests.swift; sourceTree = ""; }; + 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "WKUserContentController+DatadogTests.swift"; sourceTree = ""; }; 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HostsSanitizerMock.swift; sourceTree = ""; }; 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogWebViewTracking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DatadogWebViewTrackingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogWebViewTracking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3CE11A2729F7BE1B00202522 /* DatadogWebViewTrackingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DatadogWebViewTrackingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49274903288048AA00ECD49B /* InternalTelemetryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InternalTelemetryTests.swift; sourceTree = ""; }; 49274908288048F400ECD49B /* RUMInternalProxyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RUMInternalProxyTests.swift; sourceTree = ""; }; 61020C292757AD91005EEAEA /* BackgroundLocationMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundLocationMonitor.swift; sourceTree = ""; }; @@ -2206,8 +2266,6 @@ D2A38DDA29C37E1B007C6900 /* TracingURLSessionHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingURLSessionHandlerTests.swift; sourceTree = ""; }; D2A7840129A534F9003B03BB /* DatadogLogsTests tvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "DatadogLogsTests tvOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D2A7840229A536AD003B03BB /* PrintFunctionMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrintFunctionMock.swift; sourceTree = ""; }; - D2ADE2E42A52EA5D001A0FFB /* WebViewTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewTracking.swift; sourceTree = ""; }; - D2ADE2E72A52ECB4001A0FFB /* DDScriptMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDScriptMessageHandler.swift; sourceTree = ""; }; D2B249932A4598FE00DD4F9F /* LoggerProtocol+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoggerProtocol+Internal.swift"; sourceTree = ""; }; D2B249962A45E10500DD4F9F /* LoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggerTests.swift; sourceTree = ""; }; D2B3F0432823EE8300C2B5EE /* DataBlockTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBlockTests.swift; sourceTree = ""; }; @@ -2294,6 +2352,23 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 3CE11A1D29F7BE1800202522 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3C41694729FBF8CC0042B9D2 /* DatadogInternal.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CE11A2429F7BE1B00202522 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3C85D42929F7C6FD00AFF894 /* TestUtilities.framework in Frameworks */, + 3CE11A2829F7BE1E00202522 /* DatadogWebViewTracking.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 61133B88242393DE00786299 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2456,10 +2531,12 @@ buildActionMask = 2147483647; files = ( 61A2CC342A44A6030000FF25 /* DatadogRUM.framework in Frameworks */, + 3CE11A3729F7BE6B00202522 /* DatadogWebViewTracking.framework in Frameworks */, D25CFA9D29C4FC6E00E3A43D /* DatadogTrace.framework in Frameworks */, 9E5BD8062819742C00CB568E /* SwiftUI.framework in Frameworks */, D240687027CF971C00C04F44 /* CrashReporter.xcframework in Frameworks */, D240687127CF971C00C04F44 /* DatadogCore.framework in Frameworks */, + 3CE11A3729F7BE6B00202522 /* DatadogWebViewTracking.framework in Frameworks */, D240687227CF971C00C04F44 /* DatadogCrashReporting.framework in Frameworks */, D24C9C4629A7A520002057CF /* DatadogLogs.framework in Frameworks */, D240687327CF971C00C04F44 /* DatadogObjc.framework in Frameworks */, @@ -2627,10 +2704,9 @@ 3CE11A3B29F7BEE700202522 /* DatadogWebViewTracking */ = { isa = PBXGroup; children = ( - D2ADE2E42A52EA5D001A0FFB /* WebViewTracking.swift */, - 3C85D41429F7C59C00AFF894 /* MessageEmitter.swift */, - 3C85D41529F7C59C00AFF894 /* WebViewMessage.swift */, - D2ADE2E72A52ECB4001A0FFB /* DDScriptMessageHandler.swift */, + 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */, + 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */, + 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */, ); name = DatadogWebViewTracking; path = ../DatadogWebViewTracking/Sources; @@ -2639,8 +2715,8 @@ 3CE11A3C29F7BEF300202522 /* DatadogWebViewTrackingTests */ = { isa = PBXGroup; children = ( - 3C85D41829F7C5BE00AFF894 /* WebViewTrackingTests.swift */, - 3C85D41729F7C5BE00AFF894 /* MessageEmitterCoreTests.swift */, + 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */, + 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */, ); name = DatadogWebViewTrackingTests; path = ../DatadogWebViewTracking/Tests; @@ -2742,6 +2818,8 @@ D23F8ECD29DDCD38001CFAE8 /* DatadogRUMTests tvOS.xctest */, 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */, 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */, + 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */, + 3CE11A2729F7BE1B00202522 /* DatadogWebViewTrackingTests.xctest */, ); name = Products; sourceTree = ""; @@ -2803,6 +2881,7 @@ D29CDD3128211A2200F7DAA5 /* DataBlock.swift */, D2DC4BF527F484AA00E4FB96 /* DataEncryption.swift */, 61133BA92423979B00786299 /* FilesOrchestrator.swift */, + 3C0D5DDC2A543D5D00446CF9 /* EventGenerator.swift */, D2A7841429A53B92003B03BB /* Files */, 613E79412577C08900DFCC17 /* Writing */, 613E79422577C09B00DFCC17 /* Reading */, @@ -2986,6 +3065,7 @@ 61133C272423990D00786299 /* Persistence */ = { isa = PBXGroup; children = ( + 3C0D5DDF2A543DAE00446CF9 /* EventGeneratorTests.swift */, 61133C2A2423990D00786299 /* FilesOrchestratorTests.swift */, D2B3F0432823EE8300C2B5EE /* DataBlockTests.swift */, 619E16D42577C11B00B2516B /* Writing */, @@ -4279,6 +4359,7 @@ D23039D4298D5235001A1FA3 /* DataCompression.swift */, D23039D5298D5235001A1FA3 /* FeatureRequestBuilder.swift */, D2D3199929E98D970004F169 /* DefaultJSONEncoder.swift */, + 3C0D5DD62A543B3B00446CF9 /* Event.swift */, ); path = Upload; sourceTree = ""; @@ -4402,6 +4483,7 @@ D2EBEE4729BA17C400B15732 /* NetworkInstrumentationMocks.swift */, 61C3646F243B5C8300C4D4E6 /* ServerMock.swift */, D2160CF629C0EE2B00FAA9A5 /* UploadMocks.swift */, + 3C0D5DEE2A5442A900446CF9 /* EventMocks.swift */, ); path = Mocks; sourceTree = ""; @@ -4466,6 +4548,7 @@ D25FF2E729CC6B680063802D /* RUMFeature.swift */, D25FF2ED29CC73240063802D /* RequestBuilder.swift */, D25FF2F329CC88060063802D /* RUMBaggageKeys.swift */, + 3C0D5DEB2A54405A00446CF9 /* RUMViewEventsFilter.swift */, ); path = Feature; sourceTree = ""; @@ -4532,6 +4615,7 @@ D29A9F3F29DD84AB005C54A4 /* DatadogRUMTests */ = { isa = PBXGroup; children = ( + 3C0D5DE62A543E9700446CF9 /* RUMViewEventsFilterTests.swift */, 61C713AC2A3B793E00FA735A /* RUMMonitorProtocolTests.swift */, 61C713B52A3C600400FA735A /* RUMMonitorProtocol+ConvenienceTests.swift */, 61C713B22A3C3A0B00FA735A /* RUMMonitorProtocol+InternalTests.swift */, @@ -4774,6 +4858,7 @@ D2F44FBA299AA2310074B0D9 /* Upload */ = { isa = PBXGroup; children = ( + 3C0D5DF42A5443B100446CF9 /* DataFormatTests.swift */, D213532F270CA722000315AD /* DataCompressionTests.swift */, ); path = Upload; @@ -4789,6 +4874,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 3CE11A1B29F7BE1800202522 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 61133B7D242393DE00786299 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -4957,6 +5049,45 @@ productReference = 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 3CE11A1F29F7BE1800202522 /* DatadogWebViewTracking tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3CE11A2F29F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTracking tvOS" */; + buildPhases = ( + 3CE11A1B29F7BE1800202522 /* Headers */, + 3CE11A1C29F7BE1800202522 /* Sources */, + 3CE11A1D29F7BE1800202522 /* Frameworks */, + 3CE11A1E29F7BE1800202522 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 3C41694A29FBF8CC0042B9D2 /* PBXTargetDependency */, + ); + name = "DatadogWebViewTracking tvOS"; + productName = "DatadogWebViewTracking tvOS"; + productReference = 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */; + productType = "com.apple.product-type.framework"; + }; + 3CE11A2629F7BE1B00202522 /* DatadogWebViewTrackingTests tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3CE11A3329F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTrackingTests tvOS" */; + buildPhases = ( + 3CE11A2329F7BE1B00202522 /* Sources */, + 3CE11A2429F7BE1B00202522 /* Frameworks */, + 3CE11A2529F7BE1B00202522 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 3C41694629FBF7F50042B9D2 /* PBXTargetDependency */, + 3C41694429FBF7EE0042B9D2 /* PBXTargetDependency */, + 3CE11A2A29F7BE1E00202522 /* PBXTargetDependency */, + ); + name = "DatadogWebViewTrackingTests tvOS"; + productName = "DatadogWebViewTracking tvOSTests"; + productReference = 3CE11A2729F7BE1B00202522 /* DatadogWebViewTrackingTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 61133B81242393DE00786299 /* DatadogCore iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 61133B96242393DE00786299 /* Build configuration list for PBXNativeTarget "DatadogCore iOS" */; @@ -5633,6 +5764,13 @@ CreatedOnToolsVersion = 14.0.1; LastSwiftMigration = 1400; }; + 3CE11A1F29F7BE1800202522 = { + CreatedOnToolsVersion = 14.0.1; + }; + 3CE11A2629F7BE1B00202522 = { + CreatedOnToolsVersion = 14.0.1; + LastSwiftMigration = 1400; + }; 61133B81242393DE00786299 = { CreatedOnToolsVersion = 11.3.1; }; @@ -5753,6 +5891,8 @@ D2579571298ABB83008A1BE5 /* TestUtilities tvOS */, 3CE119FD29F7BE0000202522 /* DatadogWebViewTracking iOS */, 3CE11A0429F7BE0300202522 /* DatadogWebViewTrackingTests iOS */, + 3CE11A1F29F7BE1800202522 /* DatadogWebViewTracking tvOS */, + 3CE11A2629F7BE1B00202522 /* DatadogWebViewTrackingTests tvOS */, ); }; /* End PBXProject section */ @@ -5772,6 +5912,20 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 3CE11A1E29F7BE1800202522 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CE11A2529F7BE1B00202522 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 61133B80242393DE00786299 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -6225,10 +6379,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D2ADE2E82A52ECB4001A0FFB /* DDScriptMessageHandler.swift in Sources */, - D2ADE2E52A52EA5D001A0FFB /* WebViewTracking.swift in Sources */, - 3C85D42129F7C5C900AFF894 /* MessageEmitter.swift in Sources */, - 3C85D41F29F7C5C900AFF894 /* WebViewMessage.swift in Sources */, + 3C85D42129F7C5C900AFF894 /* WebViewTracking.swift in Sources */, + 3C85D41F29F7C5C900AFF894 /* WebViewTrackingMessage.swift in Sources */, + 3C85D42029F7C5C900AFF894 /* WKUserContentController+Datadog.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6236,8 +6389,27 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3C85D41B29F7C5C300AFF894 /* WebViewTrackingTests.swift in Sources */, - 3C85D41C29F7C5C400AFF894 /* MessageEmitterCoreTests.swift in Sources */, + 3C85D41B29F7C5C300AFF894 /* WKUserContentController+DatadogTests.swift in Sources */, + 3C85D41C29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CE11A1C29F7BE1800202522 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3C85D42429F7C5CA00AFF894 /* WebViewTracking.swift in Sources */, + 3C85D42229F7C5CA00AFF894 /* WebViewTrackingMessage.swift in Sources */, + 3C85D42329F7C5CA00AFF894 /* WKUserContentController+Datadog.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3CE11A2329F7BE1B00202522 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3C85D41D29F7C5C400AFF894 /* WKUserContentController+DatadogTests.swift in Sources */, + 3C85D41E29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6253,6 +6425,7 @@ 61D3E0D5277B23F1008BE766 /* KronosNTPPacket.swift in Sources */, 61133BCF2423979B00786299 /* FileWriter.swift in Sources */, 6179FFD3254ADB1700556A0B /* ObjcAppLaunchHandler.m in Sources */, + 3C0D5DE42A543E3400446CF9 /* EventGenerator.swift in Sources */, D2303A0A298D5412001A1FA3 /* AsyncWriter.swift in Sources */, D29CDD3228211A2200F7DAA5 /* DataBlock.swift in Sources */, D2553829288F0B2400727FAD /* LowPowerModePublisher.swift in Sources */, @@ -6333,6 +6506,7 @@ D22743DC29DEB8B4001A7EF9 /* VitalRefreshRateReaderTests.swift in Sources */, 617B954224BF4E7600E6F443 /* RUMMonitorConfigurationTests.swift in Sources */, 61F9CABA2513A7F5000A5E61 /* RUMSessionMatcher.swift in Sources */, + 3C0D5DE22A543DC400446CF9 /* EventGeneratorTests.swift in Sources */, 61C3638324361BE200C4D4E6 /* DatadogPrivateMocks.swift in Sources */, D26C49AF2886DC7B00802B2D /* ApplicationStatePublisherTests.swift in Sources */, 6147989C2A459E2B0095CB02 /* DDTrace+apiTests.m in Sources */, @@ -6711,6 +6885,7 @@ D23039FD298D5236001A1FA3 /* DataCompression.swift in Sources */, D23039F0298D5236001A1FA3 /* AnyEncoder.swift in Sources */, D2A783D429A5309F003B03BB /* SwiftExtensions.swift in Sources */, + 3C0D5DD72A543B3B00446CF9 /* Event.swift in Sources */, D22F06D929DAFD500026CC3C /* TimeInterval+Convenience.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -6758,6 +6933,7 @@ D23F8E7429DDCD28001CFAE8 /* RUMCommandSubscriber.swift in Sources */, D23F8E7529DDCD28001CFAE8 /* RUMUserActionScope.swift in Sources */, 61C713A42A3B78F900FA735A /* RUMMonitorProtocol.swift in Sources */, + 3C0D5DED2A54405A00446CF9 /* RUMViewEventsFilter.swift in Sources */, D23F8E7629DDCD28001CFAE8 /* RUMConnectivityInfoProvider.swift in Sources */, D23F8E7729DDCD28001CFAE8 /* UIKitRUMViewsPredicate.swift in Sources */, 61C713A62A3B78F900FA735A /* RUMMonitorProtocol+Internal.swift in Sources */, @@ -6825,6 +7001,7 @@ D23F8EBF29DDCD38001CFAE8 /* URLSessionRUMResourcesHandlerTests.swift in Sources */, D23F8EC029DDCD38001CFAE8 /* RUMEventSanitizerTests.swift in Sources */, D23F8EC129DDCD38001CFAE8 /* RUMEventsMapperTests.swift in Sources */, + 3C0D5DEA2A543EA300446CF9 /* RUMViewEventsFilterTests.swift in Sources */, D23F8EC429DDCD38001CFAE8 /* RUMCommandTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -6854,6 +7031,7 @@ D24C9C6929A7CE06002057CF /* DDErrorMocks.swift in Sources */, D2579558298ABB04008A1BE5 /* Encoding.swift in Sources */, D2EBEE4829BA17C400B15732 /* NetworkInstrumentationMocks.swift in Sources */, + 3C0D5DEF2A5442A900446CF9 /* EventMocks.swift in Sources */, D24C9C5529A7C5F3002057CF /* RelativeDateProvider.swift in Sources */, D2579559298ABB04008A1BE5 /* DDAssert.swift in Sources */, D2579552298ABB04008A1BE5 /* FileWriterMock.swift in Sources */, @@ -6887,6 +7065,7 @@ D24C9C6A29A7CE06002057CF /* DDErrorMocks.swift in Sources */, D257957B298ABB83008A1BE5 /* Encoding.swift in Sources */, D2EBEE4929BA17C400B15732 /* NetworkInstrumentationMocks.swift in Sources */, + 3C0D5DF02A5442A900446CF9 /* EventMocks.swift in Sources */, D24C9C5629A7C5F3002057CF /* RelativeDateProvider.swift in Sources */, D257957C298ABB83008A1BE5 /* DDAssert.swift in Sources */, D257957D298ABB83008A1BE5 /* FileWriterMock.swift in Sources */, @@ -7007,6 +7186,7 @@ D29A9F5D29DD85BB005C54A4 /* RUMCommandSubscriber.swift in Sources */, D29A9F6529DD85BB005C54A4 /* RUMUserActionScope.swift in Sources */, 61C713A32A3B78F900FA735A /* RUMMonitorProtocol.swift in Sources */, + 3C0D5DEC2A54405A00446CF9 /* RUMViewEventsFilter.swift in Sources */, D29A9F5829DD85BB005C54A4 /* RUMConnectivityInfoProvider.swift in Sources */, D29A9F5E29DD85BB005C54A4 /* UIKitRUMViewsPredicate.swift in Sources */, 61C713A52A3B78F900FA735A /* RUMMonitorProtocol+Internal.swift in Sources */, @@ -7074,6 +7254,7 @@ D29A9F9A29DDB483005C54A4 /* URLSessionRUMResourcesHandlerTests.swift in Sources */, D29A9FA229DDB483005C54A4 /* RUMEventSanitizerTests.swift in Sources */, D29A9FB929DDB483005C54A4 /* RUMEventsMapperTests.swift in Sources */, + 3C0D5DE92A543EA200446CF9 /* RUMViewEventsFilterTests.swift in Sources */, D29A9FA729DDB483005C54A4 /* RUMCommandTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -7162,6 +7343,7 @@ D2CB6E2927C50EAE00A62B57 /* KronosInternetAddress.swift in Sources */, D2CB6E2C27C50EAE00A62B57 /* KronosNTPPacket.swift in Sources */, D2CB6E3127C50EAE00A62B57 /* FileWriter.swift in Sources */, + 3C0D5DE52A543E3500446CF9 /* EventGenerator.swift in Sources */, D2EFA869286DA85700F1FAA6 /* DatadogContextProvider.swift in Sources */, D2B3F04E282A85FD00C2B5EE /* DatadogCore.swift in Sources */, D2303A0B298D5412001A1FA3 /* AsyncWriter.swift in Sources */, @@ -7234,6 +7416,7 @@ D2EFA876286E011900F1FAA6 /* DatadogContextProviderTests.swift in Sources */, 614B78F2296D7B63009C6B92 /* LowPowerModePublisherTests.swift in Sources */, D2CB6EEE27C520D400A62B57 /* DDErrorTests.swift in Sources */, + 3C0D5DE32A543DC900446CF9 /* EventGeneratorTests.swift in Sources */, D25CFAA229C8644E00E3A43D /* Casting+Tracing.swift in Sources */, D2CB6EF227C520D400A62B57 /* KronosTimeStorageTests.swift in Sources */, D2CB6EF427C520D400A62B57 /* FileWriterTests.swift in Sources */, @@ -7478,6 +7661,7 @@ D2DA237D298D57AA00C6C7E6 /* DataCompression.swift in Sources */, D2DA237E298D57AA00C6C7E6 /* AnyEncoder.swift in Sources */, D2A783D529A530A0003B03BB /* SwiftExtensions.swift in Sources */, + 3C0D5DD82A543B3B00446CF9 /* Event.swift in Sources */, D22F06DA29DAFD500026CC3C /* TimeInterval+Convenience.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -7492,6 +7676,7 @@ D21AE6BC29E5EDAF0064BF29 /* TelemetryTests.swift in Sources */, D2DA23A3298D58F400C6C7E6 /* AnyEncodableTests.swift in Sources */, D263BCB429DB014900FA0E21 /* FixedWidthInteger+ConvenienceTests.swift in Sources */, + 3C0D5DF52A5443B100446CF9 /* DataFormatTests.swift in Sources */, D2EBEE4429BA168200B15732 /* TraceIDTests.swift in Sources */, D2EBEE4329BA168200B15732 /* TraceIDGeneratorTests.swift in Sources */, D2DA23A7298D58F400C6C7E6 /* AppStateHistoryTests.swift in Sources */, @@ -7528,6 +7713,7 @@ D21AE6BD29E5EDAF0064BF29 /* TelemetryTests.swift in Sources */, D2DA23B1298D59DC00C6C7E6 /* AnyEncodableTests.swift in Sources */, D263BCB529DB014900FA0E21 /* FixedWidthInteger+ConvenienceTests.swift in Sources */, + 3C0D5DF62A5443B100446CF9 /* DataFormatTests.swift in Sources */, D2EBEE4629BA168400B15732 /* TraceIDTests.swift in Sources */, D2EBEE4529BA168400B15732 /* TraceIDGeneratorTests.swift in Sources */, D2DA23B2298D59DC00C6C7E6 /* AppStateHistoryTests.swift in Sources */, @@ -7572,6 +7758,21 @@ target = D23039A4298D513C001A1FA3 /* DatadogInternal iOS */; targetProxy = 3C41694129FBF6100042B9D2 /* PBXContainerItemProxy */; }; + 3C41694429FBF7EE0042B9D2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D2DA2355298D57AA00C6C7E6 /* DatadogInternal tvOS */; + targetProxy = 3C41694329FBF7EE0042B9D2 /* PBXContainerItemProxy */; + }; + 3C41694629FBF7F50042B9D2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D2579571298ABB83008A1BE5 /* TestUtilities tvOS */; + targetProxy = 3C41694529FBF7F50042B9D2 /* PBXContainerItemProxy */; + }; + 3C41694A29FBF8CC0042B9D2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D2DA2355298D57AA00C6C7E6 /* DatadogInternal tvOS */; + targetProxy = 3C41694929FBF8CC0042B9D2 /* PBXContainerItemProxy */; + }; 3C4D5FEF2A0115C600F1FF78 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D2C1A53329C4F2DF00946C31 /* DatadogTrace tvOS */; @@ -7592,6 +7793,11 @@ target = 3CE119FD29F7BE0000202522 /* DatadogWebViewTracking iOS */; targetProxy = 3CE11A0729F7BE0500202522 /* PBXContainerItemProxy */; }; + 3CE11A2A29F7BE1E00202522 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 3CE11A1F29F7BE1800202522 /* DatadogWebViewTracking tvOS */; + targetProxy = 3CE11A2929F7BE1E00202522 /* PBXContainerItemProxy */; + }; 61133C732423993200786299 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 61133B81242393DE00786299 /* DatadogCore iOS */; @@ -8008,6 +8214,208 @@ }; name = Integration; }; + 3CE11A3029F7BE2100202522 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 61569894256D0E9A00C6AADA /* Base.xcconfig */; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Datadog. All rights reserved."; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTracking; + PRODUCT_NAME = DatadogWebViewTracking; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + }; + name = Debug; + }; + 3CE11A3129F7BE2100202522 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 61569894256D0E9A00C6AADA /* Base.xcconfig */; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Datadog. All rights reserved."; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTracking; + PRODUCT_NAME = DatadogWebViewTracking; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + }; + name = Release; + }; + 3CE11A3229F7BE2100202522 /* Integration */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 61569894256D0E9A00C6AADA /* Base.xcconfig */; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Datadog. All rights reserved."; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTracking; + PRODUCT_NAME = DatadogWebViewTracking; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + }; + name = Integration; + }; + 3CE11A3429F7BE2100202522 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTrackingTests; + PRODUCT_NAME = DatadogWebViewTrackingTests; + SDKROOT = appletvos; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + }; + name = Debug; + }; + 3CE11A3529F7BE2100202522 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTrackingTests; + PRODUCT_NAME = DatadogWebViewTrackingTests; + SDKROOT = appletvos; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + }; + name = Release; + }; + 3CE11A3629F7BE2100202522 /* Integration */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTrackingTests; + PRODUCT_NAME = DatadogWebViewTrackingTests; + SDKROOT = appletvos; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 3; + }; + name = Integration; + }; 61133B94242393DE00786299 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -11103,6 +11511,26 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 3CE11A2F29F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTracking tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3CE11A3029F7BE2100202522 /* Debug */, + 3CE11A3129F7BE2100202522 /* Release */, + 3CE11A3229F7BE2100202522 /* Integration */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3CE11A3329F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTrackingTests tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3CE11A3429F7BE2100202522 /* Debug */, + 3CE11A3529F7BE2100202522 /* Release */, + 3CE11A3629F7BE2100202522 /* Integration */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 61133B7C242393DE00786299 /* Build configuration list for PBXProject "Datadog" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/DatadogCore/Sources/Core/Storage/DataBlock.swift b/DatadogCore/Sources/Core/Storage/DataBlock.swift index edbf0fb1d1..9f8d72156f 100644 --- a/DatadogCore/Sources/Core/Storage/DataBlock.swift +++ b/DatadogCore/Sources/Core/Storage/DataBlock.swift @@ -5,6 +5,7 @@ */ import Foundation +import DatadogInternal /// Block size binary type internal typealias BlockSize = UInt32 diff --git a/DatadogCore/Sources/Core/Storage/EventGenerator.swift b/DatadogCore/Sources/Core/Storage/EventGenerator.swift new file mode 100644 index 0000000000..17a8c08a43 --- /dev/null +++ b/DatadogCore/Sources/Core/Storage/EventGenerator.swift @@ -0,0 +1,60 @@ +/* + * 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 2019-Present Datadog, Inc. + */ + +import Foundation +import DatadogInternal + +/// Event generator that generates events from the given data blocks. +internal struct EventGenerator: Sequence, IteratorProtocol { + private let dataBlocks: [DataBlock] + private var index: Int + + init(dataBlocks: [DataBlock], index: Int = 0) { + self.dataBlocks = dataBlocks + self.index = index + } + + /// Returns the next event. + /// + /// Data format + /// ``` + /// [EVENT 1 METADATA] [EVENT 1] [EVENT 2 METADATA] [EVENT 2] [EVENT 3] + /// ``` + /// + /// - Returns: The next event or `nil` if there are no more events. + /// - Note: a `DataBlock` with `.event` type marks the beginning of the event. + /// It is either followed by another `DataBlock` with `.event` type or + /// by a `DataBlock` with `.metadata` type. + mutating func next() -> Event? { + guard index < dataBlocks.count else { + return nil + } + + var metadata: DataBlock? = nil + // If the next block is an event metadata, read it. + if dataBlocks[index].type == .eventMetadata { + metadata = dataBlocks[index] + index += 1 + } + + // If this is the last block, return nil. + // there cannot be a metadata block without an event block. + guard index < dataBlocks.count else { + return nil + } + + // If the next block is an event, read it. + guard dataBlocks[index].type == .event else { + // this is safeguard against corrupted data. + // if there was a metadata block, it will be skipped. + return next() + } + let event = dataBlocks[index] + index += 1 + + return Event(data: event.data, metadata: metadata?.data) + } +} diff --git a/DatadogCore/Sources/Core/Storage/Reading/Reader.swift b/DatadogCore/Sources/Core/Storage/Reading/Reader.swift index ef22ee91a9..ecb629d89e 100644 --- a/DatadogCore/Sources/Core/Storage/Reading/Reader.swift +++ b/DatadogCore/Sources/Core/Storage/Reading/Reader.swift @@ -5,6 +5,7 @@ */ import Foundation +import DatadogInternal internal struct Batch { /// Data blocks in the batch. diff --git a/DatadogCore/Sources/Core/Storage/Writing/AsyncWriter.swift b/DatadogCore/Sources/Core/Storage/Writing/AsyncWriter.swift index f5fb1d0050..8357d490f9 100644 --- a/DatadogCore/Sources/Core/Storage/Writing/AsyncWriter.swift +++ b/DatadogCore/Sources/Core/Storage/Writing/AsyncWriter.swift @@ -7,24 +7,6 @@ import Foundation import DatadogInternal -/// A type, writing data. -public protocol Writer { - /// Encodes given encodable value and metadata, and writes to the destination. - /// - Parameter value: Encodable value to write. - /// - Parameter metadata: Encodable metadata to write. - func write(value: T, metadata: M?) -} - -extension Writer { - /// Encodes given encodable value and writes to the destination. - /// Uses `write(value:metadata:)` with `nil` metadata. - /// - Parameter value: Encodable value to write. - public func write(value: T) { - let metadata: Data? = nil - write(value: value, metadata: metadata) - } -} - /// Writer performing writes asynchronously on a given queue. internal struct AsyncWriter: Writer { private let writer: Writer @@ -41,5 +23,6 @@ internal struct AsyncWriter: Writer { } internal struct NOPWriter: Writer { - func write(value: T, metadata: M?) { } + func write(value: T, metadata: M?) { + } } diff --git a/DatadogCore/Tests/Datadog/Core/Persistence/EventGeneratorTests.swift b/DatadogCore/Tests/Datadog/Core/Persistence/EventGeneratorTests.swift index 451150543a..7b5971e1fb 100644 --- a/DatadogCore/Tests/Datadog/Core/Persistence/EventGeneratorTests.swift +++ b/DatadogCore/Tests/Datadog/Core/Persistence/EventGeneratorTests.swift @@ -5,7 +5,7 @@ */ import XCTest -@testable import Datadog +@testable import DatadogCore final class EventGeneratorTests: XCTestCase { func testEmpty() throws { diff --git a/DatadogCore/Tests/Datadog/Core/Persistence/Reading/FileReaderTests.swift b/DatadogCore/Tests/Datadog/Core/Persistence/Reading/FileReaderTests.swift index 6d8485c398..b10033f1a1 100644 --- a/DatadogCore/Tests/Datadog/Core/Persistence/Reading/FileReaderTests.swift +++ b/DatadogCore/Tests/Datadog/Core/Persistence/Reading/FileReaderTests.swift @@ -30,7 +30,6 @@ class FileReaderTests: XCTestCase { dateProvider: SystemDateProvider() ) ) - let dataBlocks = [ DataBlock(type: .eventMetadata, data: "EFGH".utf8Data), DataBlock(type: .event, data: "ABCD".utf8Data) @@ -38,7 +37,6 @@ class FileReaderTests: XCTestCase { let data = try dataBlocks .map { try $0.serialize() } .reduce(.init(), +) - _ = try directory .createFile(named: Date.mockAny().toFileName) .append(data: data) @@ -103,7 +101,6 @@ class FileReaderTests: XCTestCase { ) let file1 = try directory.createFile(named: dateProvider.now.toFileName) try file1.append(data: DataBlock(type: .eventMetadata, data: "2".utf8Data).serialize()) - try file1.append(data: DataBlock(type: .event, data: "1".utf8Data).serialize()) let file2 = try directory.createFile(named: dateProvider.now.toFileName) diff --git a/DatadogCore/Tests/Datadog/Core/Persistence/Writing/FileWriterTests.swift b/DatadogCore/Tests/Datadog/Core/Persistence/Writing/FileWriterTests.swift index a95f13fc76..775e31bd11 100644 --- a/DatadogCore/Tests/Datadog/Core/Persistence/Writing/FileWriterTests.swift +++ b/DatadogCore/Tests/Datadog/Core/Persistence/Writing/FileWriterTests.swift @@ -26,7 +26,7 @@ class FileWriterTests: XCTestCase { func testItWritesDataWithMetadataToSingleFileInTLVFormat() throws { let writer = FileWriter( orchestrator: FilesOrchestrator( - directory: temporaryDirectory, + directory: directory, performance: PerformancePreset.mockAny(), dateProvider: SystemDateProvider() ), @@ -38,8 +38,8 @@ class FileWriterTests: XCTestCase { writer.write(value: ["key2": "value2"]) // skipped metadata here writer.write(value: ["key3": "value3"], metadata: ["meta3": "metaValue3"]) - XCTAssertEqual(try temporaryDirectory.files().count, 1) - let stream = try temporaryDirectory.files()[0].stream() + XCTAssertEqual(try directory.files().count, 1) + let stream = try directory.files()[0].stream() let reader = DataBlockReader(input: stream) var block = try reader.next() @@ -62,7 +62,7 @@ class FileWriterTests: XCTestCase { func testItWritesEncryptedDataWithMetadataToSingleFileInTLVFormat() throws { let writer = FileWriter( orchestrator: FilesOrchestrator( - directory: temporaryDirectory, + directory: directory, performance: PerformancePreset.mockAny(), dateProvider: SystemDateProvider() ), @@ -78,8 +78,8 @@ class FileWriterTests: XCTestCase { writer.write(value: ["key2": "value2"]) // skipped metadata here writer.write(value: ["key3": "value3"], metadata: ["meta3": "metaValue3"]) - XCTAssertEqual(try temporaryDirectory.files().count, 1) - let stream = try temporaryDirectory.files()[0].stream() + XCTAssertEqual(try directory.files().count, 1) + let stream = try directory.files()[0].stream() let reader = DataBlockReader(input: stream) var block = try reader.next() diff --git a/DatadogCore/Tests/Datadog/Mocks/CoreMocks.swift b/DatadogCore/Tests/Datadog/Mocks/CoreMocks.swift index a3783843fd..037f195c7c 100644 --- a/DatadogCore/Tests/Datadog/Mocks/CoreMocks.swift +++ b/DatadogCore/Tests/Datadog/Mocks/CoreMocks.swift @@ -280,7 +280,7 @@ struct DataUploaderMock: DataUploaderType { var onUpload: (() throws -> Void)? = nil - func upload(events: [Data], context: DatadogContext) throws -> DataUploadStatus { + func upload(events: [Event], context: DatadogContext) throws -> DataUploadStatus { try onUpload?() return uploadStatus } diff --git a/DatadogInternal/Sources/Storage/Writer.swift b/DatadogInternal/Sources/Storage/Writer.swift index 5ee32f16d1..0bb8e245ad 100644 --- a/DatadogInternal/Sources/Storage/Writer.swift +++ b/DatadogInternal/Sources/Storage/Writer.swift @@ -8,11 +8,18 @@ import Foundation /// A type, writing data. public protocol Writer { - func write(value: T) + /// Encodes given encodable value and metadata, and writes to the destination. + /// - Parameter value: Encodable value to write. + /// - Parameter metadata: Encodable metadata to write. + func write(value: T, metadata: M?) } -public struct NOPWriter: Writer { - public init() { } - - public func write(value: T) where T: Encodable {} +extension Writer { + /// Encodes given encodable value and writes to the destination. + /// Uses `write(value:metadata:)` with `nil` metadata. + /// - Parameter value: Encodable value to write. + public func write(value: T) { + let metadata: Data? = nil + write(value: value, metadata: metadata) + } } diff --git a/DatadogInternal/Sources/Upload/Event.swift b/DatadogInternal/Sources/Upload/Event.swift index c36ed24fc6..6f05f8dc9a 100644 --- a/DatadogInternal/Sources/Upload/Event.swift +++ b/DatadogInternal/Sources/Upload/Event.swift @@ -22,55 +22,3 @@ public struct Event: Equatable { self.metadata = metadata } } - -/// Event generator that generates events from the given data blocks. -internal struct EventGenerator: Sequence, IteratorProtocol { - private let dataBlocks: [DataBlock] - private var index: Int - - init(dataBlocks: [DataBlock], index: Int = 0) { - self.dataBlocks = dataBlocks - self.index = index - } - - /// Returns the next event. - /// - /// Data format - /// ``` - /// [EVENT 1 METADATA] [EVENT 1] [EVENT 2 METADATA] [EVENT 2] [EVENT 3] - /// ``` - /// - /// - Returns: The next event or `nil` if there are no more events. - /// - Note: a `DataBlock` with `.event` type marks the beginning of the event. - /// It is either followed by another `DataBlock` with `.event` type or - /// by a `DataBlock` with `.metadata` type. - mutating func next() -> Event? { - guard index < dataBlocks.count else { - return nil - } - - var metadata: DataBlock? = nil - // If the next block is an event metadata, read it. - if dataBlocks[index].type == .eventMetadata { - metadata = dataBlocks[index] - index += 1 - } - - // If this is the last block, return nil. - // there cannot be a metadata block without an event block. - guard index < dataBlocks.count else { - return nil - } - - // If the next block is an event, read it. - guard dataBlocks[index].type == .event else { - // this is safeguard against corrupted data. - // if there was a metadata block, it will be skipped. - return next() - } - let event = dataBlocks[index] - index += 1 - - return Event(data: event.data, metadata: metadata?.data) - } -} diff --git a/DatadogInternal/Tests/Upload/DataFormatTests.swift b/DatadogInternal/Tests/Upload/DataFormatTests.swift new file mode 100644 index 0000000000..5488942b8c --- /dev/null +++ b/DatadogInternal/Tests/Upload/DataFormatTests.swift @@ -0,0 +1,28 @@ +/* + * 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 2019-Present Datadog, Inc. + */ + +import XCTest +@testable import DatadogInternal + +final class DataFormatTests: XCTestCase { + func testFormat() throws { + let format = DataFormat(prefix: "prefix", suffix: "suffix", separator: "\n") + let events = [ + "abc".data(using: .utf8)!, + "def".data(using: .utf8)!, + "ghi".data(using: .utf8)! + ] + let formatted = format.format(events) + let actual = String(data: formatted, encoding: .utf8)! + let expected = + """ + prefixabc + def + ghisuffix + """ + XCTAssertEqual(actual, expected) + } +} diff --git a/DatadogLogs/Sources/Feature/RequestBuilder.swift b/DatadogLogs/Sources/Feature/RequestBuilder.swift index f4966e9f71..a48e758551 100644 --- a/DatadogLogs/Sources/Feature/RequestBuilder.swift +++ b/DatadogLogs/Sources/Feature/RequestBuilder.swift @@ -20,7 +20,7 @@ internal struct RequestBuilder: FeatureRequestBuilder { self.customIntakeURL = customIntakeURL } - func request(for events: [Data], with context: DatadogContext) -> URLRequest { + func request(for events: [Event], with context: DatadogContext) -> URLRequest { let builder = URLRequestBuilder( url: url(with: context), queryItems: [ @@ -40,7 +40,7 @@ internal struct RequestBuilder: FeatureRequestBuilder { ] ) - let data = format.format(events) + let data = format.format(events.map { $0.data }) return builder.uploadRequest(with: data) } diff --git a/DatadogRUM/Sources/Feature/RUMFeature.swift b/DatadogRUM/Sources/Feature/RUMFeature.swift index b375817192..d7c34b5051 100644 --- a/DatadogRUM/Sources/Feature/RUMFeature.swift +++ b/DatadogRUM/Sources/Feature/RUMFeature.swift @@ -75,7 +75,10 @@ internal final class RUMFeature: DatadogRemoteFeature { longTaskThreshold: configuration.longTaskThreshold, dateProvider: configuration.dateProvider ) - self.requestBuilder = RequestBuilder(customIntakeURL: configuration.customEndpoint) + self.requestBuilder = RequestBuilder( + customIntakeURL: configuration.customEndpoint, + eventsFilter: RUMViewEventsFilter() + ) self.messageReceiver = CombinedFeatureMessageReceiver( TelemetryReceiver( dateProvider: configuration.dateProvider, diff --git a/DatadogRUM/Sources/Feature/RUMViewEventsFilter.swift b/DatadogRUM/Sources/Feature/RUMViewEventsFilter.swift new file mode 100644 index 0000000000..de86f6f3ce --- /dev/null +++ b/DatadogRUM/Sources/Feature/RUMViewEventsFilter.swift @@ -0,0 +1,52 @@ +/* + * 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 2019-2020 Datadog, Inc. + */ + +import Foundation +import DatadogInternal + +internal struct RUMViewEventsFilter { + let decoder: JSONDecoder + + init(decoder: JSONDecoder = JSONDecoder()) { + self.decoder = decoder + } + + func filter(events: [Event]) -> [Event] { + var seen = Set() + var skipped: [String: [Int64]] = [:] + + // reversed is O(1) and no copy because it is view on the original array + let filtered = events.reversed().compactMap { event in + guard let metadata = event.metadata else { + // If there is no metadata, we can't filter it. + return event + } + + guard let viewMetadata = try? decoder.decode(RUMViewEvent.Metadata.self, from: metadata) else { + // If we can't decode the metadata, we can't filter it. + return event + } + + guard seen.contains(viewMetadata.id) == false else { + // If we've already seen this view, we can skip this + if skipped[viewMetadata.id] == nil { + skipped[viewMetadata.id] = [] + } + skipped[viewMetadata.id]?.append(viewMetadata.documentVersion) + return nil + } + + seen.insert(viewMetadata.id) + return event + } + + for (id, versions) in skipped { + DD.logger.debug("Skipping RUMViewEvent with id: \(id) and versions: \(versions.reversed().map(String.init).joined(separator: ", "))") + } + + return filtered.reversed() + } +} diff --git a/DatadogRUM/Sources/Feature/RequestBuilder.swift b/DatadogRUM/Sources/Feature/RequestBuilder.swift index edb0f846b6..39ac03de96 100644 --- a/DatadogRUM/Sources/Feature/RequestBuilder.swift +++ b/DatadogRUM/Sources/Feature/RequestBuilder.swift @@ -13,10 +13,13 @@ internal struct RequestBuilder: FeatureRequestBuilder { /// A custom RUM intake. let customIntakeURL: URL? + /// The RUM view events filter from the payload. + let eventsFilter: RUMViewEventsFilter + /// The RUM request body format. let format = DataFormat(prefix: "", suffix: "", separator: "\n") - func request(for events: [Data], with context: DatadogContext) -> URLRequest { + func request(for events: [Event], with context: DatadogContext) -> URLRequest { var tags = [ "service:\(context.service)", "version:\(context.version)", @@ -48,7 +51,8 @@ internal struct RequestBuilder: FeatureRequestBuilder { ] ) - let data = format.format(events) + let filteredEvents = eventsFilter.filter(events: events) + let data = format.format(filteredEvents.map { $0.data }) return builder.uploadRequest(with: data) } diff --git a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMViewScope.swift b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMViewScope.swift index 58793254de..11373212b5 100644 --- a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMViewScope.swift +++ b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMViewScope.swift @@ -90,6 +90,9 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { private let vitalInfoSampler: VitalInfoSampler? + /// Samples view update events, so we can minimize the number of events in payload. + private let viewUpdatesThrottler: RUMViewUpdatesThrottlerType + private var viewPerformanceMetrics: [PerformanceMetric: VitalInfo] = [:] init( @@ -124,6 +127,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { frequency: $0.frequency ) } + self.viewUpdatesThrottler = dependencies.viewUpdatesThrottlerFactory() } // MARK: - RUMContextProvider @@ -391,7 +395,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.hasReplay, + hasReplay: context.srBaggage?.isReplayBeingRecorded, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), @@ -438,12 +442,6 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { dd: .init( browserSdkVersion: nil, documentVersion: version.toInt64, - pageStates: nil, - replayStats: .init( - recordsCount: context.srBaggage?.recordsCountByViewID[viewUUID.toRUMDataFormat], - segmentsCount: nil, - segmentsTotalRawSize: nil - ), session: .init(plan: .plan1) ), application: .init(id: self.context.rumApplicationID), @@ -455,14 +453,12 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { display: nil, featureFlags: .init(featureFlagsInfo: featureFlags), os: .init(context: context), - privacy: nil, service: context.service, session: .init( - hasReplay: context.srBaggage?.hasReplay, + hasReplay: context.srBaggage?.isReplayBeingRecorded, id: self.context.sessionID.toRUMDataFormat, isActive: self.context.isSessionActive, - sampledForReplay: nil, - startPrecondition: nil, + startReason: nil, type: dependencies.ciTest != nil ? .ciTest : .user ), source: .init(rawValue: context.source) ?? .ios, @@ -513,7 +509,11 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { ) if let event = dependencies.eventBuilder.build(from: viewEvent) { - writer.write(value: event, metadata: event.metadata()) + if viewUpdatesThrottler.accept(event: event) { + writer.write(value: event, metadata: event.metadata()) + } else { // if event was dropped by sampler + version -= 1 + } // Update `CrashContext` with recent RUM view (no matter sampling - we want to always // have recent information if process is interrupted by crash): @@ -564,7 +564,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.hasReplay, + hasReplay: context.srBaggage?.isReplayBeingRecorded, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), @@ -615,7 +615,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.hasReplay, + hasReplay: context.srBaggage?.isReplayBeingRecorded, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), diff --git a/DatadogRUM/Tests/Feature/RequestBuilderTests.swift b/DatadogRUM/Tests/Feature/RequestBuilderTests.swift index 2c79409a5a..c22191ffdf 100644 --- a/DatadogRUM/Tests/Feature/RequestBuilderTests.swift +++ b/DatadogRUM/Tests/Feature/RequestBuilderTests.swift @@ -10,15 +10,15 @@ import DatadogInternal @testable import DatadogRUM class RequestBuilderTests: XCTestCase { - private let mockEvents: [Data] = [ - "event 1".utf8Data, - "event 2".utf8Data, - "event 3".utf8Data, + private let mockEvents: [Event] = [ + .init(data: "event 1".utf8Data), + .init(data: "event 2".utf8Data), + .init(data: "event 3".utf8Data) ] func testItCreatesPOSTRequest() { // Given - let builder = RequestBuilder(customIntakeURL: nil) + let builder = RequestBuilder(customIntakeURL: nil, eventsFilter: .init()) // When let request = builder.request(for: mockEvents, with: .mockAny()) @@ -29,7 +29,7 @@ class RequestBuilderTests: XCTestCase { func testItSetsRUMIntakeURL() { // Given - let builder = RequestBuilder(customIntakeURL: nil) + let builder = RequestBuilder(customIntakeURL: nil, eventsFilter: .init()) // When func url(for site: DatadogSite) -> String { @@ -49,7 +49,7 @@ class RequestBuilderTests: XCTestCase { func testItSetsCustomIntakeURL() { // Given let randomURL: URL = .mockRandom() - let builder = RequestBuilder(customIntakeURL: randomURL) + let builder = RequestBuilder(customIntakeURL: randomURL, eventsFilter: .init()) // When func url(for site: DatadogSite) -> String { @@ -75,7 +75,7 @@ class RequestBuilderTests: XCTestCase { let randomSDKVersion: String = .mockRandom(among: .alphanumerics) // Given - let builder = RequestBuilder(customIntakeURL: nil) + let builder = RequestBuilder(customIntakeURL: nil, eventsFilter: .init()) let context: DatadogContext = .mockWith( service: randomService, env: randomEnv, @@ -100,7 +100,7 @@ class RequestBuilderTests: XCTestCase { let randomVariant: String = .mockRandom(among: .alphanumerics) // Given - let builder = RequestBuilder(customIntakeURL: nil) + let builder = RequestBuilder(customIntakeURL: nil, eventsFilter: .init()) let context: DatadogContext = .mockWith(variant: randomVariant) // When @@ -125,7 +125,7 @@ class RequestBuilderTests: XCTestCase { let randomDeviceOSVersion: String = .mockRandom() // Given - let builder = RequestBuilder(customIntakeURL: nil) + let builder = RequestBuilder(customIntakeURL: nil, eventsFilter: .init()) let context: DatadogContext = .mockWith( clientToken: randomClientToken, service: randomService, @@ -162,7 +162,7 @@ class RequestBuilderTests: XCTestCase { func testItSetsHTTPBodyInExpectedFormat() { // Given - let builder = RequestBuilder(customIntakeURL: nil) + let builder = RequestBuilder(customIntakeURL: nil, eventsFilter: .init()) // When let request = builder.request(for: mockEvents, with: .mockAny()) diff --git a/DatadogRUM/Tests/RUMViewEventsFilterTests.swift b/DatadogRUM/Tests/RUMViewEventsFilterTests.swift index 4da40e901a..59f954c4d2 100644 --- a/DatadogRUM/Tests/RUMViewEventsFilterTests.swift +++ b/DatadogRUM/Tests/RUMViewEventsFilterTests.swift @@ -6,7 +6,8 @@ import XCTest import TestUtilities -@testable import Datadog +import DatadogInternal +@testable import DatadogRUM final class RUMViewEventsFilterTests: XCTestCase { let sut = RUMViewEventsFilter() @@ -108,16 +109,8 @@ final class RUMViewEventsFilterTests: XCTestCase { extension Event { init(data: String, metadata: RUMViewEvent.Metadata?) throws { - self.init(data: data.utf8Data, metadata: try JSONEncoder().encode(metadata)) - } -} - -extension Event: AnyMockable { - public static func mockAny() -> Self { - return mockWith() - } - - public static func mockWith(data: Data = .init(), metadata: Data? = nil) -> Self { - return Event(data: data, metadata: metadata) + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + self.init(data: data.utf8Data, metadata: try encoder.encode(metadata)) } } diff --git a/DatadogTrace/Sources/Feature/RequestBuilder.swift b/DatadogTrace/Sources/Feature/RequestBuilder.swift index 40b8ac75d7..566e7ad95d 100644 --- a/DatadogTrace/Sources/Feature/RequestBuilder.swift +++ b/DatadogTrace/Sources/Feature/RequestBuilder.swift @@ -20,7 +20,7 @@ internal struct TracingRequestBuilder: FeatureRequestBuilder { self.customIntakeURL = customIntakeURL } - func request(for events: [Data], with context: DatadogContext) -> URLRequest { + func request(for events: [Event], with context: DatadogContext) -> URLRequest { let builder = URLRequestBuilder( url: url(with: context), queryItems: [], @@ -38,7 +38,7 @@ internal struct TracingRequestBuilder: FeatureRequestBuilder { ] ) - let data = format.format(events) + let data = format.format(events.map { $0.data }) return builder.uploadRequest(with: data) } diff --git a/TestUtilities/Mocks/EventMocks.swift b/TestUtilities/Mocks/EventMocks.swift new file mode 100644 index 0000000000..e19c773ade --- /dev/null +++ b/TestUtilities/Mocks/EventMocks.swift @@ -0,0 +1,19 @@ +/* + * 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 2019-2020 Datadog, Inc. + */ + + +import Foundation +import DatadogInternal + +extension Event: AnyMockable { + public static func mockAny() -> Self { + return mockWith() + } + + public static func mockWith(data: Data = .init(), metadata: Data? = nil) -> Self { + return Event(data: data, metadata: metadata) + } +} From 66aed9f7c05fc4684f9e1819ed7c1d36fcdafaac Mon Sep 17 00:00:00 2001 From: Maciek Grzybowski Date: Mon, 10 Jul 2023 11:36:50 +0200 Subject: [PATCH 80/87] REPLAY-1616 Lint --- tools/sr-snapshots/Sources/Shell/ProcessCommandLine.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/sr-snapshots/Sources/Shell/ProcessCommandLine.swift b/tools/sr-snapshots/Sources/Shell/ProcessCommandLine.swift index 4c4ac3e598..bd0a6cf395 100644 --- a/tools/sr-snapshots/Sources/Shell/ProcessCommandLine.swift +++ b/tools/sr-snapshots/Sources/Shell/ProcessCommandLine.swift @@ -29,7 +29,7 @@ public class ProcessCommandLine: CommandLine { } _ = semaphore.wait(timeout: .distantFuture) - switch result! { + switch result! { // swiftlint:disable:this force_unwrapping case .success(let result): return result case .failure(let error): throw error } @@ -87,7 +87,7 @@ public class ProcessCommandLine: CommandLine { processGroup.enter() let stdoutFile = stdoutPipe.fileHandleForReading let stdoutReadIO = DispatchIO(type: .stream, fileDescriptor: stdoutFile.fileDescriptor, queue: queue) { _ in - try! stdoutFile.close() + try! stdoutFile.close() // swiftlint:disable:this force_try } stdoutReadIO.read(offset: 0, length: .max, queue: queue) { isDone, chunk, error in stdoutData.append(contentsOf: chunk ?? .empty) @@ -102,7 +102,7 @@ public class ProcessCommandLine: CommandLine { processGroup.enter() let stderrFile = stderrPipe.fileHandleForReading let stderrReadIO = DispatchIO(type: .stream, fileDescriptor: stderrFile.fileDescriptor, queue: queue) { _ in - try! stderrFile.close() + try! stderrFile.close() // swiftlint:disable:this force_try } stderrReadIO.read(offset: 0, length: .max, queue: queue) { isDone, chunk, error in stderrData.append(contentsOf: chunk ?? .empty) @@ -117,7 +117,7 @@ public class ProcessCommandLine: CommandLine { // We’ve only entered the group once at this point, so the single leave done by the // termination handler is enough to run the notify block and call the // client’s completion handler. - task.terminationHandler!(task) + task.terminationHandler!(task) // swiftlint:disable:this force_unwrapping } } } From 524eb9e1556fb9a743922075346700f802e3b48f Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 10 Jul 2023 15:39:15 +0200 Subject: [PATCH 81/87] Fix conflicts with #1347 --- .../DatadogInternal/DatadogCoreProxy.swift | 22 +----- .../Tests/Datadog/Mocks/RUMFeatureMocks.swift | 13 ---- .../Tests/Mocks/RUMDataModelMocks.swift | 7 +- DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift | 13 ++++ .../Recorder/RecordingCoordinator.swift | 76 +++++++++++-------- .../FeatureRegistrationCoreMock.swift | 4 + 6 files changed, 68 insertions(+), 67 deletions(-) diff --git a/DatadogCore/Tests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift b/DatadogCore/Tests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift index 8b080aa2e2..72ceda95ce 100644 --- a/DatadogCore/Tests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift +++ b/DatadogCore/Tests/Datadog/Mocks/DatadogInternal/DatadogCoreProxy.swift @@ -86,31 +86,11 @@ internal class DatadogCoreProxy: DatadogCoreProtocol { core.update(feature: feature, attributes: attributes) } - func send(message: FeatureMessag, else fallback: @escaping () -> Void) { + func send(message: FeatureMessage, else fallback: @escaping () -> Void) { core.send(message: message, else: fallback) } } -extension DatadogCoreProxy: DatadogV1CoreProtocol { - func feature(_ type: T.Type) -> T? { - return core.feature(type) - } - - func register(feature instance: T?) { - let key = String(describing: T.self) - featureScopeInterceptors[key] = FeatureScopeInterceptor() - - core.register(feature: instance) - } - - func scope(for featureType: T.Type) -> FeatureScope? { - return core.scope(for: featureType).map { scope in - let key = String(describing: T.self) - return FeatureScopeProxy(proxy: scope, interceptor: featureScopeInterceptors[key]!) - } - } -} - extension DatadogCoreProxy { func flush() { core.flush() diff --git a/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift b/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift index 9719ca87c8..7d663f3653 100644 --- a/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift +++ b/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift @@ -1008,16 +1008,3 @@ class ContinuousVitalReaderMock: ContinuousVitalReader { } } } - -// MARK: - Dependency on Session Replay - -extension Dictionary where Key == String, Value == FeatureBaggage { - static func mockSessionReplayAttributes(hasReplay: Bool?, recordsCountByViewID: [String: Int64]? = nil) -> Self { - return [ - SessionReplayDependency.srBaggageKey: [ - SessionReplayDependency.hasReplay: hasReplay, - SessionReplayDependency.recordsCountByViewID: recordsCountByViewID - ] - ] - } -} diff --git a/DatadogRUM/Tests/Mocks/RUMDataModelMocks.swift b/DatadogRUM/Tests/Mocks/RUMDataModelMocks.swift index 6a6b797949..dafc247d0c 100644 --- a/DatadogRUM/Tests/Mocks/RUMDataModelMocks.swift +++ b/DatadogRUM/Tests/Mocks/RUMDataModelMocks.swift @@ -86,6 +86,7 @@ extension RUMDevice.RUMDeviceType: RandomMockable { extension RUMOperatingSystem: RandomMockable { public static func mockRandom() -> RUMOperatingSystem { return .init( + build: nil, name: .mockRandom(length: 5), version: .mockRandom(among: .decimalDigits, length: 2), versionMajor: .mockRandom(among: .decimalDigits, length: 1) @@ -108,6 +109,8 @@ extension RUMViewEvent: RandomMockable { dd: .init( browserSdkVersion: nil, documentVersion: .mockRandom(), + pageStates: nil, + replayStats: nil, session: .init(plan: .plan1) ), application: .init(id: .mockRandom()), @@ -118,12 +121,14 @@ extension RUMViewEvent: RandomMockable { device: .mockRandom(), display: nil, os: .mockRandom(), + privacy: nil, service: .mockRandom(), session: .init( hasReplay: nil, id: .mockRandom(), isActive: true, - startReason: .appStart, + sampledForReplay: nil, + startPrecondition: .appLaunch, type: .user ), source: .ios, diff --git a/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift b/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift index b12d78efbb..36ed035125 100644 --- a/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift +++ b/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift @@ -990,3 +990,16 @@ internal class ValueObserverMock: ValueObserver { onValueChange?(oldValue, newValue) } } + +// MARK: - Dependency on Session Replay + +extension Dictionary where Key == String, Value == FeatureBaggage { + static func mockSessionReplayAttributes(hasReplay: Bool?, recordsCountByViewID: [String: Int64]? = nil) -> Self { + return [ + SessionReplayDependency.srBaggageKey: [ + SessionReplayDependency.hasReplay: hasReplay, + SessionReplayDependency.recordsCountByViewID: recordsCountByViewID + ] + ] + } +} diff --git a/DatadogSessionReplay/Sources/Recorder/RecordingCoordinator.swift b/DatadogSessionReplay/Sources/Recorder/RecordingCoordinator.swift index a548130742..da21e3c2ff 100644 --- a/DatadogSessionReplay/Sources/Recorder/RecordingCoordinator.swift +++ b/DatadogSessionReplay/Sources/Recorder/RecordingCoordinator.swift @@ -5,60 +5,72 @@ */ import Foundation -import Datadog +import DatadogInternal /// Object is responsible for getting the RUM context, randomising the sampling rate, /// starting/stopping the recording scheduler as needed and propagating `has_replay` to other features. internal class RecordingCoordinator { - private let recorder: Recording + let recorder: Recording + let scheduler: Scheduler + let sampler: Sampler + let privacy: PrivacyLevel + let srContextPublisher: SRContextPublisher private var currentRUMContext: RUMContext? = nil private var isSampled = false init( scheduler: Scheduler, - privacy: SessionReplayPrivacy, + privacy: PrivacyLevel, rumContextObserver: RUMContextObserver, srContextPublisher: SRContextPublisher, recorder: Recording, sampler: Sampler ) { self.recorder = recorder - srContextPublisher.setHasReplay(false) + self.scheduler = scheduler + self.sampler = sampler + self.privacy = privacy + self.srContextPublisher = srContextPublisher - scheduler.schedule { [weak self] in - guard let rumContext = self?.currentRUMContext, - let viewID = rumContext.ids.viewID else { - return - } - let recorderContext = Recorder.Context( - privacy: privacy, - applicationID: rumContext.ids.applicationID, - sessionID: rumContext.ids.sessionID, - viewID: viewID, - viewServerTimeOffset: rumContext.viewServerTimeOffset - ) - self?.recorder.captureNextRecord(recorderContext) - } + srContextPublisher.setHasReplay(false) + scheduler.schedule { [weak self] in self?.captureNextRecord() } scheduler.start() - rumContextObserver.observe(on: scheduler.queue) { [weak self] rumContext in - if self?.currentRUMContext?.ids.sessionID != rumContext?.ids.sessionID || self?.currentRUMContext == nil { - self?.isSampled = sampler.sample() - } + rumContextObserver.observe(on: scheduler.queue) { [weak self] in self?.onRUMContextChanged(rumContext: $0) } + } - self?.currentRUMContext = rumContext + private func onRUMContextChanged(rumContext: RUMContext?) { + if currentRUMContext?.ids.sessionID != rumContext?.ids.sessionID || currentRUMContext == nil { + isSampled = sampler.sample() + } - if self?.isSampled == true { - scheduler.start() - } else { - scheduler.stop() - } + currentRUMContext = rumContext + + if isSampled { + scheduler.start() + } else { + scheduler.stop() + } + + srContextPublisher.setHasReplay( + isSampled == true && currentRUMContext?.ids.viewID != nil + ) + } - srContextPublisher.setHasReplay( - self?.isSampled == true && self?.currentRUMContext?.ids.viewID != nil - ) + private func captureNextRecord() { + guard let rumContext = currentRUMContext, + let viewID = rumContext.ids.viewID else { + return } + let recorderContext = Recorder.Context( + privacy: privacy, + applicationID: rumContext.ids.applicationID, + sessionID: rumContext.ids.sessionID, + viewID: viewID, + viewServerTimeOffset: rumContext.viewServerTimeOffset + ) + recorder.captureNextRecord(recorderContext) } -} \ No newline at end of file +} diff --git a/TestUtilities/Mocks/CoreMocks/FeatureRegistrationCoreMock.swift b/TestUtilities/Mocks/CoreMocks/FeatureRegistrationCoreMock.swift index 5191511444..ee7682bc5e 100644 --- a/TestUtilities/Mocks/CoreMocks/FeatureRegistrationCoreMock.swift +++ b/TestUtilities/Mocks/CoreMocks/FeatureRegistrationCoreMock.swift @@ -55,6 +55,10 @@ public class FeatureRegistrationCoreMock: DatadogCoreProtocol { // not supported - use different type of core mock if you need this } + public func update(feature: String, attributes: @escaping () -> FeatureBaggage) { + // not supported - use different type of core mock if you need thi + } + public func send(message: DatadogInternal.FeatureMessage, else fallback: @escaping () -> Void) { // not supported - use different type of core mock if you need this } From 08540ad6a718a8e95779b45edf6ace0b2e6240c7 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 10 Jul 2023 15:42:20 +0200 Subject: [PATCH 82/87] Fix conflicts with #1354 --- Datadog/Datadog.xcodeproj/project.pbxproj | 444 +----------------- .../Tests/Datadog/Mocks/RUMFeatureMocks.swift | 6 - .../Tests/Datadog/RUM/RUMMonitorTests.swift | 1 - .../Tests/DatadogObjc/DDRUMMonitorTests.swift | 4 +- DatadogRUM/Sources/Feature/RUMFeature.swift | 1 - DatadogRUM/Sources/RUMConfiguration.swift | 3 - .../Scopes/RUMScopeDependencies.swift | 3 - .../RUMMonitor/Scopes/RUMViewScope.swift | 28 +- DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift | 14 +- 9 files changed, 38 insertions(+), 466 deletions(-) diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index b56c31fcfa..ecb6a5546e 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -22,27 +22,14 @@ 3C0D5DF52A5443B100446CF9 /* DataFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DF42A5443B100446CF9 /* DataFormatTests.swift */; }; 3C0D5DF62A5443B100446CF9 /* DataFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C0D5DF42A5443B100446CF9 /* DataFormatTests.swift */; }; 3C41693C29FBF4D50042B9D2 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; }; - 3C41694729FBF8CC0042B9D2 /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2DA2385298D57AA00C6C7E6 /* DatadogInternal.framework */; }; 3C74305C29FBC0480053B80F /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2DA2385298D57AA00C6C7E6 /* DatadogInternal.framework */; }; - 3C85D41B29F7C5C300AFF894 /* WKUserContentController+DatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */; }; - 3C85D41C29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */; }; - 3C85D41D29F7C5C400AFF894 /* WKUserContentController+DatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */; }; - 3C85D41E29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */; }; - 3C85D41F29F7C5C900AFF894 /* WebViewTrackingMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */; }; - 3C85D42029F7C5C900AFF894 /* WKUserContentController+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */; }; 3C85D42129F7C5C900AFF894 /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */; }; - 3C85D42229F7C5CA00AFF894 /* WebViewTrackingMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */; }; - 3C85D42329F7C5CA00AFF894 /* WKUserContentController+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */; }; - 3C85D42429F7C5CA00AFF894 /* WebViewTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */; }; - 3C85D42929F7C6FD00AFF894 /* TestUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D257958B298ABB83008A1BE5 /* TestUtilities.framework */; }; 3C85D42A29F7C70300AFF894 /* TestUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D257953E298ABA65008A1BE5 /* TestUtilities.framework */; }; 3C85D42C29F7C87D00AFF894 /* HostsSanitizerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */; }; 3C85D42D29F7C87D00AFF894 /* HostsSanitizerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */; }; 3C9C6BB429F7C0C000581C43 /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D23039A5298D513C001A1FA3 /* DatadogInternal.framework */; }; 3CE11A1129F7BE0900202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; }; 3CE11A1229F7BE0900202522 /* DatadogWebViewTracking.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 3CE11A2829F7BE1E00202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */; }; - 3CE11A3729F7BE6B00202522 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */; }; 49274906288048B500ECD49B /* InternalTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49274903288048AA00ECD49B /* InternalTelemetryTests.swift */; }; 49274907288048B800ECD49B /* InternalTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49274903288048AA00ECD49B /* InternalTelemetryTests.swift */; }; 61020C2A2757AD91005EEAEA /* BackgroundLocationMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61020C292757AD91005EEAEA /* BackgroundLocationMonitor.swift */; }; @@ -513,7 +500,6 @@ D23F8E5829DDCD28001CFAE8 /* VitalMemoryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BBBCB0265E71C600943419 /* VitalMemoryReader.swift */; }; D23F8E5929DDCD28001CFAE8 /* WebViewEventReceiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CBC26A294383F200134409 /* WebViewEventReceiver.swift */; }; D23F8E5A29DDCD28001CFAE8 /* RUMResourceScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494CB024C839460082C633 /* RUMResourceScope.swift */; }; - D23F8E5B29DDCD28001CFAE8 /* RUMViewUpdatesThrottler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494B7927F352570082BBCC /* RUMViewUpdatesThrottler.swift */; }; D23F8E5C29DDCD28001CFAE8 /* RUMApplicationScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C3E63D24BF1B91008053F2 /* RUMApplicationScope.swift */; }; D23F8E5D29DDCD28001CFAE8 /* SwiftUIViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D249859F2728042200B4F72D /* SwiftUIViewModifier.swift */; }; D23F8E5E29DDCD28001CFAE8 /* VitalInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3FC3C0626526EFF00DEED9E /* VitalInfo.swift */; }; @@ -527,7 +513,6 @@ D23F8E6729DDCD28001CFAE8 /* RUMUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618DCFD624C7265300589570 /* RUMUUID.swift */; }; D23F8E6829DDCD28001CFAE8 /* UIKitExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615F197B25B5A64B00BE14B5 /* UIKitExtensions.swift */; }; D23F8E6929DDCD28001CFAE8 /* RUMContextAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CBC26D294395A300134409 /* RUMContextAttributes.swift */; }; - D23F8E6A29DDCD28001CFAE8 /* (null) in Sources */ = {isa = PBXBuildFile; }; D23F8E6B29DDCD28001CFAE8 /* RUMMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61E5333524B84B43003D6C4E /* RUMMonitor.swift */; }; D23F8E6C29DDCD28001CFAE8 /* RUMContextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6156CB8D24DDA1B5008CB2B2 /* RUMContextProvider.swift */; }; D23F8E6D29DDCD28001CFAE8 /* RUMViewIdentity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FF9A4425AC5DEA001058CC /* RUMViewIdentity.swift */; }; @@ -567,7 +552,6 @@ D23F8EA029DDCD38001CFAE8 /* RUMOffViewEventsHandlingRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A614E9276B9D4C00A06CE7 /* RUMOffViewEventsHandlingRuleTests.swift */; }; D23F8EA229DDCD38001CFAE8 /* RUMSessionScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C2C20824C0C75500C0321C /* RUMSessionScopeTests.swift */; }; D23F8EA329DDCD38001CFAE8 /* RUMUserActionScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 617CD0DC24CEDDD300B0B557 /* RUMUserActionScopeTests.swift */; }; - D23F8EA429DDCD38001CFAE8 /* RUMViewUpdatesThrottlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6141CE662806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift */; }; D23F8EA529DDCD38001CFAE8 /* UIKitMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29A9FDF29DDC75A005C54A4 /* UIKitMocks.swift */; }; D23F8EA629DDCD38001CFAE8 /* RUMDeviceInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FD9FCE28534EBD00214BD9 /* RUMDeviceInfoTests.swift */; }; D23F8EA829DDCD38001CFAE8 /* RUMResourceScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494CB424C864680082C633 /* RUMResourceScopeTests.swift */; }; @@ -730,6 +714,11 @@ D293302D2A137DAD0029C9EA /* CrashReportingFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = D293302B2A137DAD0029C9EA /* CrashReportingFeature.swift */; }; D295A16529F299C9007C0E9A /* URLSessionInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D295A16429F299C9007C0E9A /* URLSessionInterceptor.swift */; }; D295A16629F299C9007C0E9A /* URLSessionInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D295A16429F299C9007C0E9A /* URLSessionInterceptor.swift */; }; + D29732492A5C108700827599 /* DDScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29732462A5C108700827599 /* DDScriptMessageHandler.swift */; }; + D297324B2A5C108700827599 /* MessageEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29732472A5C108700827599 /* MessageEmitter.swift */; }; + D297324D2A5C108700827599 /* WebViewMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29732482A5C108700827599 /* WebViewMessage.swift */; }; + D29732512A5C109A00827599 /* MessageEmitterCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D297324F2A5C109A00827599 /* MessageEmitterCoreTests.swift */; }; + D29732532A5C109A00827599 /* WebViewTrackingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29732502A5C109A00827599 /* WebViewTrackingTests.swift */; }; D29A9F3C29DD84AB005C54A4 /* DatadogRUM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29A9F3429DD84AA005C54A4 /* DatadogRUM.framework */; }; D29A9F4B29DD8525005C54A4 /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D23039A5298D513C001A1FA3 /* DatadogInternal.framework */; }; D29A9F4C29DD8525005C54A4 /* DatadogInternal.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D23039A5298D513C001A1FA3 /* DatadogInternal.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -739,7 +728,6 @@ D29A9F5329DD85BB005C54A4 /* RUMOffViewEventsHandlingRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A614E7276B2BD000A06CE7 /* RUMOffViewEventsHandlingRule.swift */; }; D29A9F5429DD85BB005C54A4 /* RUMScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C3E63624BF191F008053F2 /* RUMScope.swift */; }; D29A9F5529DD85BB005C54A4 /* PerformanceMetric.swift in Sources */ = {isa = PBXBuildFile; fileRef = E179FB4D28F80A6400CC2698 /* PerformanceMetric.swift */; }; - D29A9F5629DD85BB005C54A4 /* RUMViewUpdatesThrottler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61494B7927F352570082BBCC /* RUMViewUpdatesThrottler.swift */; }; D29A9F5729DD85BB005C54A4 /* URLSessionRUMResourcesHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2BCB11E29D30AF000737A9A /* URLSessionRUMResourcesHandler.swift */; }; D29A9F5829DD85BB005C54A4 /* RUMConnectivityInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614B0A4E24EBDC6B00A2A780 /* RUMConnectivityInfoProvider.swift */; }; D29A9F5929DD85BB005C54A4 /* RUMCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C3E63A24BF1A4B008053F2 /* RUMCommand.swift */; }; @@ -760,7 +748,6 @@ D29A9F6929DD85BB005C54A4 /* UIKitRUMUserActionsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6141015A251A601D00E3C2D9 /* UIKitRUMUserActionsHandler.swift */; }; D29A9F6A29DD85BB005C54A4 /* SwiftUIViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D249859F2728042200B4F72D /* SwiftUIViewModifier.swift */; }; D29A9F6B29DD85BB005C54A4 /* VitalInfoSampler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E9973F0268DF69500D8059B /* VitalInfoSampler.swift */; }; - D29A9F6C29DD85BB005C54A4 /* (null) in Sources */ = {isa = PBXBuildFile; }; D29A9F6D29DD85BB005C54A4 /* UIApplicationSwizzler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6141014E251A57AF00E3C2D9 /* UIApplicationSwizzler.swift */; }; D29A9F6E29DD85BB005C54A4 /* RUMUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618DCFD624C7265300589570 /* RUMUUID.swift */; }; D29A9F6F29DD85BB005C54A4 /* RUMInstrumentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616CCE15250A467E009FED46 /* RUMInstrumentation.swift */; }; @@ -809,7 +796,6 @@ D29A9FAC29DDB483005C54A4 /* UIKitRUMUserActionsHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615C3195251DD5080018781C /* UIKitRUMUserActionsHandlerTests.swift */; }; D29A9FAE29DDB483005C54A4 /* SessionReplayDependencyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615950EA291C029700470E0C /* SessionReplayDependencyTests.swift */; }; D29A9FB029DDB483005C54A4 /* RUMOperatingSystemInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616C0AA028573F6300C13264 /* RUMOperatingSystemInfoTests.swift */; }; - D29A9FB129DDB483005C54A4 /* RUMViewUpdatesThrottlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6141CE662806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift */; }; D29A9FB329DDB483005C54A4 /* RUMScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 618DCFDE24C75FD300589570 /* RUMScopeTests.swift */; }; D29A9FB729DDB483005C54A4 /* RUMViewIdentityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61C1510C25AC8C1B00362D4B /* RUMViewIdentityTests.swift */; }; D29A9FB829DDB483005C54A4 /* RUMViewScopeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6198D27024C6E3B700493501 /* RUMViewScopeTests.swift */; }; @@ -1265,27 +1251,6 @@ remoteGlobalIDString = D23039A4298D513C001A1FA3; remoteInfo = "DatadogInternal iOS"; }; - 3C41694329FBF7EE0042B9D2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 61133B79242393DE00786299 /* Project object */; - proxyType = 1; - remoteGlobalIDString = D2DA2355298D57AA00C6C7E6; - remoteInfo = "DatadogInternal tvOS"; - }; - 3C41694529FBF7F50042B9D2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 61133B79242393DE00786299 /* Project object */; - proxyType = 1; - remoteGlobalIDString = D2579571298ABB83008A1BE5; - remoteInfo = "TestUtilities tvOS"; - }; - 3C41694929FBF8CC0042B9D2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 61133B79242393DE00786299 /* Project object */; - proxyType = 1; - remoteGlobalIDString = D2DA2355298D57AA00C6C7E6; - remoteInfo = "DatadogInternal tvOS"; - }; 3C4D5FEE2A0115C600F1FF78 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 61133B79242393DE00786299 /* Project object */; @@ -1314,13 +1279,6 @@ remoteGlobalIDString = 3CE119FD29F7BE0000202522; remoteInfo = "DatadogWebViewTracking iOS"; }; - 3CE11A2929F7BE1E00202522 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 61133B79242393DE00786299 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 3CE11A1F29F7BE1800202522; - remoteInfo = "DatadogWebViewTracking tvOS"; - }; 61133C722423993200786299 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 61133B79242393DE00786299 /* Project object */; @@ -1690,15 +1648,9 @@ 3C0D5DEE2A5442A900446CF9 /* EventMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventMocks.swift; sourceTree = ""; }; 3C0D5DF42A5443B100446CF9 /* DataFormatTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataFormatTests.swift; sourceTree = ""; }; 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewTracking.swift; sourceTree = ""; }; - 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewTrackingMessage.swift; sourceTree = ""; }; - 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WKUserContentController+Datadog.swift"; sourceTree = ""; }; - 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewTrackingCoreTests.swift; sourceTree = ""; }; - 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "WKUserContentController+DatadogTests.swift"; sourceTree = ""; }; 3C85D42B29F7C87D00AFF894 /* HostsSanitizerMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HostsSanitizerMock.swift; sourceTree = ""; }; 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogWebViewTracking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DatadogWebViewTrackingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogWebViewTracking.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3CE11A2729F7BE1B00202522 /* DatadogWebViewTrackingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DatadogWebViewTrackingTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49274903288048AA00ECD49B /* InternalTelemetryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InternalTelemetryTests.swift; sourceTree = ""; }; 49274908288048F400ECD49B /* RUMInternalProxyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RUMInternalProxyTests.swift; sourceTree = ""; }; 61020C292757AD91005EEAEA /* BackgroundLocationMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundLocationMonitor.swift; sourceTree = ""; }; @@ -1802,7 +1754,6 @@ 6141015A251A601D00E3C2D9 /* UIKitRUMUserActionsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitRUMUserActionsHandler.swift; sourceTree = ""; }; 61410166251A661D00E3C2D9 /* UIApplicationSwizzlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationSwizzlerTests.swift; sourceTree = ""; }; 61411B0F24EC15AC0012EAB2 /* Casting+RUM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Casting+RUM.swift"; sourceTree = ""; }; - 6141CE662806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewUpdatesThrottlerTests.swift; sourceTree = ""; }; 61441C0224616DE9003D8BB8 /* Example iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Example iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 61441C0424616DE9003D8BB8 /* ExampleAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleAppDelegate.swift; sourceTree = ""; }; 61441C0B24616DE9003D8BB8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "Base.lproj/Main iOS.storyboard"; sourceTree = ""; }; @@ -1821,7 +1772,6 @@ 6147989B2A459E2B0095CB02 /* DDTrace+apiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "DDTrace+apiTests.m"; sourceTree = ""; }; 6147E3B2270486920092BC9F /* TracingConfigurationE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingConfigurationE2ETests.swift; sourceTree = ""; }; 614872762485067300E3EBDB /* SpanTagsReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpanTagsReducer.swift; sourceTree = ""; }; - 61494B7927F352570082BBCC /* RUMViewUpdatesThrottler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewUpdatesThrottler.swift; sourceTree = ""; }; 61494CB024C839460082C633 /* RUMResourceScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMResourceScope.swift; sourceTree = ""; }; 61494CB424C864680082C633 /* RUMResourceScopeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMResourceScopeTests.swift; sourceTree = ""; }; 61494CB924CB126F0082C633 /* RUMUserActionScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMUserActionScope.swift; sourceTree = ""; }; @@ -2246,6 +2196,11 @@ D29294E2291D652900F8EFF9 /* ApplicationVersionPublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationVersionPublisherTests.swift; sourceTree = ""; }; D293302B2A137DAD0029C9EA /* CrashReportingFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportingFeature.swift; sourceTree = ""; }; D295A16429F299C9007C0E9A /* URLSessionInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionInterceptor.swift; sourceTree = ""; }; + D29732462A5C108700827599 /* DDScriptMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DDScriptMessageHandler.swift; sourceTree = ""; }; + D29732472A5C108700827599 /* MessageEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageEmitter.swift; sourceTree = ""; }; + D29732482A5C108700827599 /* WebViewMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewMessage.swift; sourceTree = ""; }; + D297324F2A5C109A00827599 /* MessageEmitterCoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageEmitterCoreTests.swift; sourceTree = ""; }; + D29732502A5C109A00827599 /* WebViewTrackingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewTrackingTests.swift; sourceTree = ""; }; D29889C72734136200A4D1A9 /* RUMViewsHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMViewsHandlerTests.swift; sourceTree = ""; }; D29A9F3429DD84AA005C54A4 /* DatadogRUM.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogRUM.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D29A9F3B29DD84AB005C54A4 /* DatadogRUMTests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "DatadogRUMTests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2352,23 +2307,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3CE11A1D29F7BE1800202522 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3C41694729FBF8CC0042B9D2 /* DatadogInternal.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 3CE11A2429F7BE1B00202522 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3C85D42929F7C6FD00AFF894 /* TestUtilities.framework in Frameworks */, - 3CE11A2829F7BE1E00202522 /* DatadogWebViewTracking.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 61133B88242393DE00786299 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2531,12 +2469,10 @@ buildActionMask = 2147483647; files = ( 61A2CC342A44A6030000FF25 /* DatadogRUM.framework in Frameworks */, - 3CE11A3729F7BE6B00202522 /* DatadogWebViewTracking.framework in Frameworks */, D25CFA9D29C4FC6E00E3A43D /* DatadogTrace.framework in Frameworks */, 9E5BD8062819742C00CB568E /* SwiftUI.framework in Frameworks */, D240687027CF971C00C04F44 /* CrashReporter.xcframework in Frameworks */, D240687127CF971C00C04F44 /* DatadogCore.framework in Frameworks */, - 3CE11A3729F7BE6B00202522 /* DatadogWebViewTracking.framework in Frameworks */, D240687227CF971C00C04F44 /* DatadogCrashReporting.framework in Frameworks */, D24C9C4629A7A520002057CF /* DatadogLogs.framework in Frameworks */, D240687327CF971C00C04F44 /* DatadogObjc.framework in Frameworks */, @@ -2705,8 +2641,9 @@ isa = PBXGroup; children = ( 3C85D41429F7C59C00AFF894 /* WebViewTracking.swift */, - 3C85D41529F7C59C00AFF894 /* WebViewTrackingMessage.swift */, - 3C85D41629F7C59C00AFF894 /* WKUserContentController+Datadog.swift */, + D29732462A5C108700827599 /* DDScriptMessageHandler.swift */, + D29732472A5C108700827599 /* MessageEmitter.swift */, + D29732482A5C108700827599 /* WebViewMessage.swift */, ); name = DatadogWebViewTracking; path = ../DatadogWebViewTracking/Sources; @@ -2715,8 +2652,8 @@ 3CE11A3C29F7BEF300202522 /* DatadogWebViewTrackingTests */ = { isa = PBXGroup; children = ( - 3C85D41729F7C5BE00AFF894 /* WebViewTrackingCoreTests.swift */, - 3C85D41829F7C5BE00AFF894 /* WKUserContentController+DatadogTests.swift */, + D297324F2A5C109A00827599 /* MessageEmitterCoreTests.swift */, + D29732502A5C109A00827599 /* WebViewTrackingTests.swift */, ); name = DatadogWebViewTrackingTests; path = ../DatadogWebViewTracking/Tests; @@ -2818,8 +2755,6 @@ D23F8ECD29DDCD38001CFAE8 /* DatadogRUMTests tvOS.xctest */, 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */, 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */, - 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */, - 3CE11A2729F7BE1B00202522 /* DatadogWebViewTrackingTests.xctest */, ); name = Products; sourceTree = ""; @@ -3329,7 +3264,6 @@ children = ( 61C1510C25AC8C1B00362D4B /* RUMViewIdentityTests.swift */, 61A614E9276B9D4C00A06CE7 /* RUMOffViewEventsHandlingRuleTests.swift */, - 6141CE662806B41C00EBB879 /* RUMViewUpdatesThrottlerTests.swift */, ); path = Utils; sourceTree = ""; @@ -3411,7 +3345,6 @@ children = ( 61FF9A4425AC5DEA001058CC /* RUMViewIdentity.swift */, 61A614E7276B2BD000A06CE7 /* RUMOffViewEventsHandlingRule.swift */, - 61494B7927F352570082BBCC /* RUMViewUpdatesThrottler.swift */, ); path = Utils; sourceTree = ""; @@ -4874,13 +4807,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3CE11A1B29F7BE1800202522 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 61133B7D242393DE00786299 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -5049,45 +4975,6 @@ productReference = 3CE11A0529F7BE0300202522 /* DatadogWebViewTrackingTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - 3CE11A1F29F7BE1800202522 /* DatadogWebViewTracking tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3CE11A2F29F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTracking tvOS" */; - buildPhases = ( - 3CE11A1B29F7BE1800202522 /* Headers */, - 3CE11A1C29F7BE1800202522 /* Sources */, - 3CE11A1D29F7BE1800202522 /* Frameworks */, - 3CE11A1E29F7BE1800202522 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 3C41694A29FBF8CC0042B9D2 /* PBXTargetDependency */, - ); - name = "DatadogWebViewTracking tvOS"; - productName = "DatadogWebViewTracking tvOS"; - productReference = 3CE11A2029F7BE1800202522 /* DatadogWebViewTracking.framework */; - productType = "com.apple.product-type.framework"; - }; - 3CE11A2629F7BE1B00202522 /* DatadogWebViewTrackingTests tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3CE11A3329F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTrackingTests tvOS" */; - buildPhases = ( - 3CE11A2329F7BE1B00202522 /* Sources */, - 3CE11A2429F7BE1B00202522 /* Frameworks */, - 3CE11A2529F7BE1B00202522 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 3C41694629FBF7F50042B9D2 /* PBXTargetDependency */, - 3C41694429FBF7EE0042B9D2 /* PBXTargetDependency */, - 3CE11A2A29F7BE1E00202522 /* PBXTargetDependency */, - ); - name = "DatadogWebViewTrackingTests tvOS"; - productName = "DatadogWebViewTracking tvOSTests"; - productReference = 3CE11A2729F7BE1B00202522 /* DatadogWebViewTrackingTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; 61133B81242393DE00786299 /* DatadogCore iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 61133B96242393DE00786299 /* Build configuration list for PBXNativeTarget "DatadogCore iOS" */; @@ -5762,14 +5649,7 @@ }; 3CE11A0429F7BE0300202522 = { CreatedOnToolsVersion = 14.0.1; - LastSwiftMigration = 1400; - }; - 3CE11A1F29F7BE1800202522 = { - CreatedOnToolsVersion = 14.0.1; - }; - 3CE11A2629F7BE1B00202522 = { - CreatedOnToolsVersion = 14.0.1; - LastSwiftMigration = 1400; + LastSwiftMigration = 1430; }; 61133B81242393DE00786299 = { CreatedOnToolsVersion = 11.3.1; @@ -5891,8 +5771,6 @@ D2579571298ABB83008A1BE5 /* TestUtilities tvOS */, 3CE119FD29F7BE0000202522 /* DatadogWebViewTracking iOS */, 3CE11A0429F7BE0300202522 /* DatadogWebViewTrackingTests iOS */, - 3CE11A1F29F7BE1800202522 /* DatadogWebViewTracking tvOS */, - 3CE11A2629F7BE1B00202522 /* DatadogWebViewTrackingTests tvOS */, ); }; /* End PBXProject section */ @@ -5912,20 +5790,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3CE11A1E29F7BE1800202522 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 3CE11A2529F7BE1B00202522 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 61133B80242393DE00786299 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -6380,8 +6244,9 @@ buildActionMask = 2147483647; files = ( 3C85D42129F7C5C900AFF894 /* WebViewTracking.swift in Sources */, - 3C85D41F29F7C5C900AFF894 /* WebViewTrackingMessage.swift in Sources */, - 3C85D42029F7C5C900AFF894 /* WKUserContentController+Datadog.swift in Sources */, + D297324D2A5C108700827599 /* WebViewMessage.swift in Sources */, + D297324B2A5C108700827599 /* MessageEmitter.swift in Sources */, + D29732492A5C108700827599 /* DDScriptMessageHandler.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6389,27 +6254,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3C85D41B29F7C5C300AFF894 /* WKUserContentController+DatadogTests.swift in Sources */, - 3C85D41C29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 3CE11A1C29F7BE1800202522 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3C85D42429F7C5CA00AFF894 /* WebViewTracking.swift in Sources */, - 3C85D42229F7C5CA00AFF894 /* WebViewTrackingMessage.swift in Sources */, - 3C85D42329F7C5CA00AFF894 /* WKUserContentController+Datadog.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 3CE11A2329F7BE1B00202522 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3C85D41D29F7C5C400AFF894 /* WKUserContentController+DatadogTests.swift in Sources */, - 3C85D41E29F7C5C400AFF894 /* WebViewTrackingCoreTests.swift in Sources */, + D29732532A5C109A00827599 /* WebViewTrackingTests.swift in Sources */, + D29732512A5C109A00827599 /* MessageEmitterCoreTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6902,7 +6748,6 @@ D23F8E5829DDCD28001CFAE8 /* VitalMemoryReader.swift in Sources */, D23F8E5929DDCD28001CFAE8 /* WebViewEventReceiver.swift in Sources */, D23F8E5A29DDCD28001CFAE8 /* RUMResourceScope.swift in Sources */, - D23F8E5B29DDCD28001CFAE8 /* RUMViewUpdatesThrottler.swift in Sources */, D23F8E5C29DDCD28001CFAE8 /* RUMApplicationScope.swift in Sources */, D23F8E5D29DDCD28001CFAE8 /* SwiftUIViewModifier.swift in Sources */, D23F8E5E29DDCD28001CFAE8 /* VitalInfo.swift in Sources */, @@ -6918,7 +6763,6 @@ D23F8E6829DDCD28001CFAE8 /* UIKitExtensions.swift in Sources */, 61C713A82A3B78F900FA735A /* RUMMonitorProtocol+Convenience.swift in Sources */, D23F8E6929DDCD28001CFAE8 /* RUMContextAttributes.swift in Sources */, - D23F8E6A29DDCD28001CFAE8 /* (null) in Sources */, D23F8E6B29DDCD28001CFAE8 /* RUMMonitor.swift in Sources */, D23F8E6C29DDCD28001CFAE8 /* RUMContextProvider.swift in Sources */, D23F8E6D29DDCD28001CFAE8 /* RUMViewIdentity.swift in Sources */, @@ -6971,7 +6815,6 @@ D23F8EA029DDCD38001CFAE8 /* RUMOffViewEventsHandlingRuleTests.swift in Sources */, D23F8EA229DDCD38001CFAE8 /* RUMSessionScopeTests.swift in Sources */, D23F8EA329DDCD38001CFAE8 /* RUMUserActionScopeTests.swift in Sources */, - D23F8EA429DDCD38001CFAE8 /* RUMViewUpdatesThrottlerTests.swift in Sources */, 61C713B42A3C3A0B00FA735A /* RUMMonitorProtocol+InternalTests.swift in Sources */, D23F8EA529DDCD38001CFAE8 /* UIKitMocks.swift in Sources */, D23F8EA629DDCD38001CFAE8 /* RUMDeviceInfoTests.swift in Sources */, @@ -7155,7 +6998,6 @@ D29A9F5B29DD85BB005C54A4 /* VitalMemoryReader.swift in Sources */, D29A9F6229DD85BB005C54A4 /* WebViewEventReceiver.swift in Sources */, D29A9F8429DD85BB005C54A4 /* RUMResourceScope.swift in Sources */, - D29A9F5629DD85BB005C54A4 /* RUMViewUpdatesThrottler.swift in Sources */, D29A9F7329DD85BB005C54A4 /* RUMApplicationScope.swift in Sources */, D29A9F6A29DD85BB005C54A4 /* SwiftUIViewModifier.swift in Sources */, D29A9F6429DD85BB005C54A4 /* VitalInfo.swift in Sources */, @@ -7171,7 +7013,6 @@ D29A9F8D29DD8665005C54A4 /* UIKitExtensions.swift in Sources */, 61C713A72A3B78F900FA735A /* RUMMonitorProtocol+Convenience.swift in Sources */, D29A9F6829DD85BB005C54A4 /* RUMContextAttributes.swift in Sources */, - D29A9F6C29DD85BB005C54A4 /* (null) in Sources */, D29A9F6329DD85BB005C54A4 /* RUMMonitor.swift in Sources */, D29A9F7029DD85BB005C54A4 /* RUMContextProvider.swift in Sources */, D29A9F6029DD85BB005C54A4 /* RUMViewIdentity.swift in Sources */, @@ -7224,7 +7065,6 @@ D29A9FA629DDB483005C54A4 /* RUMOffViewEventsHandlingRuleTests.swift in Sources */, D29A9FBD29DDB483005C54A4 /* RUMSessionScopeTests.swift in Sources */, D29A9FAB29DDB483005C54A4 /* RUMUserActionScopeTests.swift in Sources */, - D29A9FB129DDB483005C54A4 /* RUMViewUpdatesThrottlerTests.swift in Sources */, 61C713B32A3C3A0B00FA735A /* RUMMonitorProtocol+InternalTests.swift in Sources */, D29A9FE029DDC75A005C54A4 /* UIKitMocks.swift in Sources */, D29A9FA329DDB483005C54A4 /* RUMDeviceInfoTests.swift in Sources */, @@ -7758,21 +7598,6 @@ target = D23039A4298D513C001A1FA3 /* DatadogInternal iOS */; targetProxy = 3C41694129FBF6100042B9D2 /* PBXContainerItemProxy */; }; - 3C41694429FBF7EE0042B9D2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = D2DA2355298D57AA00C6C7E6 /* DatadogInternal tvOS */; - targetProxy = 3C41694329FBF7EE0042B9D2 /* PBXContainerItemProxy */; - }; - 3C41694629FBF7F50042B9D2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = D2579571298ABB83008A1BE5 /* TestUtilities tvOS */; - targetProxy = 3C41694529FBF7F50042B9D2 /* PBXContainerItemProxy */; - }; - 3C41694A29FBF8CC0042B9D2 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = D2DA2355298D57AA00C6C7E6 /* DatadogInternal tvOS */; - targetProxy = 3C41694929FBF8CC0042B9D2 /* PBXContainerItemProxy */; - }; 3C4D5FEF2A0115C600F1FF78 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D2C1A53329C4F2DF00946C31 /* DatadogTrace tvOS */; @@ -7793,11 +7618,6 @@ target = 3CE119FD29F7BE0000202522 /* DatadogWebViewTracking iOS */; targetProxy = 3CE11A0729F7BE0500202522 /* PBXContainerItemProxy */; }; - 3CE11A2A29F7BE1E00202522 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 3CE11A1F29F7BE1800202522 /* DatadogWebViewTracking tvOS */; - targetProxy = 3CE11A2929F7BE1E00202522 /* PBXContainerItemProxy */; - }; 61133C732423993200786299 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 61133B81242393DE00786299 /* DatadogCore iOS */; @@ -8214,208 +8034,6 @@ }; name = Integration; }; - 3CE11A3029F7BE2100202522 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 61569894256D0E9A00C6AADA /* Base.xcconfig */; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Datadog. All rights reserved."; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTracking; - PRODUCT_NAME = DatadogWebViewTracking; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Debug; - }; - 3CE11A3129F7BE2100202522 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 61569894256D0E9A00C6AADA /* Base.xcconfig */; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Datadog. All rights reserved."; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTracking; - PRODUCT_NAME = DatadogWebViewTracking; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Release; - }; - 3CE11A3229F7BE2100202522 /* Integration */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 61569894256D0E9A00C6AADA /* Base.xcconfig */; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Datadog. All rights reserved."; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTracking; - PRODUCT_NAME = DatadogWebViewTracking; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Integration; - }; - 3CE11A3429F7BE2100202522 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTrackingTests; - PRODUCT_NAME = DatadogWebViewTrackingTests; - SDKROOT = appletvos; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Debug; - }; - 3CE11A3529F7BE2100202522 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTrackingTests; - PRODUCT_NAME = DatadogWebViewTrackingTests; - SDKROOT = appletvos; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Release; - }; - 3CE11A3629F7BE2100202522 /* Integration */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/../Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.DatadogWebViewTrackingTests; - PRODUCT_NAME = DatadogWebViewTrackingTests; - SDKROOT = appletvos; - SUPPORTED_PLATFORMS = "appletvos appletvsimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 3; - }; - name = Integration; - }; 61133B94242393DE00786299 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -11511,26 +11129,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 3CE11A2F29F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTracking tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3CE11A3029F7BE2100202522 /* Debug */, - 3CE11A3129F7BE2100202522 /* Release */, - 3CE11A3229F7BE2100202522 /* Integration */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 3CE11A3329F7BE2100202522 /* Build configuration list for PBXNativeTarget "DatadogWebViewTrackingTests tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3CE11A3429F7BE2100202522 /* Debug */, - 3CE11A3529F7BE2100202522 /* Release */, - 3CE11A3629F7BE2100202522 /* Integration */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 61133B7C242393DE00786299 /* Build configuration list for PBXProject "Datadog" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift b/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift index 7d663f3653..15ef1fb5bc 100644 --- a/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift +++ b/DatadogCore/Tests/Datadog/Mocks/RUMFeatureMocks.swift @@ -653,12 +653,6 @@ extension RUMSessionState: AnyMockable, RandomMockable { // MARK: - RUMScope Mocks -internal struct NoOpRUMViewUpdatesThrottler: RUMViewUpdatesThrottlerType { - func accept(event: RUMViewEvent) -> Bool { - return true // always send view update - } -} - func mockNoOpSessionListener() -> RUM.SessionListener { return { _, _ in } } diff --git a/DatadogCore/Tests/Datadog/RUM/RUMMonitorTests.swift b/DatadogCore/Tests/Datadog/RUM/RUMMonitorTests.swift index b345a4efc9..356f5c8877 100644 --- a/DatadogCore/Tests/Datadog/RUM/RUMMonitorTests.swift +++ b/DatadogCore/Tests/Datadog/RUM/RUMMonitorTests.swift @@ -21,7 +21,6 @@ class RUMMonitorTests: XCTestCase { super.setUp() core = DatadogCoreProxy() config = RUM.Configuration(applicationID: .mockAny()) - config.viewUpdatesThrottlerFactory = { NoOpRUMViewUpdatesThrottler() } // disable view updates sampling for deterministic behaviour } override func tearDown() { diff --git a/DatadogCore/Tests/DatadogObjc/DDRUMMonitorTests.swift b/DatadogCore/Tests/DatadogObjc/DDRUMMonitorTests.swift index f3739c7f50..07e090358f 100644 --- a/DatadogCore/Tests/DatadogObjc/DDRUMMonitorTests.swift +++ b/DatadogCore/Tests/DatadogObjc/DDRUMMonitorTests.swift @@ -141,7 +141,6 @@ class DDRUMMonitorTests: XCTestCase { core = DatadogCoreProxy() CoreRegistry.register(default: core) config = RUM.Configuration(applicationID: .mockAny()) - config.viewUpdatesThrottlerFactory = { NoOpRUMViewUpdatesThrottler() } // disable view updates sampling for deterministic behaviour } override func tearDown() { @@ -198,7 +197,6 @@ class DDRUMMonitorTests: XCTestCase { } func testSendingViewEventsWithTiming() throws { - config.viewUpdatesThrottlerFactory = { RUMViewUpdatesThrottler() } RUM.enable(with: config) let objcRUMMonitor = DDRUMMonitor.shared() @@ -211,7 +209,7 @@ class DDRUMMonitorTests: XCTestCase { let viewEvents = rumEventMatchers.filterRUMEvents(ofType: RUMViewEvent.self) { event in return event.view.name != RUMOffViewEventsHandlingRule.Constants.applicationLaunchViewName } - XCTAssertEqual(viewEvents.count, 2) + XCTAssertEqual(viewEvents.count, 3) let event1: RUMViewEvent = try viewEvents[0].model() let event2: RUMViewEvent = try viewEvents[1].model() diff --git a/DatadogRUM/Sources/Feature/RUMFeature.swift b/DatadogRUM/Sources/Feature/RUMFeature.swift index d7c34b5051..3453961744 100644 --- a/DatadogRUM/Sources/Feature/RUMFeature.swift +++ b/DatadogRUM/Sources/Feature/RUMFeature.swift @@ -51,7 +51,6 @@ internal final class RUMFeature: DatadogRemoteFeature { ), rumUUIDGenerator: configuration.uuidGenerator, ciTest: configuration.ciTestExecutionID.map { RUMCITest(testExecutionId: $0) }, - viewUpdatesThrottlerFactory: configuration.viewUpdatesThrottlerFactory, vitalsReaders: configuration.vitalsUpdateFrequency.map { VitalsReaders(frequency: $0.timeInterval) }, onSessionStart: configuration.onSessionStart ) diff --git a/DatadogRUM/Sources/RUMConfiguration.swift b/DatadogRUM/Sources/RUMConfiguration.swift index 4949b94ccf..2fdf131fae 100644 --- a/DatadogRUM/Sources/RUMConfiguration.swift +++ b/DatadogRUM/Sources/RUMConfiguration.swift @@ -250,9 +250,6 @@ extension RUM { internal var dateProvider: DateProvider = SystemDateProvider() - /// Produces view update events' throttler for each started RUM view scope. - internal var viewUpdatesThrottlerFactory: () -> RUMViewUpdatesThrottlerType = { RUMViewUpdatesThrottler() } - internal var debugSDK: Bool = ProcessInfo.processInfo.arguments.contains(LaunchArguments.Debug) internal var debugViews: Bool = ProcessInfo.processInfo.arguments.contains("DD_DEBUG_RUM") internal var ciTestExecutionID: String? = ProcessInfo.processInfo.environment["CI_VISIBILITY_TEST_EXECUTION_ID"] diff --git a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMScopeDependencies.swift b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMScopeDependencies.swift index efdc0cfee6..68eaa51c75 100644 --- a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMScopeDependencies.swift +++ b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMScopeDependencies.swift @@ -27,9 +27,6 @@ internal struct RUMScopeDependencies { let rumUUIDGenerator: RUMUUIDGenerator /// Integration with CIApp tests. It contains the CIApp test context when active. let ciTest: RUMCITest? - /// Produces `RUMViewUpdatesThrottlerType` for each started RUM view scope. - let viewUpdatesThrottlerFactory: () -> RUMViewUpdatesThrottlerType - let vitalsReaders: VitalsReaders? let onSessionStart: RUM.SessionListener? } diff --git a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMViewScope.swift b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMViewScope.swift index 11373212b5..58793254de 100644 --- a/DatadogRUM/Sources/RUMMonitor/Scopes/RUMViewScope.swift +++ b/DatadogRUM/Sources/RUMMonitor/Scopes/RUMViewScope.swift @@ -90,9 +90,6 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { private let vitalInfoSampler: VitalInfoSampler? - /// Samples view update events, so we can minimize the number of events in payload. - private let viewUpdatesThrottler: RUMViewUpdatesThrottlerType - private var viewPerformanceMetrics: [PerformanceMetric: VitalInfo] = [:] init( @@ -127,7 +124,6 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { frequency: $0.frequency ) } - self.viewUpdatesThrottler = dependencies.viewUpdatesThrottlerFactory() } // MARK: - RUMContextProvider @@ -395,7 +391,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), @@ -442,6 +438,12 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { dd: .init( browserSdkVersion: nil, documentVersion: version.toInt64, + pageStates: nil, + replayStats: .init( + recordsCount: context.srBaggage?.recordsCountByViewID[viewUUID.toRUMDataFormat], + segmentsCount: nil, + segmentsTotalRawSize: nil + ), session: .init(plan: .plan1) ), application: .init(id: self.context.rumApplicationID), @@ -453,12 +455,14 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { display: nil, featureFlags: .init(featureFlagsInfo: featureFlags), os: .init(context: context), + privacy: nil, service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, isActive: self.context.isSessionActive, - startReason: nil, + sampledForReplay: nil, + startPrecondition: nil, type: dependencies.ciTest != nil ? .ciTest : .user ), source: .init(rawValue: context.source) ?? .ios, @@ -509,11 +513,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { ) if let event = dependencies.eventBuilder.build(from: viewEvent) { - if viewUpdatesThrottler.accept(event: event) { - writer.write(value: event, metadata: event.metadata()) - } else { // if event was dropped by sampler - version -= 1 - } + writer.write(value: event, metadata: event.metadata()) // Update `CrashContext` with recent RUM view (no matter sampling - we want to always // have recent information if process is interrupted by crash): @@ -564,7 +564,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), @@ -615,7 +615,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { os: .init(context: context), service: context.service, session: .init( - hasReplay: context.srBaggage?.isReplayBeingRecorded, + hasReplay: context.srBaggage?.hasReplay, id: self.context.sessionID.toRUMDataFormat, type: dependencies.ciTest != nil ? .ciTest : .user ), diff --git a/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift b/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift index 36ed035125..628423fe72 100644 --- a/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift +++ b/DatadogRUM/Tests/Mocks/RUMFeatureMocks.swift @@ -640,12 +640,6 @@ extension RUMContext { // MARK: - RUMScope Mocks -internal struct NoOpRUMViewUpdatesThrottler: RUMViewUpdatesThrottlerType { - func accept(event: RUMViewEvent) -> Bool { - return true // always send view update - } -} - func mockNoOpSessionListener() -> RUM.SessionListener { return { _, _ in } } @@ -665,7 +659,6 @@ extension RUMScopeDependencies { eventBuilder: RUMEventBuilder = RUMEventBuilder(eventsMapper: .mockNoOp()), rumUUIDGenerator: RUMUUIDGenerator = DefaultRUMUUIDGenerator(), ciTest: RUMCITest? = nil, - viewUpdatesThrottlerFactory: @escaping () -> RUMViewUpdatesThrottlerType = { NoOpRUMViewUpdatesThrottler() }, vitalsReaders: VitalsReaders? = nil, onSessionStart: @escaping RUM.SessionListener = mockNoOpSessionListener() ) -> RUMScopeDependencies { @@ -679,7 +672,6 @@ extension RUMScopeDependencies { eventBuilder: eventBuilder, rumUUIDGenerator: rumUUIDGenerator, ciTest: ciTest, - viewUpdatesThrottlerFactory: viewUpdatesThrottlerFactory, vitalsReaders: vitalsReaders, onSessionStart: onSessionStart ) @@ -695,7 +687,6 @@ extension RUMScopeDependencies { eventBuilder: RUMEventBuilder? = nil, rumUUIDGenerator: RUMUUIDGenerator? = nil, ciTest: RUMCITest? = nil, - viewUpdatesThrottlerFactory: (() -> RUMViewUpdatesThrottlerType)? = nil, vitalsReaders: VitalsReaders? = nil, onSessionStart: RUM.SessionListener? = nil ) -> RUMScopeDependencies { @@ -709,7 +700,6 @@ extension RUMScopeDependencies { eventBuilder: eventBuilder ?? self.eventBuilder, rumUUIDGenerator: rumUUIDGenerator ?? self.rumUUIDGenerator, ciTest: ciTest ?? self.ciTest, - viewUpdatesThrottlerFactory: viewUpdatesThrottlerFactory ?? self.viewUpdatesThrottlerFactory, vitalsReaders: vitalsReaders ?? self.vitalsReaders, onSessionStart: onSessionStart ?? self.onSessionStart ) @@ -733,14 +723,14 @@ extension RUMSessionScope { parent: RUMContextProvider = RUMContextProviderMock(), startTime: Date = .mockAny(), dependencies: RUMScopeDependencies = .mockAny(), - isReplayBeingRecorded: Bool? = .mockAny() + hasReplay: Bool? = .mockAny() ) -> RUMSessionScope { return RUMSessionScope( isInitialSession: isInitialSession, parent: parent, startTime: startTime, dependencies: dependencies, - isReplayBeingRecorded: isReplayBeingRecorded + hasReplay: hasReplay ) } } From 2b51ad149ab1c0f7b5e27f16b7e97b479a629f60 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 10 Jul 2023 15:42:46 +0200 Subject: [PATCH 83/87] Fix conflicts with configuration --- .../DatadogWebViewTracking tvOS.xcscheme | 78 ------------------- DatadogCore/Sources/Core/DatadogCore.swift | 3 +- .../DatadogCore/DatadogCoreTests.swift | 16 ++-- DatadogCore/Tests/Datadog/LoggerTests.swift | 8 +- .../Storage/PerformancePresetOverride.swift | 12 +-- 5 files changed, 18 insertions(+), 99 deletions(-) delete mode 100644 Datadog/Datadog.xcodeproj/xcshareddata/xcschemes/DatadogWebViewTracking tvOS.xcscheme diff --git a/Datadog/Datadog.xcodeproj/xcshareddata/xcschemes/DatadogWebViewTracking tvOS.xcscheme b/Datadog/Datadog.xcodeproj/xcshareddata/xcschemes/DatadogWebViewTracking tvOS.xcscheme deleted file mode 100644 index 485d876257..0000000000 --- a/Datadog/Datadog.xcodeproj/xcshareddata/xcschemes/DatadogWebViewTracking tvOS.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/DatadogCore/Sources/Core/DatadogCore.swift b/DatadogCore/Sources/Core/DatadogCore.swift index d23f7a5a76..25c66fe923 100644 --- a/DatadogCore/Sources/Core/DatadogCore.swift +++ b/DatadogCore/Sources/Core/DatadogCore.swift @@ -70,8 +70,7 @@ internal final class DatadogCore { /// - Parameters: /// - directory: The core directory for this instance of the SDK. /// - dateProvider: The system date provider. - /// - consentProvider: The user consent provider. - /// - userInfoProvider: The user info provider. + /// - initialConsent: The initial user consent. /// - performance: The core SDK performance presets. /// - httpClient: The HTTP Client for uploads. /// - encryption: The on-disk data encryption. diff --git a/DatadogCore/Tests/Datadog/DatadogCore/DatadogCoreTests.swift b/DatadogCore/Tests/Datadog/DatadogCore/DatadogCoreTests.swift index a3b2e7886d..8cda8db58f 100644 --- a/DatadogCore/Tests/Datadog/DatadogCore/DatadogCoreTests.swift +++ b/DatadogCore/Tests/Datadog/DatadogCore/DatadogCoreTests.swift @@ -203,12 +203,11 @@ class DatadogCoreTests: XCTestCase { try core.register( feature: FeatureMock(performanceOverride: nil) ) - var store = core.stores.values.first + let store = core.stores.values.first XCTAssertEqual(store?.storage.authorizedFilesOrchestrator.performance.maxObjectSize, UInt64(512).KB) XCTAssertEqual(store?.storage.authorizedFilesOrchestrator.performance.maxFileSize, UInt64(4).MB) try core.register( feature: FeatureMock( - name: name, performanceOverride: PerformancePresetOverride( maxFileSize: 123, maxObjectSize: 456, @@ -217,11 +216,11 @@ class DatadogCoreTests: XCTestCase { ) ) ) - feature = core.v2Features.values.first - XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.maxObjectSize, 456) - XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.maxFileSize, 123) - XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.maxFileAgeForWrite, 95) - XCTAssertEqual(feature?.storage.authorizedFilesOrchestrator.performance.minFileAgeForRead, 105) + let storage = core.stores.values.first?.storage + XCTAssertEqual(storage?.authorizedFilesOrchestrator.performance.maxObjectSize, 456) + XCTAssertEqual(storage?.authorizedFilesOrchestrator.performance.maxFileSize, 123) + XCTAssertEqual(storage?.authorizedFilesOrchestrator.performance.maxFileAgeForWrite, 95) + XCTAssertEqual(storage?.authorizedFilesOrchestrator.performance.minFileAgeForRead, 105) } func testItUpdatesTheFeatureBaggage() throws { @@ -231,7 +230,6 @@ class DatadogCoreTests: XCTestCase { directory: temporaryCoreDirectory, dateProvider: SystemDateProvider(), initialConsent: .mockRandom(), - userInfoProvider: .mockAny(), performance: .mockRandom(), httpClient: .mockAny(), encryption: nil, @@ -239,7 +237,7 @@ class DatadogCoreTests: XCTestCase { applicationVersion: .mockAny() ) defer { core.flushAndTearDown() } - try core.register(feature: FeatureMock(name: "mock")) + try core.register(feature: FeatureMock()) // When core.update(feature: "mock") { diff --git a/DatadogCore/Tests/Datadog/LoggerTests.swift b/DatadogCore/Tests/Datadog/LoggerTests.swift index e2af6f5052..85963eaede 100644 --- a/DatadogCore/Tests/Datadog/LoggerTests.swift +++ b/DatadogCore/Tests/Datadog/LoggerTests.swift @@ -619,7 +619,7 @@ class LoggerTests: XCTestCase { // given let logger = Logger.create(in: core) - RUM.enable(in: core) + RUM.enable(with: .mockAny(), in: core) RUMMonitor.shared(in: core).startView(viewController: mockView) // when @@ -652,7 +652,7 @@ class LoggerTests: XCTestCase { // given let logger = Logger.create(in: core) - RUM.enable(in: core) + RUM.enable(with: .mockAny(), in: core) RUMMonitor.shared(in: core).startView(viewController: mockView) // when @@ -691,7 +691,7 @@ class LoggerTests: XCTestCase { // given let logger = Logger.create(in: core) - RUM.enable(in: core) + RUM.enable(with: .mockAny(), in: core) RUMMonitor.shared(in: core).startView(viewController: mockView) // when @@ -726,7 +726,7 @@ class LoggerTests: XCTestCase { // given let logger = Logger.create(in: core) - RUM.enable(in: core) + RUM.enable(with: .mockAny(), in: core) RUMMonitor.shared(in: core).startView(viewController: mockView) // when diff --git a/DatadogInternal/Sources/Storage/PerformancePresetOverride.swift b/DatadogInternal/Sources/Storage/PerformancePresetOverride.swift index 187a02b32f..2005222330 100644 --- a/DatadogInternal/Sources/Storage/PerformancePresetOverride.swift +++ b/DatadogInternal/Sources/Storage/PerformancePresetOverride.swift @@ -20,27 +20,27 @@ public struct PerformancePresetOverride { /// Overrides the maximum age qualifying given file for reuse (in seconds). /// If recently used file is younger than this, it is reused - otherwise: new file is created. - let maxFileAgeForWrite: TimeInterval? + public let maxFileAgeForWrite: TimeInterval? /// Minimum age qualifying given file for upload (in seconds). /// If the file is older than this, it is uploaded (and then deleted if upload succeeded). /// It has an arbitrary offset (~0.5s) over `maxFileAgeForWrite` to ensure that no upload can start for the file being currently written. - let minFileAgeForRead: TimeInterval? + public let minFileAgeForRead: TimeInterval? /// Overrides the initial upload delay (in seconds). /// At runtime, the upload interval starts with `initialUploadDelay` and then ranges from `minUploadDelay` to `maxUploadDelay` depending /// on delivery success or failure. - let initialUploadDelay: TimeInterval? + public let initialUploadDelay: TimeInterval? /// Overrides the mininum interval of data upload (in seconds). - let minUploadDelay: TimeInterval? + public let minUploadDelay: TimeInterval? /// Overrides the maximum interval of data upload (in seconds). - let maxUploadDelay: TimeInterval? + public let maxUploadDelay: TimeInterval? /// Overrides the current interval is change on successful upload. Should be less or equal `1.0`. /// E.g: if rate is `0.1` then `delay` will be changed by `delay * 0.1`. - let uploadDelayChangeRate: Double? + public let uploadDelayChangeRate: Double? /// Initializes a new `PerformancePresetOverride` instance with the provided overrides. /// From 623a60419d74cf37e634c294ad16af3b0afb0dad Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Mon, 10 Jul 2023 19:19:59 +0200 Subject: [PATCH 84/87] Update CHANGELOG.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0dd3b3759..d37cdf074b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,6 @@ - [IMPROVEMENT] Reduce number of view updates by filtering events from payload. See [#1328][] -# 1.21.0 / 27-07-2023 # 1.21.0 / 27-06-2023 - [BUGFIX] Fix TracingUUID string format. See [#1311][] (Thanks [@changm4n][]) - [BUGFIX] Rename _Datadog_Private to DatadogPrivate. See [#1331] (Thanks [@alexfanatics][]) From 16f13adfe60be6f455ca4222b430e575b756ead7 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Tue, 11 Jul 2023 11:26:19 +0200 Subject: [PATCH 85/87] Migrate E2E Tests --- Datadog/Datadog.xcodeproj/project.pbxproj | 54 ++--- Datadog/E2ETests/E2ETests.swift | 37 ++-- Datadog/E2ETests/E2EUtils.swift | 3 +- .../E2ETests/Helpers/DatadogE2EHelpers.swift | 9 +- .../E2ETests/Helpers/LoggingE2EHelpers.swift | 12 +- Datadog/E2ETests/Helpers/RUME2EHelpers.swift | 15 +- ...s.swift => LoggerConfigurationTests.swift} | 71 +++---- Datadog/E2ETests/Logging/LoggerE2ETests.swift | 5 +- ....swift => LogsConfigurationE2ETests.swift} | 46 ++--- ...wift => LogsTrackingConsentE2ETests.swift} | 92 ++++++--- Datadog/E2ETests/NTP/KronosE2ETests.swift | 11 +- Datadog/E2ETests/RUM/RUMGlobalE2ETests.swift | 32 +-- Datadog/E2ETests/RUM/RUMMonitorE2ETests.swift | 187 +++++++++--------- .../RUM/RUMTrackingConsentE2ETests.swift | 90 ++++++--- Datadog/E2ETests/RUM/RUMUtils.swift | 19 +- Datadog/E2ETests/Tracing/SpanE2ETests.swift | 14 +- ...swift => TraceConfigurationE2ETests.swift} | 43 ++-- Datadog/E2ETests/Tracing/TracerE2ETests.swift | 14 +- 18 files changed, 433 insertions(+), 321 deletions(-) rename Datadog/E2ETests/Logging/{LoggerBuilderE2ETests.swift => LoggerConfigurationTests.swift} (78%) rename Datadog/E2ETests/Logging/{LoggingConfigurationE2ETests.swift => LogsConfigurationE2ETests.swift} (63%) rename Datadog/E2ETests/Logging/{LoggingTrackingConsentE2ETests.swift => LogsTrackingConsentE2ETests.swift} (81%) rename Datadog/E2ETests/Tracing/{TracingConfigurationE2ETests.swift => TraceConfigurationE2ETests.swift} (60%) diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index ecb6a5546e..ca748ff2e8 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -76,9 +76,9 @@ 6115299725E3BEF9004F740E /* UIKitExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6115299625E3BEF9004F740E /* UIKitExtensionsTests.swift */; }; 611720D52524D9FB00634D9E /* DDURLSessionDelegate+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611720D42524D9FB00634D9E /* DDURLSessionDelegate+objc.swift */; }; 6121627C247D220500AC5D67 /* TracingWithLoggingIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61216279247D21FE00AC5D67 /* TracingWithLoggingIntegrationTests.swift */; }; - 61216B762666DDA10089DCD1 /* LoggerBuilderE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61216B752666DDA10089DCD1 /* LoggerBuilderE2ETests.swift */; }; - 61216B7B2667A9AE0089DCD1 /* LoggingConfigurationE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61216B7A2667A9AE0089DCD1 /* LoggingConfigurationE2ETests.swift */; }; - 61216B802667C79B0089DCD1 /* LoggingTrackingConsentE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61216B7F2667C79B0089DCD1 /* LoggingTrackingConsentE2ETests.swift */; }; + 61216B762666DDA10089DCD1 /* LoggerConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61216B752666DDA10089DCD1 /* LoggerConfigurationTests.swift */; }; + 61216B7B2667A9AE0089DCD1 /* LogsConfigurationE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61216B7A2667A9AE0089DCD1 /* LogsConfigurationE2ETests.swift */; }; + 61216B802667C79B0089DCD1 /* LogsTrackingConsentE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61216B7F2667C79B0089DCD1 /* LogsTrackingConsentE2ETests.swift */; }; 61216B842667CFF70089DCD1 /* DatadogE2EHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61216B7D2667BC220089DCD1 /* DatadogE2EHelpers.swift */; }; 61216B852667CFFE0089DCD1 /* RUME2EHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61216B7826679DD20089DCD1 /* RUME2EHelpers.swift */; }; 612556B0268C8D31002BCE74 /* CrashReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 612556AF268C8D31002BCE74 /* CrashReport.swift */; }; @@ -119,7 +119,7 @@ 614798A12A45A4790095CB02 /* DatadogTrace.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D2C1A55A29C4F2DF00946C31 /* DatadogTrace.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 614798A22A45A48F0095CB02 /* DatadogTrace.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2C1A55A29C4F2DF00946C31 /* DatadogTrace.framework */; }; 614798A32A45A4980095CB02 /* DatadogTrace.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D25EE93429C4C3C300CE3839 /* DatadogTrace.framework */; }; - 6147E3B3270486920092BC9F /* TracingConfigurationE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6147E3B2270486920092BC9F /* TracingConfigurationE2ETests.swift */; }; + 6147E3B3270486920092BC9F /* TraceConfigurationE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6147E3B2270486920092BC9F /* TraceConfigurationE2ETests.swift */; }; 614B78ED296D7B63009C6B92 /* DatadogCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614B78EA296D7B63009C6B92 /* DatadogCoreTests.swift */; }; 614B78EE296D7B63009C6B92 /* DatadogCoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614B78EA296D7B63009C6B92 /* DatadogCoreTests.swift */; }; 614B78F1296D7B63009C6B92 /* LowPowerModePublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614B78EC296D7B63009C6B92 /* LowPowerModePublisherTests.swift */; }; @@ -165,10 +165,7 @@ 6199362E265BA959009D7EA8 /* E2EAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6199362D265BA959009D7EA8 /* E2EAppDelegate.swift */; }; 61993637265BA95A009D7EA8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 61993636265BA95A009D7EA8 /* Assets.xcassets */; }; 6199363A265BA95A009D7EA8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61993638265BA95A009D7EA8 /* LaunchScreen.storyboard */; }; - 61993654265BB6A6009D7EA8 /* CrashReporter.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 614ED36B260352DC00C8C519 /* CrashReporter.xcframework */; }; - 61993656265BB6A6009D7EA8 /* DatadogCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61133B82242393DE00786299 /* DatadogCore.framework */; }; 61993657265BB6A6009D7EA8 /* DatadogCore.framework in ⚙️ Embed Framework Dependencies */ = {isa = PBXBuildFile; fileRef = 61133B82242393DE00786299 /* DatadogCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 6199365A265BB6A6009D7EA8 /* DatadogCrashReporting.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61B7885425C180CB002675B5 /* DatadogCrashReporting.framework */; }; 6199365B265BB6A6009D7EA8 /* DatadogCrashReporting.framework in ⚙️ Embed Framework Dependencies */ = {isa = PBXBuildFile; fileRef = 61B7885425C180CB002675B5 /* DatadogCrashReporting.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 61993668265BBEDC009D7EA8 /* E2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61993667265BBEDC009D7EA8 /* E2ETests.swift */; }; 619A29F326E64910007D62A3 /* CrashReporter.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 614ED36B260352DC00C8C519 /* CrashReporter.xcframework */; }; @@ -698,6 +695,14 @@ D2777D9D29F6A75800FFBB40 /* TelemetryReceiverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2777D9C29F6A75800FFBB40 /* TelemetryReceiverTests.swift */; }; D2777D9E29F6A75800FFBB40 /* TelemetryReceiverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2777D9C29F6A75800FFBB40 /* TelemetryReceiverTests.swift */; }; D2790C7229DEFCF400D88DA9 /* RUMDataModelMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22743E829DEC9A9001A7EF9 /* RUMDataModelMocks.swift */; }; + D27D81C12A5D415200281CC2 /* CrashReporter.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 614ED36B260352DC00C8C519 /* CrashReporter.xcframework */; }; + D27D81C22A5D415200281CC2 /* DatadogCrashReporting.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61B7885425C180CB002675B5 /* DatadogCrashReporting.framework */; }; + D27D81C32A5D415200281CC2 /* DatadogInternal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D23039A5298D513C001A1FA3 /* DatadogInternal.framework */; }; + D27D81C42A5D415200281CC2 /* DatadogLogs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D207317C29A5226A00ECBF94 /* DatadogLogs.framework */; }; + D27D81C52A5D415200281CC2 /* DatadogRUM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29A9F3429DD84AA005C54A4 /* DatadogRUM.framework */; }; + D27D81C62A5D415200281CC2 /* DatadogTrace.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D25EE93429C4C3C300CE3839 /* DatadogTrace.framework */; }; + D27D81C72A5D415200281CC2 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; }; + D27D81C82A5D41F400281CC2 /* TestUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D257953E298ABA65008A1BE5 /* TestUtilities.framework */; }; D286626E2A43487500852CE3 /* Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = D286626D2A43487500852CE3 /* Datadog.swift */; }; D286626F2A43487500852CE3 /* Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = D286626D2A43487500852CE3 /* Datadog.swift */; }; D28F836529C9E69E00EF8EA2 /* DatadogTraceFeatureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61AD4E3924534075006E34EA /* DatadogTraceFeatureTests.swift */; }; @@ -1721,11 +1726,11 @@ 611F82022563C66100CB9BDB /* UIKitRUMViewsPredicateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitRUMViewsPredicateTests.swift; sourceTree = ""; }; 61216275247D1CD700AC5D67 /* TracingWithLoggingIntegration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingWithLoggingIntegration.swift; sourceTree = ""; }; 61216279247D21FE00AC5D67 /* TracingWithLoggingIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingWithLoggingIntegrationTests.swift; sourceTree = ""; }; - 61216B752666DDA10089DCD1 /* LoggerBuilderE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggerBuilderE2ETests.swift; sourceTree = ""; }; + 61216B752666DDA10089DCD1 /* LoggerConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggerConfigurationTests.swift; sourceTree = ""; }; 61216B7826679DD20089DCD1 /* RUME2EHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUME2EHelpers.swift; sourceTree = ""; }; - 61216B7A2667A9AE0089DCD1 /* LoggingConfigurationE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingConfigurationE2ETests.swift; sourceTree = ""; }; + 61216B7A2667A9AE0089DCD1 /* LogsConfigurationE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogsConfigurationE2ETests.swift; sourceTree = ""; }; 61216B7D2667BC220089DCD1 /* DatadogE2EHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatadogE2EHelpers.swift; sourceTree = ""; }; - 61216B7F2667C79B0089DCD1 /* LoggingTrackingConsentE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingTrackingConsentE2ETests.swift; sourceTree = ""; }; + 61216B7F2667C79B0089DCD1 /* LogsTrackingConsentE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogsTrackingConsentE2ETests.swift; sourceTree = ""; }; 6122514727FDFF82004F5AE4 /* RUMScopeDependencies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMScopeDependencies.swift; sourceTree = ""; }; 612556AF268C8D31002BCE74 /* CrashReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReport.swift; sourceTree = ""; }; 612556BA268DD9BF002BCE74 /* DDCrashReportExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDCrashReportExporter.swift; sourceTree = ""; }; @@ -1770,7 +1775,7 @@ 614798952A459AA80095CB02 /* DDTraceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDTraceTests.swift; sourceTree = ""; }; 614798982A459B2E0095CB02 /* DDTraceConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDTraceConfigurationTests.swift; sourceTree = ""; }; 6147989B2A459E2B0095CB02 /* DDTrace+apiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "DDTrace+apiTests.m"; sourceTree = ""; }; - 6147E3B2270486920092BC9F /* TracingConfigurationE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingConfigurationE2ETests.swift; sourceTree = ""; }; + 6147E3B2270486920092BC9F /* TraceConfigurationE2ETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TraceConfigurationE2ETests.swift; sourceTree = ""; }; 614872762485067300E3EBDB /* SpanTagsReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpanTagsReducer.swift; sourceTree = ""; }; 61494CB024C839460082C633 /* RUMResourceScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMResourceScope.swift; sourceTree = ""; }; 61494CB424C864680082C633 /* RUMResourceScopeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUMResourceScopeTests.swift; sourceTree = ""; }; @@ -2381,9 +2386,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 61993656265BB6A6009D7EA8 /* DatadogCore.framework in Frameworks */, - 6199365A265BB6A6009D7EA8 /* DatadogCrashReporting.framework in Frameworks */, - 61993654265BB6A6009D7EA8 /* CrashReporter.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2391,8 +2393,16 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D27D81C82A5D41F400281CC2 /* TestUtilities.framework in Frameworks */, D2303996298D50F1001A1FA3 /* XCTest.framework in Frameworks */, + D27D81C32A5D415200281CC2 /* DatadogInternal.framework in Frameworks */, D2303997298D50F1001A1FA3 /* DatadogCore.framework in Frameworks */, + D27D81C42A5D415200281CC2 /* DatadogLogs.framework in Frameworks */, + D27D81C52A5D415200281CC2 /* DatadogRUM.framework in Frameworks */, + D27D81C62A5D415200281CC2 /* DatadogTrace.framework in Frameworks */, + D27D81C22A5D415200281CC2 /* DatadogCrashReporting.framework in Frameworks */, + D27D81C12A5D415200281CC2 /* CrashReporter.xcframework in Frameworks */, + D27D81C72A5D415200281CC2 /* DatadogWebViewTracking.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3527,7 +3537,7 @@ 6187A53726FCBDD00015D94A /* Tracing */ = { isa = PBXGroup; children = ( - 6147E3B2270486920092BC9F /* TracingConfigurationE2ETests.swift */, + 6147E3B2270486920092BC9F /* TraceConfigurationE2ETests.swift */, 6187A53826FCBE240015D94A /* TracerE2ETests.swift */, 6185F4AD26FE1956001A7641 /* SpanE2ETests.swift */, ); @@ -3649,10 +3659,10 @@ 61B3BD502661224800A9BEF0 /* Logging */ = { isa = PBXGroup; children = ( - 61216B7F2667C79B0089DCD1 /* LoggingTrackingConsentE2ETests.swift */, - 61216B7A2667A9AE0089DCD1 /* LoggingConfigurationE2ETests.swift */, + 61216B7F2667C79B0089DCD1 /* LogsTrackingConsentE2ETests.swift */, + 61216B7A2667A9AE0089DCD1 /* LogsConfigurationE2ETests.swift */, 61B3BD51266128D300A9BEF0 /* LoggerE2ETests.swift */, - 61216B752666DDA10089DCD1 /* LoggerBuilderE2ETests.swift */, + 61216B752666DDA10089DCD1 /* LoggerConfigurationTests.swift */, ); path = Logging; sourceTree = ""; @@ -6542,20 +6552,20 @@ 9E5B6D30270C85AB002499B8 /* RUMUtils.swift in Sources */, 6167C7952666622800D4CF07 /* LoggingE2EHelpers.swift in Sources */, 618F984F265BC905009959F8 /* E2EConfig.swift in Sources */, - 61216B7B2667A9AE0089DCD1 /* LoggingConfigurationE2ETests.swift in Sources */, + 61216B7B2667A9AE0089DCD1 /* LogsConfigurationE2ETests.swift in Sources */, 9E5B6D32270DE9E5002499B8 /* RUMTrackingConsentE2ETests.swift in Sources */, 6187A53926FCBE240015D94A /* TracerE2ETests.swift in Sources */, 61993668265BBEDC009D7EA8 /* E2ETests.swift in Sources */, 61216B852667CFFE0089DCD1 /* RUME2EHelpers.swift in Sources */, 9E5B6D2E270C84B4002499B8 /* RUMMonitorE2ETests.swift in Sources */, - 61216B762666DDA10089DCD1 /* LoggerBuilderE2ETests.swift in Sources */, + 61216B762666DDA10089DCD1 /* LoggerConfigurationTests.swift in Sources */, 61B3BD52266128D300A9BEF0 /* LoggerE2ETests.swift in Sources */, 9E64849D27031071007CCD7B /* RUMGlobalE2ETests.swift in Sources */, 61216B842667CFF70089DCD1 /* DatadogE2EHelpers.swift in Sources */, 6167C79326665D6900D4CF07 /* E2EUtils.swift in Sources */, - 6147E3B3270486920092BC9F /* TracingConfigurationE2ETests.swift in Sources */, + 6147E3B3270486920092BC9F /* TraceConfigurationE2ETests.swift in Sources */, 6185F4AE26FE1956001A7641 /* SpanE2ETests.swift in Sources */, - 61216B802667C79B0089DCD1 /* LoggingTrackingConsentE2ETests.swift in Sources */, + 61216B802667C79B0089DCD1 /* LogsTrackingConsentE2ETests.swift in Sources */, 61D3E0EA277E0C58008BE766 /* KronosE2ETests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Datadog/E2ETests/E2ETests.swift b/Datadog/E2ETests/E2ETests.swift index aadfdf1266..71557a0eca 100644 --- a/Datadog/E2ETests/E2ETests.swift +++ b/Datadog/E2ETests/E2ETests.swift @@ -5,7 +5,12 @@ */ import XCTest -import DatadogCore +import DatadogInternal +import DatadogLogs +import DatadogTrace +import DatadogRUM + +@testable import DatadogCore /// A base class for all E2E test cases. class E2ETests: XCTestCase { @@ -18,7 +23,14 @@ class E2ETests: XCTestCase { super.setUp() deleteAllSDKData() if !skipSDKInitialization { - initializeSDK() + Datadog.initialize( + with: .e2e, + trackingConsent: .granted + ) + + Logs.enable() + Trace.enable() + RUM.enable(with: .e2e) } } @@ -47,8 +59,8 @@ class E2ETests: XCTestCase { let result = block() let stop = Date() - let performanceSpan = DatadogTracer.shared().startRootSpan(operationName: "perf_measure", startTime: start) - performanceSpan.setTag(key: DDTags.resource, value: resourceName) + let performanceSpan = Tracer.shared().startRootSpan(operationName: "perf_measure", startTime: start) + performanceSpan.setTag(key: SpanTags.resource, value: resourceName) performanceSpan.finish(at: stop) return result @@ -56,20 +68,6 @@ class E2ETests: XCTestCase { // MARK: - SDK Lifecycle - func initializeSDK( - trackingConsent: TrackingConsent = .granted, - configuration: Datadog.Configuration = Datadog.Configuration.builderUsingE2EConfig().build() - ) { - Datadog.initialize( - appContext: .init(), - trackingConsent: trackingConsent, - configuration: configuration - ) - - DatadogTracer.initialize() - Global.rum = RUMMonitor.initialize() - } - /// Sends all collected data and deinitializes the SDK. It is executed synchronously. private func sendAllDataAndDeinitializeSDK() { Datadog.flushAndDeinitialize() @@ -79,6 +77,7 @@ class E2ETests: XCTestCase { /// Deletes persisted data for all SDK features. Ensures clean start for each test. private func deleteAllSDKData() { - PersistenceHelpers.deleteAllSDKData() + let core = CoreRegistry.default as? DatadogCore + core?.stores.values.forEach { $0.storage.clearAllData() } } } diff --git a/Datadog/E2ETests/E2EUtils.swift b/Datadog/E2ETests/E2EUtils.swift index 16b2aa5ec5..3644aad260 100644 --- a/Datadog/E2ETests/E2EUtils.swift +++ b/Datadog/E2ETests/E2EUtils.swift @@ -5,7 +5,6 @@ */ import Foundation -import DatadogCore /// Collection of utilities for creating values for facets configured in "Mobile - Integration" org. struct DD { @@ -98,7 +97,7 @@ struct DD { /// Attributes added to each log event. /// /// Each attributes has a facet used in monitor to assert that events are actually delivered. - static func logAttributes(functionName: StaticString = #function) -> [AttributeKey: AttributeValue] { + static func logAttributes(functionName: StaticString = #function) -> [String: Encodable] { return [ "test_method_name": testMethodName(functionName: functionName) ] diff --git a/Datadog/E2ETests/Helpers/DatadogE2EHelpers.swift b/Datadog/E2ETests/Helpers/DatadogE2EHelpers.swift index 2ff3d2a8e4..db48bcd78d 100644 --- a/Datadog/E2ETests/Helpers/DatadogE2EHelpers.swift +++ b/Datadog/E2ETests/Helpers/DatadogE2EHelpers.swift @@ -7,11 +7,10 @@ import DatadogCore extension Datadog.Configuration { - static func builderUsingE2EConfig() -> Datadog.Configuration.Builder { - return builderUsing( - rumApplicationID: E2EConfig.readRUMApplicationID(), + static var e2e: Self { + .init( clientToken: E2EConfig.readClientToken(), - environment: E2EConfig.readEnv() - ).set(sampleTelemetry: 100) + env: E2EConfig.readEnv() + ) } } diff --git a/Datadog/E2ETests/Helpers/LoggingE2EHelpers.swift b/Datadog/E2ETests/Helpers/LoggingE2EHelpers.swift index f36d595786..08ad3a9723 100644 --- a/Datadog/E2ETests/Helpers/LoggingE2EHelpers.swift +++ b/Datadog/E2ETests/Helpers/LoggingE2EHelpers.swift @@ -4,11 +4,11 @@ * Copyright 2019-Present Datadog, Inc. */ +import DatadogLogs import TestUtilities -import DatadogCore -extension Logger { - func sendRandomLog(with attributes: [AttributeKey: AttributeValue]) { +extension LoggerProtocol { + func sendRandomLog(with attributes: [String: Encodable]) { let message: String = .mockRandom() let error: Error? = Bool.random() ? ErrorMock(.mockRandom()) : nil @@ -28,9 +28,9 @@ extension Logger { } } -extension Logger.Builder.ConsoleLogFormat { - static func random() -> Logger.Builder.ConsoleLogFormat { - let allFormats: [Logger.Builder.ConsoleLogFormat] = [ +extension Logger.Configuration.ConsoleLogFormat { + static func random() -> Logger.Configuration.ConsoleLogFormat { + let allFormats: [Logger.Configuration.ConsoleLogFormat] = [ .short, .shortWith(prefix: .mockRandom()) ] diff --git a/Datadog/E2ETests/Helpers/RUME2EHelpers.swift b/Datadog/E2ETests/Helpers/RUME2EHelpers.swift index 416d4202ea..6352b28149 100644 --- a/Datadog/E2ETests/Helpers/RUME2EHelpers.swift +++ b/Datadog/E2ETests/Helpers/RUME2EHelpers.swift @@ -4,8 +4,17 @@ * Copyright 2019-Present Datadog, Inc. */ -import DatadogCore +@testable import DatadogRUM -extension DDRUMMonitor { - var dd: RUMMonitor { self as! RUMMonitor } +extension RUMMonitorProtocol { + var dd: Monitor { self as! Monitor } +} + +extension RUM.Configuration { + static var e2e: Self { + .init( + applicationID: E2EConfig.readRUMApplicationID(), + telemetrySampleRate: 100 + ) + } } diff --git a/Datadog/E2ETests/Logging/LoggerBuilderE2ETests.swift b/Datadog/E2ETests/Logging/LoggerConfigurationTests.swift similarity index 78% rename from Datadog/E2ETests/Logging/LoggerBuilderE2ETests.swift rename to Datadog/E2ETests/Logging/LoggerConfigurationTests.swift index 0ff4617cf7..6502ba206a 100644 --- a/Datadog/E2ETests/Logging/LoggerBuilderE2ETests.swift +++ b/Datadog/E2ETests/Logging/LoggerConfigurationTests.swift @@ -5,9 +5,12 @@ */ import DatadogCore +import DatadogLogs +import DatadogRUM +import DatadogTrace -class LoggerBuilderE2ETests: E2ETests { - private var logger: Logger! // swiftlint:disable:this implicitly_unwrapped_optional +class LoggerConfigurationTests: E2ETests { + private var logger: LoggerProtocol! // swiftlint:disable:this implicitly_unwrapped_optional override func tearDown() { logger = nil @@ -16,7 +19,7 @@ class LoggerBuilderE2ETests: E2ETests { // MARK: - Common Monitors - /// - common performance monitor - measures `Logger.builder.build()` performance: + /// - common performance monitor - measures `Logger.create()` performance: /// ```apm /// $feature = logs /// $monitor_id = logs_logger_initialize_performance @@ -27,7 +30,7 @@ class LoggerBuilderE2ETests: E2ETests { // MARK: - Enabling Options - /// - api-surface: Logger.Builder.set(serviceName: String) -> Builder + /// - api-surface: Logger.Configuration(service: String) -> Builder /// /// - data monitor: /// ```logs @@ -37,13 +40,13 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_set_SERVICE_NAME() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.set(serviceName: "com.datadog.ios.nightly.custom").build() + logger = Logger.create(with: Logger.Configuration(service: "com.datadog.ios.nightly.custom")) } logger.sendRandomLog(with: DD.logAttributes()) } - /// - api-surface: Logger.Builder.set(loggerName: String) -> Builder + /// - api-surface: Logger.Configuration(name: String) -> Builder /// /// - data monitor: /// ```logs @@ -53,13 +56,13 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_set_LOGGER_NAME() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.set(loggerName: "custom_logger_name").build() + logger = Logger.create(with: Logger.Configuration(name: "custom_logger_name")) } logger.sendRandomLog(with: DD.logAttributes()) } - /// - api-surface: Logger.Builder.sendNetworkInfo(_ enabled: Bool) -> Builder + /// - api-surface: Logger.Configuration(networkInfoEnabled: Bool) -> Builder /// /// - data monitor: /// ```logs @@ -69,13 +72,13 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_SEND_NETWORK_INFO_enabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.sendNetworkInfo(true).build() + logger = Logger.create(with: Logger.Configuration(networkInfoEnabled: true)) } logger.sendRandomLog(with: DD.logAttributes()) } - /// - api-surface: Logger.Builder.sendNetworkInfo(_ enabled: Bool) -> Builder + /// - api-surface: Logger.Configuration(networkInfoEnabled: Bool) -> Builder /// /// - data monitor: /// ```logs @@ -87,7 +90,7 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_SEND_NETWORK_INFO_disabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.sendNetworkInfo(false).build() + logger = Logger.create(with: Logger.Configuration(networkInfoEnabled: false)) } logger.sendRandomLog(with: DD.logAttributes()) @@ -95,7 +98,7 @@ class LoggerBuilderE2ETests: E2ETests { // MARK: - Choosing Logs Output - /// - api-surface: Logger.Builder.sendLogsToDatadog(_ enabled: Bool) -> Builder + /// - api-surface: Logger.Configuration(remoteSampleRate: Float) -> Builder /// /// - data monitor: /// ```logs @@ -105,13 +108,13 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_SEND_LOGS_TO_DATADOG_enabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.sendLogsToDatadog(true).build() + logger = Logger.create(with: Logger.Configuration(remoteSampleRate: 100)) } logger.sendRandomLog(with: DD.logAttributes()) } - /// - api-surface: Logger.Builder.sendLogsToDatadog(_ enabled: Bool) -> Builder + /// - api-surface: Logger.Configuration(remoteSampleRate: Float) -> Builder /// /// - data monitor: /// ```logs @@ -123,13 +126,13 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_SEND_LOGS_TO_DATADOG_disabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.sendLogsToDatadog(false).build() + logger = Logger.create(with: Logger.Configuration(remoteSampleRate: 0)) } logger.sendRandomLog(with: DD.logAttributes()) } - /// - api-surface: Logger.Builder.printLogsToConsole(_ enabled: Bool, usingFormat format: ConsoleLogFormat = .short) -> Builder + /// - api-surface: Logger.Configuration(consoleLogFormat: ConsoleLogFormat) -> Builder /// /// - data monitor - as long as sending logs to Datadog is enabled (which is default), this this monitor should receive data: /// ```logs @@ -139,13 +142,13 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_PRINT_LOGS_TO_CONSOLE_enabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.printLogsToConsole(true, usingFormat: .random()).build() + logger = Logger.create(with: Logger.Configuration(consoleLogFormat: .random())) } logger.sendRandomLog(with: DD.logAttributes()) } - /// - api-surface: Logger.Builder.printLogsToConsole(_ enabled: Bool, usingFormat format: ConsoleLogFormat = .short) -> Builder + /// - api-surface: Logger.Configuration(consoleLogFormat: ConsoleLogFormat) -> Builder /// /// - data monitor - as long as sending logs to Datadog is enabled (which is default), this this monitor should receive data: /// ```logs @@ -155,7 +158,7 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_PRINT_LOGS_TO_CONSOLE_disabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.printLogsToConsole(false, usingFormat: .random()).build() + logger = Logger.create(with: Logger.Configuration(consoleLogFormat: nil)) } logger.sendRandomLog(with: DD.logAttributes()) @@ -163,7 +166,7 @@ class LoggerBuilderE2ETests: E2ETests { // MARK: - Bundling With Other Features - /// - api-surface: Logger.Builder.bundleWithRUM(_ enabled: Bool) -> Builder + /// - api-surface: Logger.Configuration(bundleWithRumEnabled: Bool) -> Builder /// /// - data monitor: /// ```logs @@ -173,17 +176,16 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_BUNDLE_WITH_RUM_enabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.bundleWithRUM(true).build() + logger = Logger.create(with: Logger.Configuration(bundleWithRumEnabled: true)) } let viewKey: String = .mockRandom() - Global.rum.startView(key: viewKey) - Global.rum.dd.flush() + RUMMonitor.shared().startView(key: viewKey) logger.sendRandomLog(with: DD.logAttributes()) - Global.rum.stopView(key: viewKey) + RUMMonitor.shared().stopView(key: viewKey) } - /// - api-surface: Logger.Builder.bundleWithRUM(_ enabled: Bool) -> Builder + /// - api-surface: Logger.Configuration(bundleWithRumEnabled: Bool) -> Builder /// /// - data monitor: /// ```logs @@ -195,19 +197,18 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_BUNDLE_WITH_RUM_disabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.bundleWithRUM(false).build() + logger = Logger.create(with: Logger.Configuration(bundleWithRumEnabled: false)) } logger.sendRandomLog(with: DD.logAttributes()) let viewKey: String = .mockRandom() - Global.rum.startView(key: viewKey) - Global.rum.dd.flush() + RUMMonitor.shared().startView(key: viewKey) logger.sendRandomLog(with: DD.logAttributes()) - Global.rum.stopView(key: viewKey) + RUMMonitor.shared().stopView(key: viewKey) } - /// - api-surface: Logger.Builder.bundleWithTrace(_ enabled: Bool) -> Builder + /// - api-surface: Logger.Configuration(bundleWithTraceEnabled: Bool) -> Builder /// /// - data monitor - unfortunately we can't assert any APM trait in this monitor, so we just check if the data comes in: /// ```logs @@ -217,17 +218,17 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_BUNDLE_WITH_TRACE_enabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.bundleWithTrace(true).build() + logger = Logger.create(with: Logger.Configuration(bundleWithTraceEnabled: true)) } - let activeSpan = DatadogTracer.shared() + let activeSpan = Tracer.shared() .startRootSpan(operationName: .mockRandom()) .setActive() logger.sendRandomLog(with: DD.logAttributes()) activeSpan.finish() } - /// - api-surface: Logger.Builder.bundleWithTrace(_ enabled: Bool) -> Builder + /// - api-surface: Logger.Configuration(bundleWithTraceEnabled: Bool) -> Builder /// /// - data monitor - unfortunately we can't assert any APM trait in this monitor, so we just check if the data comes in: /// ```logs @@ -237,10 +238,10 @@ class LoggerBuilderE2ETests: E2ETests { /// ``` func test_logs_logger_builder_BUNDLE_WITH_TRACE_disabled() { measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.bundleWithTrace(false).build() + logger = Logger.create(with: Logger.Configuration(bundleWithTraceEnabled: false)) } - let activeSpan = DatadogTracer.shared() + let activeSpan = Tracer.shared() .startRootSpan(operationName: .mockRandom()) .setActive() logger.sendRandomLog(with: DD.logAttributes()) diff --git a/Datadog/E2ETests/Logging/LoggerE2ETests.swift b/Datadog/E2ETests/Logging/LoggerE2ETests.swift index 21addf9b44..e6faf31031 100644 --- a/Datadog/E2ETests/Logging/LoggerE2ETests.swift +++ b/Datadog/E2ETests/Logging/LoggerE2ETests.swift @@ -6,13 +6,14 @@ import TestUtilities import DatadogCore +import DatadogLogs class LoggerE2ETests: E2ETests { - private var logger: Logger! // swiftlint:disable:this implicitly_unwrapped_optional + private var logger: LoggerProtocol! // swiftlint:disable:this implicitly_unwrapped_optional override func setUp() { super.setUp() - logger = Logger.builder.build() + logger = Logger.create() } override func tearDown() { diff --git a/Datadog/E2ETests/Logging/LoggingConfigurationE2ETests.swift b/Datadog/E2ETests/Logging/LogsConfigurationE2ETests.swift similarity index 63% rename from Datadog/E2ETests/Logging/LoggingConfigurationE2ETests.swift rename to Datadog/E2ETests/Logging/LogsConfigurationE2ETests.swift index 7f3171e561..f2047b1864 100644 --- a/Datadog/E2ETests/Logging/LoggingConfigurationE2ETests.swift +++ b/Datadog/E2ETests/Logging/LogsConfigurationE2ETests.swift @@ -5,10 +5,13 @@ */ import DatadogCore +import DatadogLogs +import DatadogRUM +import DatadogTrace import DatadogCrashReporting -class LoggingConfigurationE2ETests: E2ETests { - private var logger: Logger! // swiftlint:disable:this implicitly_unwrapped_optional +class LogsConfigurationE2ETests: E2ETests { + private var logger: LoggerProtocol! // swiftlint:disable:this implicitly_unwrapped_optional override func setUp() { skipSDKInitialization = true // we will initialize it in each test @@ -20,7 +23,7 @@ class LoggingConfigurationE2ETests: E2ETests { super.tearDown() } - /// - api-surface: Datadog.Configuration.Builder.enableLogging(_ enabled: Bool) -> Builder + /// - api-surface: Logs.enable() /// /// - data monitor: /// ```logs @@ -30,25 +33,25 @@ class LoggingConfigurationE2ETests: E2ETests { /// ``` func test_logs_config_feature_enabled() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK( - trackingConsent: .granted, - configuration: Datadog.Configuration.builderUsingE2EConfig() - .enableLogging(true) - .enableTracing(true) - .enableRUM(true) - .enableCrashReporting(using: DDCrashReportingPlugin()) - .build() + Datadog.initialize( + with: .e2e, + trackingConsent: .granted ) + + Logs.enable() + Trace.enable() + RUM.enable(with: .e2e) + CrashReporting.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } logger.sendRandomLog(with: DD.logAttributes()) } - /// - api-surface: Datadog.Configuration.Builder.enableLogging(_ enabled: Bool) -> Builder + /// - api-surface: Logs.enable() /// /// - data monitor - we assert that no data is delivered in this monitor: /// ```logs @@ -60,19 +63,18 @@ class LoggingConfigurationE2ETests: E2ETests { /// ``` func test_logs_config_feature_disabled() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK( - trackingConsent: .granted, - configuration: Datadog.Configuration.builderUsingE2EConfig() - .enableLogging(false) - .enableTracing(true) - .enableRUM(true) - .enableCrashReporting(using: DDCrashReportingPlugin()) - .build() + Datadog.initialize( + with: .e2e, + trackingConsent: .granted ) + + Trace.enable() + RUM.enable(with: .e2e) + CrashReporting.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } logger.sendRandomLog(with: DD.logAttributes()) diff --git a/Datadog/E2ETests/Logging/LoggingTrackingConsentE2ETests.swift b/Datadog/E2ETests/Logging/LogsTrackingConsentE2ETests.swift similarity index 81% rename from Datadog/E2ETests/Logging/LoggingTrackingConsentE2ETests.swift rename to Datadog/E2ETests/Logging/LogsTrackingConsentE2ETests.swift index 9939660afe..312241654f 100644 --- a/Datadog/E2ETests/Logging/LoggingTrackingConsentE2ETests.swift +++ b/Datadog/E2ETests/Logging/LogsTrackingConsentE2ETests.swift @@ -5,9 +5,10 @@ */ import DatadogCore +import DatadogLogs -class LoggingTrackingConsentE2ETests: E2ETests { - private var logger: Logger! // swiftlint:disable:this implicitly_unwrapped_optional +class LogsTrackingConsentE2ETests: E2ETests { + private var logger: LoggerProtocol! // swiftlint:disable:this implicitly_unwrapped_optional override func setUp() { skipSDKInitialization = true // we will initialize it in each test @@ -32,7 +33,7 @@ class LoggingTrackingConsentE2ETests: E2ETests { // MARK: - Starting With a Consent - /// - api-surface: Datadog.initialize(appContext: AppContext,trackingConsent: TrackingConsent,configuration: Configuration) + /// - api-surface: Datadog.initialize(with : Configuration, trackingConsent: TrackingConsent) /// - api-surface: TrackingConsent.granted /// /// - data monitor: @@ -43,15 +44,20 @@ class LoggingTrackingConsentE2ETests: E2ETests { /// ``` func test_logs_config_consent_GRANTED() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .granted) + Datadog.initialize( + with: .e2e, + trackingConsent: .granted + ) + + Logs.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } logger.sendRandomLog(with: DD.logAttributes()) } - /// - api-surface: Datadog.initialize(appContext: AppContext,trackingConsent: TrackingConsent,configuration: Configuration) + /// - api-surface: Datadog.initialize(with : Configuration, trackingConsent: TrackingConsent) /// - api-surface: TrackingConsent.notGranted /// /// - data monitor - we assert that no data is delivered in this monitor: @@ -64,15 +70,20 @@ class LoggingTrackingConsentE2ETests: E2ETests { /// ``` func test_logs_config_consent_NOT_GRANTED() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .notGranted) + Datadog.initialize( + with: .e2e, + trackingConsent: .notGranted + ) + + Logs.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } logger.sendRandomLog(with: DD.logAttributes()) } - /// - api-surface: Datadog.initialize(appContext: AppContext,trackingConsent: TrackingConsent,configuration: Configuration) + /// - api-surface: Datadog.initialize(with : Configuration, trackingConsent: TrackingConsent) /// - api-surface: TrackingConsent.pending /// /// - data monitor - we assert that no data is delivered in this monitor: @@ -85,10 +96,15 @@ class LoggingTrackingConsentE2ETests: E2ETests { /// ``` func test_logs_config_consent_PENDING() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .pending) + Datadog.initialize( + with: .e2e, + trackingConsent: .pending + ) + + Logs.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } logger.sendRandomLog(with: DD.logAttributes()) } @@ -107,10 +123,15 @@ class LoggingTrackingConsentE2ETests: E2ETests { /// ``` func test_logs_config_consent_GRANTED_to_NOT_GRANTED() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .granted) + Datadog.initialize( + with: .e2e, + trackingConsent: .granted + ) + + Logs.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } measure(resourceName: DD.PerfSpanName.setTrackingConsent) { Datadog.set(trackingConsent: .notGranted) @@ -131,10 +152,15 @@ class LoggingTrackingConsentE2ETests: E2ETests { /// ``` func test_logs_config_consent_GRANTED_to_PENDING() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .granted) + Datadog.initialize( + with: .e2e, + trackingConsent: .granted + ) + + Logs.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } measure(resourceName: DD.PerfSpanName.setTrackingConsent) { Datadog.set(trackingConsent: .pending) @@ -153,10 +179,15 @@ class LoggingTrackingConsentE2ETests: E2ETests { /// ``` func test_logs_config_consent_NOT_GRANTED_to_GRANTED() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .notGranted) + Datadog.initialize( + with: .e2e, + trackingConsent: .notGranted + ) + + Logs.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } measure(resourceName: DD.PerfSpanName.setTrackingConsent) { Datadog.set(trackingConsent: .granted) @@ -177,10 +208,15 @@ class LoggingTrackingConsentE2ETests: E2ETests { /// ``` func test_logs_config_consent_NOT_GRANTED_to_PENDING() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .notGranted) + Datadog.initialize( + with: .e2e, + trackingConsent: .notGranted + ) + + Logs.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } measure(resourceName: DD.PerfSpanName.setTrackingConsent) { Datadog.set(trackingConsent: .pending) @@ -199,10 +235,15 @@ class LoggingTrackingConsentE2ETests: E2ETests { /// ``` func test_logs_config_consent_PENDING_to_GRANTED() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .pending) + Datadog.initialize( + with: .e2e, + trackingConsent: .pending + ) + + Logs.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } logger.sendRandomLog(with: DD.logAttributes()) @@ -224,10 +265,15 @@ class LoggingTrackingConsentE2ETests: E2ETests { /// ``` func test_logs_config_consent_PENDING_to_NOT_GRANTED() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .pending) + Datadog.initialize( + with: .e2e, + trackingConsent: .pending + ) + + Logs.enable() } measure(resourceName: DD.PerfSpanName.loggerInitialize) { - logger = Logger.builder.build() + logger = Logger.create() } logger.sendRandomLog(with: DD.logAttributes()) diff --git a/Datadog/E2ETests/NTP/KronosE2ETests.swift b/Datadog/E2ETests/NTP/KronosE2ETests.swift index f67002b953..63d69d1cb9 100644 --- a/Datadog/E2ETests/NTP/KronosE2ETests.swift +++ b/Datadog/E2ETests/NTP/KronosE2ETests.swift @@ -4,20 +4,21 @@ * Copyright 2019-Present Datadog, Inc. */ +import Foundation +import DatadogInternal +import DatadogLogs + @testable import DatadogCore class KronosE2ETests: E2ETests { /// The logger sending logs on Kronos execution. These logs are available in Mobile Integrations org. - private var logger: Logger! // swiftlint:disable:this implicitly_unwrapped_optional + private var logger: LoggerProtocol! // swiftlint:disable:this implicitly_unwrapped_optional /// The logger sending telemetry on internal Kronos execution. These logs are available in Mobile Integrations org. private let queue = DispatchQueue(label: "kronos-monitor-queue") override func setUp() { super.setUp() - logger = Logger - .builder - .set(loggerName: "kronos-e2e") - .build() + logger = Logger.create(with: Logger.Configuration(name: "kronos-e2e")) } override func tearDown() { diff --git a/Datadog/E2ETests/RUM/RUMGlobalE2ETests.swift b/Datadog/E2ETests/RUM/RUMGlobalE2ETests.swift index 565e3dcdab..88ed8f3f2f 100644 --- a/Datadog/E2ETests/RUM/RUMGlobalE2ETests.swift +++ b/Datadog/E2ETests/RUM/RUMGlobalE2ETests.swift @@ -6,10 +6,10 @@ import Foundation import TestUtilities -import DatadogCore +import DatadogRUM class RUMGlobalE2ETests: E2ETests { - private lazy var rum = Global.rum.dd + private var rum: RUMMonitorProtocol { RUMMonitor.shared() } // MARK: - Common Monitors @@ -31,7 +31,7 @@ class RUMGlobalE2ETests: E2ETests { // MARK: - RUM manual APIs - /// - api-surface: DDRUMMonitor.addAttribute(forKey key: AttributeKey, value: AttributeValue) + /// - api-surface: RUMMonitorProtocol.addAttribute(forKey key: AttributeKey, value: AttributeValue) /// /// - data monitor: /// ```rum @@ -56,7 +56,7 @@ class RUMGlobalE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.removeAttribute(forKey key: AttributeKey) + /// - api-surface: RUMMonitorProtocol.removeAttribute(forKey key: AttributeKey) /// /// - data monitor: /// ```rum @@ -85,7 +85,7 @@ class RUMGlobalE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addAttribute(forKey key: AttributeKey, value: AttributeValue) + /// - api-surface: RUMMonitorProtocol.addAttribute(forKey key: AttributeKey, value: AttributeValue) /// /// - data monitor: /// ```rum @@ -109,7 +109,7 @@ class RUMGlobalE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.addUserAction(type: .custom, name: actionName, attributes: DD.logAttributes()) + rum.addAction(type: .custom, name: actionName, attributes: DD.logAttributes()) Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) rum.stopView(key: viewKey, attributes: [:]) @@ -118,7 +118,7 @@ class RUMGlobalE2ETests: E2ETests { rum.removeAttribute(forKey: RUMConstants.customAttribute_Int) } - /// - api-surface: DDRUMMonitor.removeAttribute(forKey key: AttributeKey) + /// - api-surface: RUMMonitorProtocol.removeAttribute(forKey key: AttributeKey) /// /// - data monitor: /// ```rum @@ -146,13 +146,13 @@ class RUMGlobalE2ETests: E2ETests { rum.removeAttribute(forKey: RUMConstants.customAttribute_Int) } - rum.addUserAction(type: .custom, name: actionName, attributes: DD.logAttributes()) + rum.addAction(type: .custom, name: actionName, attributes: DD.logAttributes()) Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addAttribute(forKey key: AttributeKey, value: AttributeValue) + /// - api-surface: RUMMonitorProtocol.addAttribute(forKey key: AttributeKey, value: AttributeValue) /// /// - data monitor: /// ```rum @@ -176,7 +176,7 @@ class RUMGlobalE2ETests: E2ETests { rum.addAttribute(forKey: RUMConstants.customAttribute_Int, value: intAttrValue) } - rum.startResourceLoading( + rum.startResource( resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), @@ -190,7 +190,7 @@ class RUMGlobalE2ETests: E2ETests { rum.removeAttribute(forKey: RUMConstants.customAttribute_Int) } - /// - api-surface: DDRUMMonitor.removeAttribute(forKey key: AttributeKey) + /// - api-surface: RUMMonitorProtocol.removeAttribute(forKey key: AttributeKey) /// /// - data monitor: /// ```rum @@ -217,7 +217,7 @@ class RUMGlobalE2ETests: E2ETests { rum.removeAttribute(forKey: RUMConstants.customAttribute_Int) } - rum.startResourceLoading( + rum.startResource( resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), @@ -228,7 +228,7 @@ class RUMGlobalE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addAttribute(forKey key: AttributeKey, value: AttributeValue) + /// - api-surface: RUMMonitorProtocol.addAttribute(forKey key: AttributeKey, value: AttributeValue) /// /// - data monitor: /// ```rum @@ -254,8 +254,8 @@ class RUMGlobalE2ETests: E2ETests { rum.addError( message: errorMessage, - source: .source, stack: nil, + source: .source, attributes: DD.logAttributes(), file: nil, line: nil @@ -268,7 +268,7 @@ class RUMGlobalE2ETests: E2ETests { rum.removeAttribute(forKey: RUMConstants.customAttribute_Int) } - /// - api-surface: DDRUMMonitor.removeAttribute(forKey key: AttributeKey) + /// - api-surface: RUMMonitorProtocol.removeAttribute(forKey key: AttributeKey) /// /// - data monitor: /// ```rum @@ -297,8 +297,8 @@ class RUMGlobalE2ETests: E2ETests { rum.addError( message: errorMessage, - source: .source, stack: nil, + source: .source, attributes: DD.logAttributes(), file: nil, line: nil diff --git a/Datadog/E2ETests/RUM/RUMMonitorE2ETests.swift b/Datadog/E2ETests/RUM/RUMMonitorE2ETests.swift index 5662f03d6d..b34897b0db 100644 --- a/Datadog/E2ETests/RUM/RUMMonitorE2ETests.swift +++ b/Datadog/E2ETests/RUM/RUMMonitorE2ETests.swift @@ -5,15 +5,16 @@ */ import Foundation -import DatadogCore +import TestUtilities +import DatadogRUM class RUMMonitorE2ETests: E2ETests { - private lazy var rum = Global.rum.dd + private var rum: RUMMonitorProtocol { RUMMonitor.shared() } - let actionTypePool = [RUMUserActionType.swipe, .scroll, .tap, .custom] - let nonCustomActionTypePool = [RUMUserActionType.swipe, .scroll, .tap] + let actionTypePool = [RUMActionType.swipe, .scroll, .tap, .custom] + let nonCustomActionTypePool = [RUMActionType.swipe, .scroll, .tap] - /// - api-surface: DDRUMMonitor.startView(key: String,name: String? = nil,attributes: [AttributeKey: AttributeValue] = [:]) + /// - api-surface: RUMMonitorProtocol.startView(key: String,name: String? = nil,attributes: [AttributeKey: AttributeValue] = [:]) /// /// - data monitor: /// ```rum @@ -41,7 +42,7 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.stopView(key: String,attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.stopView(key: String,attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -69,7 +70,7 @@ class RUMMonitorE2ETests: E2ETests { } } - /// - api-surface: DDRUMMonitor.stopView(key: String,attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.stopView(key: String,attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -92,16 +93,16 @@ class RUMMonitorE2ETests: E2ETests { let resourceKey = String.mockRandom() rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.startResourceLoading(resourceKey: resourceKey, httpMethod: .get, urlString: resourceKey, attributes: DD.logAttributes()) + rum.startResource(resourceKey: resourceKey, httpMethod: .get, urlString: resourceKey, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { rum.stopView(key: viewKey, attributes: [:]) } - rum.stopResourceLoading(resourceKey: resourceKey, statusCode: (200...500).randomElement()!, kind: .other) + rum.stopResource(resourceKey: resourceKey, statusCode: (200...500).randomElement()!, kind: .other) } - /// - api-surface: DDRUMMonitor.stopView(key: String,attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.stopView(key: String,attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -125,16 +126,16 @@ class RUMMonitorE2ETests: E2ETests { let actionType = actionTypePool.randomElement()! rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.startUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.startAction(type: actionType, name: actionName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { rum.stopView(key: viewKey, attributes: [:]) } - rum.stopUserAction(type: actionType, name: actionName, attributes: [:]) + rum.stopAction(type: actionType, name: actionName, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addTiming(name: String) + /// - api-surface: RUMMonitorProtocol.addTiming(name: String) /// /// - data monitor: /// ```rum @@ -178,7 +179,7 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -204,14 +205,14 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.startUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.startAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -232,18 +233,18 @@ class RUMMonitorE2ETests: E2ETests { let viewKey = String.mockRandom() let viewName = String.mockRandom() let actionName = String.mockRandom() - let actionType = RUMUserActionType.custom + let actionType = RUMActionType.custom rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.startUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.startAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -269,15 +270,15 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.startUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.startAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } rum.sendRandomActionOutcomeEvent() rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) - /// - api-surface: DDRUMMonitor.stopUserAction(type: RUMUserActionType, name: String?, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.stopAction(type: RUMActionType, name: String?, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -302,9 +303,9 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.startUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.startAction(type: actionType, name: actionName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.stopUserAction(type: actionType, name: actionName, attributes: [:]) + rum.stopAction(type: actionType, name: actionName, attributes: [:]) } Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) @@ -312,8 +313,8 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) - /// - api-surface: DDRUMMonitor.stopUserAction(type: RUMUserActionType, name: String?, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.stopAction(type: RUMActionType, name: String?, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -334,13 +335,13 @@ class RUMMonitorE2ETests: E2ETests { let viewKey = String.mockRandom() let viewName = String.mockRandom() let actionName = String.mockRandom() - let actionType = RUMUserActionType.custom + let actionType = RUMActionType.custom rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.startUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.startAction(type: actionType, name: actionName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.stopUserAction(type: actionType, name: actionName, attributes: [:]) + rum.stopAction(type: actionType, name: actionName, attributes: [:]) } Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) @@ -348,8 +349,8 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) - /// - api-surface: DDRUMMonitor.stopUserAction(type: RUMUserActionType, name: String?, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.stopAction(type: RUMActionType, name: String?, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -374,9 +375,9 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.startUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.startAction(type: actionType, name: actionName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.stopUserAction(type: actionType, name: actionName, attributes: [:]) + rum.stopAction(type: actionType, name: actionName, attributes: [:]) } Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) @@ -384,7 +385,7 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.addAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -410,7 +411,7 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.addAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) @@ -418,7 +419,7 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.addAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -439,19 +440,19 @@ class RUMMonitorE2ETests: E2ETests { let viewKey = String.mockRandom() let viewName = String.mockRandom() let actionName = String.mockRandom() - let actionType = RUMUserActionType.custom + let actionType = RUMActionType.custom rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.addAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.addAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -477,7 +478,7 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.addAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } rum.sendRandomActionOutcomeEvent() Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) @@ -485,9 +486,9 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) - /// - api-surface: DDRUMMonitor.startUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) - /// - api-surface: DDRUMMonitor.stopUserAction(type: RUMUserActionType, name: String?, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.addAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.stopAction(type: RUMActionType, name: String?, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -513,19 +514,19 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.startUserAction(type: actionType, name: activeActionName, attributes: DD.logAttributes()) + rum.startAction(type: actionType, name: activeActionName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addUserAction(type: .custom, name: customActionName, attributes: DD.logAttributes()) + rum.addAction(type: .custom, name: customActionName, attributes: DD.logAttributes()) } rum.sendRandomActionOutcomeEvent() Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) - rum.stopUserAction(type: actionType, name: activeActionName, attributes: [:]) + rum.stopAction(type: actionType, name: activeActionName, attributes: [:]) rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) - /// - api-surface: DDRUMMonitor.stopUserAction(type: RUMUserActionType, name: String?, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.stopAction(type: RUMActionType, name: String?, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -547,16 +548,16 @@ class RUMMonitorE2ETests: E2ETests { let actionName = String.mockRandom() let actionType = actionTypePool.randomElement()! - rum.startUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.startAction(type: actionType, name: actionName, attributes: DD.logAttributes()) rum.sendRandomActionOutcomeEvent() Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.stopUserAction(type: actionType, name: actionName, attributes: [:]) + rum.stopAction(type: actionType, name: actionName, attributes: [:]) } } - /// - api-surface: DDRUMMonitor.addUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.addAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -579,11 +580,11 @@ class RUMMonitorE2ETests: E2ETests { let actionType = nonCustomActionTypePool.randomElement()! measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.addAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } } - /// - api-surface: DDRUMMonitor.addUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.addAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -603,15 +604,15 @@ class RUMMonitorE2ETests: E2ETests { /// ``` func test_rum_rummonitor_ignore_add_background_custom_action_with_no_outcome() { let actionName = String.mockRandom() - let actionType = RUMUserActionType.custom + let actionType = RUMActionType.custom measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.addAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) } - /// - api-surface: DDRUMMonitor.addUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.addAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -631,16 +632,16 @@ class RUMMonitorE2ETests: E2ETests { /// ``` func test_rum_rummonitor_ignore_add_background_custom_action_with_outcome() { let actionName = String.mockRandom() - let actionType = RUMUserActionType.custom + let actionType = RUMActionType.custom measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.addAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) rum.sendRandomActionOutcomeEvent() } - /// - api-surface: DDRUMMonitor.addUserAction(type: RUMUserActionType, name: String, attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.addAction(type: RUMActionType, name: String, attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -663,13 +664,13 @@ class RUMMonitorE2ETests: E2ETests { let actionType = nonCustomActionTypePool.randomElement()! measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addUserAction(type: actionType, name: actionName, attributes: DD.logAttributes()) + rum.addAction(type: actionType, name: actionName, attributes: DD.logAttributes()) } Thread.sleep(forTimeInterval: RUMConstants.actionInactivityThreshold) rum.sendRandomActionOutcomeEvent() } - /// - api-surface: DDRUMMonitor.startResourceLoading(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) + /// - api-surface: RUMMonitorProtocol.startResource(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) /// /// - data monitor: /// ```rum @@ -694,7 +695,7 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.startResourceLoading( + rum.startResource( resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), @@ -705,8 +706,8 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startResourceLoading(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) - /// - api-surface: DDRUMMonitor.stopResourceLoading(resourceKey: String,statusCode: Int?,kind: RUMResourceType,size: Int64? = nil,attributes: [AttributeKey: AttributeValue] = [:]) + /// - api-surface: RUMMonitorProtocol.startResource(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) + /// - api-surface: RUMMonitorProtocol.stopResource(resourceKey: String,statusCode: Int?,kind: RUMResourceType,size: Int64? = nil,attributes: [AttributeKey: AttributeValue] = [:]) /// /// - data monitor: /// ```rum @@ -730,21 +731,21 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.startResourceLoading( + rum.startResource( resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), attributes: DD.logAttributes() ) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.stopResourceLoading(resourceKey: resourceKey, statusCode: 200, kind: .other) + rum.stopResource(resourceKey: resourceKey, statusCode: 200, kind: .other) } rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startResourceLoading(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) - /// - api-surface: DDRUMMonitor.stopResourceLoadingWithError(resourceKey: String,errorMessage: String,response: URLResponse?,attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startResource(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) + /// - api-surface: RUMMonitorProtocol.stopResourceWithError(resourceKey: String,message: String,response: URLResponse?,attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -768,16 +769,16 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.startResourceLoading( + rum.startResource( resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), attributes: DD.logAttributes() ) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.stopResourceLoadingWithError( + rum.stopResourceWithError( resourceKey: resourceKey, - errorMessage: String.mockRandom(), + message: String.mockRandom(), response: HTTPURLResponse( url: URL.mockRandom(), statusCode: (400...511).randomElement()!, @@ -791,8 +792,8 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startResourceLoading(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) - /// - api-surface: DDRUMMonitor.stopResourceLoadingWithError(resourceKey: String,errorMessage: String,response: URLResponse?,attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startResource(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) + /// - api-surface: RUMMonitorProtocol.stopResourceWithError(resourceKey: String,message: String,response: URLResponse?,attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -816,16 +817,16 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) - rum.startResourceLoading( + rum.startResource( resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), attributes: DD.logAttributes() ) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.stopResourceLoadingWithError( + rum.stopResourceWithError( resourceKey: resourceKey, - errorMessage: String.mockRandom(), + message: String.mockRandom(), response: nil, attributes: DD.logAttributes() ) @@ -834,8 +835,8 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.startResourceLoading(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) - /// - api-surface: DDRUMMonitor.stopResourceLoading(resourceKey: String,statusCode: Int?,kind: RUMResourceType,size: Int64? = nil,attributes: [AttributeKey: AttributeValue] = [:]) + /// - api-surface: RUMMonitorProtocol.startResource(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) + /// - api-surface: RUMMonitorProtocol.stopResource(resourceKey: String,statusCode: Int?,kind: RUMResourceType,size: Int64? = nil,attributes: [AttributeKey: AttributeValue] = [:]) /// /// - data monitor: /// ```rum @@ -856,19 +857,19 @@ class RUMMonitorE2ETests: E2ETests { func test_rum_rummonitor_ignore_stop_background_resource() { let resourceKey = String.mockRandom() - rum.startResourceLoading( + rum.startResource( resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), attributes: DD.logAttributes() ) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.stopResourceLoading(resourceKey: resourceKey, statusCode: 200, kind: .other) + rum.stopResource(resourceKey: resourceKey, statusCode: 200, kind: .other) } } - /// - api-surface: DDRUMMonitor.startResourceLoading(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) - /// - api-surface: DDRUMMonitor.stopResourceLoadingWithError(resourceKey: String,errorMessage: String,response: URLResponse?,attributes: [AttributeKey: AttributeValue]) + /// - api-surface: RUMMonitorProtocol.startResource(resourceKey: String,httpMethod: RUMMethod,urlString: String,attributes: [AttributeKey: AttributeValue] = [:]) + /// - api-surface: RUMMonitorProtocol.stopResourceWithError(resourceKey: String,message: String,response: URLResponse?,attributes: [AttributeKey: AttributeValue]) /// /// - data monitor: /// ```rum @@ -889,16 +890,16 @@ class RUMMonitorE2ETests: E2ETests { func test_rum_rummonitor_ignore_stop_background_resource_with_error() { let resourceKey = String.mockRandom() - rum.startResourceLoading( + rum.startResource( resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), attributes: DD.logAttributes() ) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.stopResourceLoadingWithError( + rum.stopResourceWithError( resourceKey: resourceKey, - errorMessage: String.mockRandom(), + message: String.mockRandom(), response: HTTPURLResponse( url: URL.mockRandom(), statusCode: (400...511).randomElement()!, @@ -910,7 +911,7 @@ class RUMMonitorE2ETests: E2ETests { } } - /// - api-surface: DDRUMMonitor.addError(message: String,source: RUMErrorSource,stack: String?,attributes: [AttributeKey: AttributeValue],file: StaticString?,line: UInt?) + /// - api-surface: RUMMonitorProtocol.addError(message: String,source: RUMErrorSource,stack: String?,attributes: [AttributeKey: AttributeValue],file: StaticString?,line: UInt?) /// /// - data monitor: /// ```rum @@ -935,13 +936,13 @@ class RUMMonitorE2ETests: E2ETests { rum.startView(key: viewKey, name: viewName, attributes: DD.logAttributes()) measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addError(message: errorMessage, source: .custom, stack: nil, attributes: DD.logAttributes(), file: nil, line: nil) + rum.addError(message: errorMessage, stack: nil, source: .custom, attributes: DD.logAttributes(), file: nil, line: nil) } rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addError(message: String,source: RUMErrorSource,stack: String?,attributes: [AttributeKey: AttributeValue],file: StaticString?,line: UInt?) + /// - api-surface: RUMMonitorProtocol.addError(message: String,source: RUMErrorSource,stack: String?,attributes: [AttributeKey: AttributeValue],file: StaticString?,line: UInt?) /// /// - data monitor: /// ```rum @@ -968,8 +969,8 @@ class RUMMonitorE2ETests: E2ETests { measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { rum.addError( message: errorMessage, - source: .custom, stack: String.mockRandom(), + source: .custom, attributes: DD.logAttributes(), file: nil, line: nil @@ -979,7 +980,7 @@ class RUMMonitorE2ETests: E2ETests { rum.stopView(key: viewKey, attributes: [:]) } - /// - api-surface: DDRUMMonitor.addError(message: String,source: RUMErrorSource,stack: String?,attributes: [AttributeKey: AttributeValue],file: StaticString?,line: UInt?) + /// - api-surface: RUMMonitorProtocol.addError(message: String,source: RUMErrorSource,stack: String?,attributes: [AttributeKey: AttributeValue],file: StaticString?,line: UInt?) /// /// - data monitor: /// ```rum @@ -1001,11 +1002,11 @@ class RUMMonitorE2ETests: E2ETests { let errorMessage = String.mockRandom() measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addError(message: errorMessage, source: .custom, stack: nil, attributes: DD.logAttributes(), file: nil, line: nil) + rum.addError(message: errorMessage, stack: nil, source: .custom, attributes: DD.logAttributes(), file: nil, line: nil) } } - /// - api-surface: DDRUMMonitor.addError(message: String,source: RUMErrorSource,stack: String?,attributes: [AttributeKey: AttributeValue],file: StaticString?,line: UInt?) + /// - api-surface: RUMMonitorProtocol.addError(message: String,source: RUMErrorSource,stack: String?,attributes: [AttributeKey: AttributeValue],file: StaticString?,line: UInt?) /// /// - data monitor: /// ```rum @@ -1027,7 +1028,7 @@ class RUMMonitorE2ETests: E2ETests { let errorMessage = String.mockRandom() measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { - rum.addError(message: errorMessage, source: .custom, stack: String.mockRandom(), attributes: DD.logAttributes(), file: nil, line: nil) + rum.addError(message: errorMessage, stack: String.mockRandom(), source: .custom, attributes: DD.logAttributes(), file: nil, line: nil) } } } diff --git a/Datadog/E2ETests/RUM/RUMTrackingConsentE2ETests.swift b/Datadog/E2ETests/RUM/RUMTrackingConsentE2ETests.swift index 86a371fc88..e2820b5573 100644 --- a/Datadog/E2ETests/RUM/RUMTrackingConsentE2ETests.swift +++ b/Datadog/E2ETests/RUM/RUMTrackingConsentE2ETests.swift @@ -6,16 +6,17 @@ import Foundation import DatadogCore +import DatadogRUM class RUMTrackingConsentE2ETests: E2ETests { - private lazy var rum = Global.rum.dd + private var rum: RUMMonitorProtocol { RUMMonitor.shared() } override func setUp() { skipSDKInitialization = true // we will initialize it in each test super.setUp() } - /// - api-surface: DDRUMMonitor.initialize() -> DDRUMMonitor + /// - api-surface: RUM.enable() -> RUMMonitorProtocol /// /// - data monitor: /// ```rum @@ -25,12 +26,17 @@ class RUMTrackingConsentE2ETests: E2ETests { /// ``` func test_rum_config_consent_pending() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .pending) + Datadog.initialize( + with: .e2e, + trackingConsent: .pending + ) + + RUM.enable(with: .e2e) } - rum.dd.sendRandomRUMEvent() + rum.sendRandomRUMEvent() } - /// - api-surface: DDRUMMonitor.initialize() -> DDRUMMonitor + /// - api-surface: RUM.enable() -> RUMMonitorProtocol /// /// - data monitor: /// ```rum @@ -40,12 +46,17 @@ class RUMTrackingConsentE2ETests: E2ETests { /// ``` func test_rum_config_consent_granted() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .granted) + Datadog.initialize( + with: .e2e, + trackingConsent: .granted + ) + + RUM.enable(with: .e2e) } - rum.dd.sendRandomRUMEvent() + rum.sendRandomRUMEvent() } - /// - api-surface: DDRUMMonitor.initialize() -> DDRUMMonitor + /// - api-surface: RUM.enable() -> RUMMonitorProtocol /// /// - data monitor: /// ```rum @@ -55,12 +66,17 @@ class RUMTrackingConsentE2ETests: E2ETests { /// ``` func test_rum_config_consent_not_granted() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .notGranted) + Datadog.initialize( + with: .e2e, + trackingConsent: .notGranted + ) + + RUM.enable(with: .e2e) } - rum.dd.sendRandomRUMEvent() + rum.sendRandomRUMEvent() } - /// - api-surface: DDRUMMonitor.initialize() -> DDRUMMonitor + /// - api-surface: RUMMonitorProtocol.enable() -> RUMMonitorProtocol /// - api-surface: Datadog.set(trackingConsent: TrackingConsent) /// /// - data monitor: @@ -71,7 +87,12 @@ class RUMTrackingConsentE2ETests: E2ETests { /// ``` func test_rum_config_consent_pending_to_granted() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .pending) + Datadog.initialize( + with: .e2e, + trackingConsent: .pending + ) + + RUM.enable(with: .e2e) } rum.dd.sendRandomRUMEvent() measure(resourceName: DD.PerfSpanName.setTrackingConsent) { @@ -79,7 +100,7 @@ class RUMTrackingConsentE2ETests: E2ETests { } } - /// - api-surface: DDRUMMonitor.initialize() -> DDRUMMonitor + /// - api-surface: RUM.enable() -> RUMMonitorProtocol /// - api-surface: Datadog.set(trackingConsent: TrackingConsent) /// /// - data monitor: @@ -90,7 +111,12 @@ class RUMTrackingConsentE2ETests: E2ETests { /// ``` func test_rum_config_consent_pending_to_not_granted() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .pending) + Datadog.initialize( + with: .e2e, + trackingConsent: .pending + ) + + RUM.enable(with: .e2e) } rum.dd.sendRandomRUMEvent() measure(resourceName: DD.PerfSpanName.setTrackingConsent) { @@ -98,7 +124,7 @@ class RUMTrackingConsentE2ETests: E2ETests { } } - /// - api-surface: DDRUMMonitor.initialize() -> DDRUMMonitor + /// - api-surface: RUM.enable() -> RUMMonitorProtocol /// - api-surface: Datadog.set(trackingConsent: TrackingConsent) /// /// - data monitor: @@ -109,7 +135,12 @@ class RUMTrackingConsentE2ETests: E2ETests { /// ``` func test_rum_config_consent_granted_to_not_granted() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .granted) + Datadog.initialize( + with: .e2e, + trackingConsent: .granted + ) + + RUM.enable(with: .e2e) } rum.dd.sendRandomRUMEvent() measure(resourceName: DD.PerfSpanName.setTrackingConsent) { @@ -117,7 +148,7 @@ class RUMTrackingConsentE2ETests: E2ETests { } } - /// - api-surface: DDRUMMonitor.initialize() -> DDRUMMonitor + /// - api-surface: RUM.enable() -> RUMMonitorProtocol /// - api-surface: Datadog.set(trackingConsent: TrackingConsent) /// /// - data monitor: @@ -128,7 +159,12 @@ class RUMTrackingConsentE2ETests: E2ETests { /// ``` func test_rum_config_consent_granted_to_pending() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .granted) + Datadog.initialize( + with: .e2e, + trackingConsent: .granted + ) + + RUM.enable(with: .e2e) } rum.dd.sendRandomRUMEvent() measure(resourceName: DD.PerfSpanName.setTrackingConsent) { @@ -136,7 +172,7 @@ class RUMTrackingConsentE2ETests: E2ETests { } } - /// - api-surface: DDRUMMonitor.initialize() -> DDRUMMonitor + /// - api-surface: RUM.enable() -> RUMMonitorProtocol /// - api-surface: Datadog.set(trackingConsent: TrackingConsent) /// /// - data monitor: @@ -147,7 +183,12 @@ class RUMTrackingConsentE2ETests: E2ETests { /// ``` func test_rum_config_consent_not_granted_to_granted() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .notGranted) + Datadog.initialize( + with: .e2e, + trackingConsent: .notGranted + ) + + RUM.enable(with: .e2e) } rum.dd.sendRandomRUMEvent() measure(resourceName: DD.PerfSpanName.setTrackingConsent) { @@ -155,7 +196,7 @@ class RUMTrackingConsentE2ETests: E2ETests { } } - /// - api-surface: DDRUMMonitor.initialize() -> DDRUMMonitor + /// - api-surface: RUM.enable() -> RUMMonitorProtocol /// - api-surface: Datadog.set(trackingConsent: TrackingConsent) /// /// - data monitor: @@ -166,7 +207,12 @@ class RUMTrackingConsentE2ETests: E2ETests { /// ``` func test_rum_config_consent_not_granted_to_pending() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK(trackingConsent: .notGranted) + Datadog.initialize( + with: .e2e, + trackingConsent: .notGranted + ) + + RUM.enable(with: .e2e) } rum.dd.sendRandomRUMEvent() measure(resourceName: DD.PerfSpanName.setTrackingConsent) { diff --git a/Datadog/E2ETests/RUM/RUMUtils.swift b/Datadog/E2ETests/RUM/RUMUtils.swift index 9cf16c6b60..d32c4e953b 100644 --- a/Datadog/E2ETests/RUM/RUMUtils.swift +++ b/Datadog/E2ETests/RUM/RUMUtils.swift @@ -5,7 +5,8 @@ */ import Foundation -import DatadogCore +import DatadogRUM +import TestUtilities internal struct RUMConstants { static let customAttribute_String = "custom_attribute.string" @@ -17,7 +18,7 @@ internal struct RUMConstants { static let timingName = "custom timing" } -internal extension RUMMonitor { +internal extension RUMMonitorProtocol { func sendRandomRUMEvent() { let viewKey = String.mockRandom() let viewName = String.mockRandom() @@ -31,19 +32,19 @@ internal extension RUMMonitor { { let resourceKey = String.mockRandom() self.startView(key: viewKey, name: viewName, attributes: [:]) - self.startResourceLoading(resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), attributes: [:]) - self.stopResourceLoading(resourceKey: resourceKey, statusCode: (200...500).randomElement()!, kind: .other) + self.startResource(resourceKey: resourceKey, httpMethod: .get, urlString: String.mockRandom(), attributes: [:]) + self.stopResource(resourceKey: resourceKey, statusCode: (200...500).randomElement()!, kind: .other) self.stopView(key: viewKey, attributes: [:]) }, { self.startView(key: viewKey, name: viewName, attributes: [:]) - self.addError(message: String.mockRandom(), source: .custom, stack: String.mockRandom(), attributes: [:], file: nil, line: nil) + self.addError(message: String.mockRandom(), stack: String.mockRandom(), source: .custom, attributes: [:], file: nil, line: nil) self.stopView(key: viewKey, attributes: [:]) }, { let actionName = String.mockRandom() self.startView(key: viewKey, name: viewName, attributes: [:]) - self.addUserAction(type: [RUMUserActionType.swipe, .scroll, .tap, .custom].randomElement()!, name: actionName, attributes: [:]) + self.addAction(type: [RUMActionType.swipe, .scroll, .tap, .custom].randomElement()!, name: actionName, attributes: [:]) self.sendRandomActionOutcomeEvent() self.stopView(key: viewKey, attributes: [:]) } @@ -56,10 +57,10 @@ internal extension RUMMonitor { func sendRandomActionOutcomeEvent() { if Bool.random() { let key = String.mockRandom() - self.startResourceLoading(resourceKey: key, httpMethod: .get, urlString: key) - self.stopResourceLoading(resourceKey: key, statusCode: (200...500).randomElement()!, kind: .other) + self.startResource(resourceKey: key, httpMethod: .get, urlString: key) + self.stopResource(resourceKey: key, statusCode: (200...500).randomElement()!, kind: .other) } else { - self.addError(message: String.mockRandom(), source: .custom, stack: nil, attributes: [:], file: nil, line: nil) + self.addError(message: String.mockRandom(), stack: nil, source: .custom, attributes: [:], file: nil, line: nil) } } } diff --git a/Datadog/E2ETests/Tracing/SpanE2ETests.swift b/Datadog/E2ETests/Tracing/SpanE2ETests.swift index 002df36abb..4d9d835d29 100644 --- a/Datadog/E2ETests/Tracing/SpanE2ETests.swift +++ b/Datadog/E2ETests/Tracing/SpanE2ETests.swift @@ -4,7 +4,7 @@ * Copyright 2019-Present Datadog, Inc. */ -import DatadogCore +import DatadogTrace class SpanE2ETests: E2ETests { /// - api-surface: OTSpan.setOperationName(_ operationName: String) @@ -26,7 +26,7 @@ class SpanE2ETests: E2ETests { /// $monitor_query = "avg(last_1d):p50:trace.perf_measure{env:instrumentation,resource_name:trace_span_set_operation_name,service:com.datadog.ios.nightly} > 0.024" /// ``` func test_trace_span_set_operation_name() { - let span = DatadogTracer.shared().startSpan(operationName: .mockRandom()) + let span = Tracer.shared().startSpan(operationName: .mockRandom()) let knownOperationName = "trace_span_set_operation_name_new_operation_name" // asserted in monitor measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { @@ -55,7 +55,7 @@ class SpanE2ETests: E2ETests { /// $monitor_query = "avg(last_1d):p50:trace.perf_measure{env:instrumentation,resource_name:trace_span_set_tag,service:com.datadog.ios.nightly} > 0.024" /// ``` func test_trace_span_set_tag() { - let span = DatadogTracer.shared().startSpan(operationName: "ios_trace_span_set_tag") + let span = Tracer.shared().startSpan(operationName: "ios_trace_span_set_tag") let knownTag = DD.specialTag() measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { @@ -84,7 +84,7 @@ class SpanE2ETests: E2ETests { /// $monitor_query = "avg(last_1d):p50:trace.perf_measure{env:instrumentation,resource_name:trace_span_set_baggage_item,service:com.datadog.ios.nightly} > 0.024" /// ``` func test_trace_span_set_baggage_item() { - let span = DatadogTracer.shared().startSpan(operationName: "ios_trace_span_set_baggage_item") + let span = Tracer.shared().startSpan(operationName: "ios_trace_span_set_baggage_item") let knownTag = DD.specialTag() measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { @@ -113,7 +113,7 @@ class SpanE2ETests: E2ETests { /// $monitor_query = "avg(last_1d):p50:trace.perf_measure{env:instrumentation,resource_name:trace_span_set_active,service:com.datadog.ios.nightly} > 0.024" /// ``` func test_trace_span_set_active() { - let span = DatadogTracer.shared().startSpan(operationName: "trace_span_set_active_measured_span") + let span = Tracer.shared().startSpan(operationName: "trace_span_set_active_measured_span") measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { span.setActive() @@ -140,7 +140,7 @@ class SpanE2ETests: E2ETests { /// $monitor_query = "avg(last_1d):p50:trace.perf_measure{env:instrumentation,resource_name:trace_span_log,service:com.datadog.ios.nightly} > 0.024" /// ``` func test_trace_span_log() { - let span = DatadogTracer.shared().startSpan(operationName: "trace_span_log_measured_span") + let span = Tracer.shared().startSpan(operationName: "trace_span_log_measured_span") let log = DD.specialStringAttribute() var fields = DD.logAttributes() @@ -172,7 +172,7 @@ class SpanE2ETests: E2ETests { /// $monitor_query = "avg(last_1d):p50:trace.perf_measure{env:instrumentation,resource_name:trace_span_finish,service:com.datadog.ios.nightly} > 0.024" /// ``` func test_trace_span_finish() { - let span = DatadogTracer.shared().startSpan(operationName: "trace_span_finish_measured_span") + let span = Tracer.shared().startSpan(operationName: "trace_span_finish_measured_span") measure(resourceName: DD.PerfSpanName.fromCurrentMethodName()) { span.finish() diff --git a/Datadog/E2ETests/Tracing/TracingConfigurationE2ETests.swift b/Datadog/E2ETests/Tracing/TraceConfigurationE2ETests.swift similarity index 60% rename from Datadog/E2ETests/Tracing/TracingConfigurationE2ETests.swift rename to Datadog/E2ETests/Tracing/TraceConfigurationE2ETests.swift index 6a07b5e959..8154f59667 100644 --- a/Datadog/E2ETests/Tracing/TracingConfigurationE2ETests.swift +++ b/Datadog/E2ETests/Tracing/TraceConfigurationE2ETests.swift @@ -5,14 +5,18 @@ */ import DatadogCore +import DatadogTrace +import DatadogLogs +import DatadogRUM +import DatadogCrashReporting -class TracingConfigurationE2ETests: E2ETests { +class TraceConfigurationE2ETests: E2ETests { override func setUp() { skipSDKInitialization = true // we will initialize it in each test super.setUp() } - /// - api-surface: Datadog.Configuration.Builder.enableTracing(_ enabled: Bool) -> Builder + /// - api-surface: Trace.enable() /// /// - data monitor: /// ```apm @@ -24,21 +28,22 @@ class TracingConfigurationE2ETests: E2ETests { /// ``` func test_trace_config_feature_enabled() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK( - trackingConsent: .granted, - configuration: Datadog.Configuration.builderUsingE2EConfig() - .enableLogging(true) - .enableTracing(true) - .enableRUM(true) - .build() + Datadog.initialize( + with: .e2e, + trackingConsent: .granted ) + + Logs.enable() + Trace.enable() + RUM.enable(with: .e2e) + CrashReporting.enable() } - let span = DatadogTracer.shared().startRootSpan(operationName: "trace_config_feature_enabled_observed_span") + let span = Tracer.shared().startRootSpan(operationName: "trace_config_feature_enabled_observed_span") span.finish() } - /// - api-surface: Datadog.Configuration.Builder.enableTracing(_ enabled: Bool) -> Builder + /// - api-surface: Trace.enable() /// /// - data monitor: /// ```apm @@ -50,17 +55,17 @@ class TracingConfigurationE2ETests: E2ETests { /// ``` func test_trace_config_feature_disabled() { measure(resourceName: DD.PerfSpanName.sdkInitialize) { - initializeSDK( - trackingConsent: .granted, - configuration: Datadog.Configuration.builderUsingE2EConfig() - .enableLogging(true) - .enableTracing(true) - .enableRUM(true) - .build() + Datadog.initialize( + with: .e2e, + trackingConsent: .granted ) + + Logs.enable() + RUM.enable(with: .e2e) + CrashReporting.enable() } - let span = DatadogTracer.shared().startRootSpan(operationName: "test_trace_config_feature_disabled_observed_span") + let span = Tracer.shared().startRootSpan(operationName: "test_trace_config_feature_disabled_observed_span") span.finish() } } diff --git a/Datadog/E2ETests/Tracing/TracerE2ETests.swift b/Datadog/E2ETests/Tracing/TracerE2ETests.swift index d80f6ec7d1..4e272c1350 100644 --- a/Datadog/E2ETests/Tracing/TracerE2ETests.swift +++ b/Datadog/E2ETests/Tracing/TracerE2ETests.swift @@ -5,19 +5,11 @@ */ import DatadogCore +import DatadogInternal +import DatadogTrace class TracerE2ETests: E2ETests { - private var tracer: OTTracer! // swiftlint:disable:this implicitly_unwrapped_optional - - override func setUp() { - super.setUp() - tracer = DatadogTracer.initialize(configuration: .init()) - } - - override func tearDown() { - tracer = nil - super.tearDown() - } + private var tracer: OTTracer { Tracer.shared() } /// - api-surface: OTTracer.startSpan(operationName: String,references: [OTReference]?,tags: [String: Encodable]?,startTime: Date?) -> OTSpan /// From 02bce4cbfd54976b57357f2fccc9440c7af76105 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Tue, 11 Jul 2023 11:31:47 +0200 Subject: [PATCH 86/87] Update api-surface --- Makefile | 1 - api-surface-objc | 107 +++++++++++++++++++++++----------- api-surface-swift | 144 +++++++++++++++++++++++++++++----------------- 3 files changed, 165 insertions(+), 87 deletions(-) diff --git a/Makefile b/Makefile index 6d1dd9a2eb..fc8007211f 100644 --- a/Makefile +++ b/Makefile @@ -133,7 +133,6 @@ api-surface: --library-name DatadogLogs \ --library-name DatadogTrace \ --library-name DatadogRUM \ - --library-name DatadogSessionReplay \ --library-name DatadogCrashReporting \ --library-name DatadogWebViewTracking \ > ../../api-surface-swift && \ diff --git a/api-surface-objc b/api-surface-objc index a4a4093aa2..874866f013 100644 --- a/api-surface-objc +++ b/api-surface-objc @@ -23,13 +23,13 @@ public class DDLogs: NSObject public class DDLoggerConfiguration: NSObject @objc public var service: String? @objc public var name: String? - @objc public var sendNetworkInfo: Bool - @objc public var bundleWithRUM: Bool - @objc public var bundleWithTrace: Bool + @objc public var networkInfoEnabled: Bool + @objc public var bundleWithRumEnabled: Bool + @objc public var bundleWithTraceEnabled: Bool @objc public var remoteSampleRate: Float @objc public var printLogsToConsole: Bool @objc public var remoteLogThreshold: DDLogLevel - public init(service: String? = nil,name: String? = nil,sendNetworkInfo: Bool = false,bundleWithRUM: Bool = true,bundleWithTrace: Bool = true,remoteSampleRate: Float = 100,remoteLogThreshold: DDLogLevel = .debug,printLogsToConsole: Bool = false) + public init(service: String? = nil,name: String? = nil,networkInfoEnabled: Bool = false,bundleWithRumEnabled: Bool = true,bundleWithTraceEnabled: Bool = true,remoteSampleRate: Float = 100,remoteLogThreshold: DDLogLevel = .debug,printLogsToConsole: Bool = false) public class DDLogger: NSObject public func debug(_ message: String) public func debug(_ message: String, attributes: [String: Any]) @@ -207,8 +207,8 @@ public class DDRUMConfiguration: NSObject @objc public var uiKitViewsPredicate: DDUIKitRUMViewsPredicate? @objc public var uiKitActionsPredicate: DDUIKitRUMActionsPredicate? public func setURLSessionTracking(_ tracking: DDRUMURLSessionTracking) - @objc public var frustrationsTracking: Bool - @objc public var backgroundEventsTracking: Bool + @objc public var trackFrustrations: Bool + @objc public var trackBackgroundEvents: Bool @objc public var longTaskThreshold: TimeInterval @objc public var vitalsUpdateFrequency: DDRUMVitalsFrequency public func setViewEventMapper(_ mapper: @escaping (DDRUMViewEvent) -> DDRUMViewEvent) @@ -251,7 +251,7 @@ public class DDRUMActionEvent: NSObject @objc public var context: DDRUMActionEventRUMEventAttributes? @objc public var date: NSNumber @objc public var device: DDRUMActionEventRUMDevice? - @objc public var display: DDRUMActionEventRUMDisplay? + @objc public var display: DDRUMActionEventDisplay? @objc public var os: DDRUMActionEventRUMOperatingSystem? @objc public var service: String? @objc public var session: DDRUMActionEventSession @@ -279,6 +279,7 @@ public class DDRUMActionEventDDActionTarget: NSObject public class DDRUMActionEventDDSession: NSObject @objc public var plan: DDRUMActionEventDDSessionPlan public enum DDRUMActionEventDDSessionPlan: Int + case none case plan1 case plan2 public class DDRUMActionEventAction: NSObject @@ -358,12 +359,13 @@ public enum DDRUMActionEventRUMDeviceRUMDeviceType: Int case gamingConsole case bot case other -public class DDRUMActionEventRUMDisplay: NSObject - @objc public var viewport: DDRUMActionEventRUMDisplayViewport? -public class DDRUMActionEventRUMDisplayViewport: NSObject +public class DDRUMActionEventDisplay: NSObject + @objc public var viewport: DDRUMActionEventDisplayViewport? +public class DDRUMActionEventDisplayViewport: NSObject @objc public var height: NSNumber @objc public var width: NSNumber public class DDRUMActionEventRUMOperatingSystem: NSObject + @objc public var build: String? @objc public var name: String @objc public var version: String @objc public var versionMajor: String @@ -407,7 +409,7 @@ public class DDRUMErrorEvent: NSObject @objc public var context: DDRUMErrorEventRUMEventAttributes? @objc public var date: NSNumber @objc public var device: DDRUMErrorEventRUMDevice? - @objc public var display: DDRUMErrorEventRUMDisplay? + @objc public var display: DDRUMErrorEventDisplay? @objc public var error: DDRUMErrorEventError @objc public var featureFlags: DDRUMErrorEventFeatureFlags? @objc public var os: DDRUMErrorEventRUMOperatingSystem? @@ -426,6 +428,7 @@ public class DDRUMErrorEventDD: NSObject public class DDRUMErrorEventDDSession: NSObject @objc public var plan: DDRUMErrorEventDDSessionPlan public enum DDRUMErrorEventDDSessionPlan: Int + case none case plan1 case plan2 public class DDRUMErrorEventAction: NSObject @@ -474,13 +477,14 @@ public enum DDRUMErrorEventRUMDeviceRUMDeviceType: Int case gamingConsole case bot case other -public class DDRUMErrorEventRUMDisplay: NSObject - @objc public var viewport: DDRUMErrorEventRUMDisplayViewport? -public class DDRUMErrorEventRUMDisplayViewport: NSObject +public class DDRUMErrorEventDisplay: NSObject + @objc public var viewport: DDRUMErrorEventDisplayViewport? +public class DDRUMErrorEventDisplayViewport: NSObject @objc public var height: NSNumber @objc public var width: NSNumber public class DDRUMErrorEventError: NSObject @objc public var causes: [DDRUMErrorEventErrorCauses]? + @objc public var fingerprint: String? @objc public var handling: DDRUMErrorEventErrorHandling @objc public var handlingStack: String? @objc public var id: String? @@ -561,6 +565,7 @@ public enum DDRUMErrorEventErrorSourceType: Int public class DDRUMErrorEventFeatureFlags: NSObject @objc public var featureFlagsInfo: [String: Any] public class DDRUMErrorEventRUMOperatingSystem: NSObject + @objc public var build: String? @objc public var name: String @objc public var version: String @objc public var versionMajor: String @@ -604,7 +609,7 @@ public class DDRUMLongTaskEvent: NSObject @objc public var context: DDRUMLongTaskEventRUMEventAttributes? @objc public var date: NSNumber @objc public var device: DDRUMLongTaskEventRUMDevice? - @objc public var display: DDRUMLongTaskEventRUMDisplay? + @objc public var display: DDRUMLongTaskEventDisplay? @objc public var longTask: DDRUMLongTaskEventLongTask @objc public var os: DDRUMLongTaskEventRUMOperatingSystem? @objc public var service: String? @@ -623,6 +628,7 @@ public class DDRUMLongTaskEventDD: NSObject public class DDRUMLongTaskEventDDSession: NSObject @objc public var plan: DDRUMLongTaskEventDDSessionPlan public enum DDRUMLongTaskEventDDSessionPlan: Int + case none case plan1 case plan2 public class DDRUMLongTaskEventAction: NSObject @@ -671,9 +677,9 @@ public enum DDRUMLongTaskEventRUMDeviceRUMDeviceType: Int case gamingConsole case bot case other -public class DDRUMLongTaskEventRUMDisplay: NSObject - @objc public var viewport: DDRUMLongTaskEventRUMDisplayViewport? -public class DDRUMLongTaskEventRUMDisplayViewport: NSObject +public class DDRUMLongTaskEventDisplay: NSObject + @objc public var viewport: DDRUMLongTaskEventDisplayViewport? +public class DDRUMLongTaskEventDisplayViewport: NSObject @objc public var height: NSNumber @objc public var width: NSNumber public class DDRUMLongTaskEventLongTask: NSObject @@ -681,6 +687,7 @@ public class DDRUMLongTaskEventLongTask: NSObject @objc public var id: String? @objc public var isFrozenFrame: NSNumber? public class DDRUMLongTaskEventRUMOperatingSystem: NSObject + @objc public var build: String? @objc public var name: String @objc public var version: String @objc public var versionMajor: String @@ -723,7 +730,7 @@ public class DDRUMResourceEvent: NSObject @objc public var context: DDRUMResourceEventRUMEventAttributes? @objc public var date: NSNumber @objc public var device: DDRUMResourceEventRUMDevice? - @objc public var display: DDRUMResourceEventRUMDisplay? + @objc public var display: DDRUMResourceEventDisplay? @objc public var os: DDRUMResourceEventRUMOperatingSystem? @objc public var resource: DDRUMResourceEventResource @objc public var service: String? @@ -745,6 +752,7 @@ public class DDRUMResourceEventDD: NSObject public class DDRUMResourceEventDDSession: NSObject @objc public var plan: DDRUMResourceEventDDSessionPlan public enum DDRUMResourceEventDDSessionPlan: Int + case none case plan1 case plan2 public class DDRUMResourceEventAction: NSObject @@ -793,12 +801,13 @@ public enum DDRUMResourceEventRUMDeviceRUMDeviceType: Int case gamingConsole case bot case other -public class DDRUMResourceEventRUMDisplay: NSObject - @objc public var viewport: DDRUMResourceEventRUMDisplayViewport? -public class DDRUMResourceEventRUMDisplayViewport: NSObject +public class DDRUMResourceEventDisplay: NSObject + @objc public var viewport: DDRUMResourceEventDisplayViewport? +public class DDRUMResourceEventDisplayViewport: NSObject @objc public var height: NSNumber @objc public var width: NSNumber public class DDRUMResourceEventRUMOperatingSystem: NSObject + @objc public var build: String? @objc public var name: String @objc public var version: String @objc public var versionMajor: String @@ -806,7 +815,7 @@ public class DDRUMResourceEventResource: NSObject @objc public var connect: DDRUMResourceEventResourceConnect? @objc public var dns: DDRUMResourceEventResourceDNS? @objc public var download: DDRUMResourceEventResourceDownload? - @objc public var duration: NSNumber + @objc public var duration: NSNumber? @objc public var firstByte: DDRUMResourceEventResourceFirstByte? @objc public var id: String? @objc public var method: DDRUMResourceEventResourceRUMMethod @@ -913,9 +922,10 @@ public class DDRUMViewEvent: NSObject @objc public var context: DDRUMViewEventRUMEventAttributes? @objc public var date: NSNumber @objc public var device: DDRUMViewEventRUMDevice? - @objc public var display: DDRUMViewEventRUMDisplay? + @objc public var display: DDRUMViewEventDisplay? @objc public var featureFlags: DDRUMViewEventFeatureFlags? @objc public var os: DDRUMViewEventRUMOperatingSystem? + @objc public var privacy: DDRUMViewEventPrivacy? @objc public var service: String? @objc public var session: DDRUMViewEventSession @objc public var source: DDRUMViewEventSource @@ -928,10 +938,26 @@ public class DDRUMViewEventDD: NSObject @objc public var browserSdkVersion: String? @objc public var documentVersion: NSNumber @objc public var formatVersion: NSNumber + @objc public var pageStates: [DDRUMViewEventDDPageStates]? + @objc public var replayStats: DDRUMViewEventDDReplayStats? @objc public var session: DDRUMViewEventDDSession? +public class DDRUMViewEventDDPageStates: NSObject + @objc public var start: NSNumber + @objc public var state: DDRUMViewEventDDPageStatesState +public enum DDRUMViewEventDDPageStatesState: Int + case active + case passive + case hidden + case frozen + case terminated +public class DDRUMViewEventDDReplayStats: NSObject + @objc public var recordsCount: NSNumber? + @objc public var segmentsCount: NSNumber? + @objc public var segmentsTotalRawSize: NSNumber? public class DDRUMViewEventDDSession: NSObject @objc public var plan: DDRUMViewEventDDSessionPlan public enum DDRUMViewEventDDSessionPlan: Int + case none case plan1 case plan2 public class DDRUMViewEventApplication: NSObject @@ -975,29 +1001,43 @@ public enum DDRUMViewEventRUMDeviceRUMDeviceType: Int case gamingConsole case bot case other -public class DDRUMViewEventRUMDisplay: NSObject - @objc public var viewport: DDRUMViewEventRUMDisplayViewport? -public class DDRUMViewEventRUMDisplayViewport: NSObject +public class DDRUMViewEventDisplay: NSObject + @objc public var scroll: DDRUMViewEventDisplayScroll? + @objc public var viewport: DDRUMViewEventDisplayViewport? +public class DDRUMViewEventDisplayScroll: NSObject + @objc public var maxDepth: NSNumber + @objc public var maxDepthScrollHeight: NSNumber + @objc public var maxDepthScrollTop: NSNumber + @objc public var maxDepthTime: NSNumber +public class DDRUMViewEventDisplayViewport: NSObject @objc public var height: NSNumber @objc public var width: NSNumber public class DDRUMViewEventFeatureFlags: NSObject @objc public var featureFlagsInfo: [String: Any] public class DDRUMViewEventRUMOperatingSystem: NSObject + @objc public var build: String? @objc public var name: String @objc public var version: String @objc public var versionMajor: String +public class DDRUMViewEventPrivacy: NSObject + @objc public var replayLevel: DDRUMViewEventPrivacyReplayLevel +public enum DDRUMViewEventPrivacyReplayLevel: Int + case allow + case mask + case maskUserInput public class DDRUMViewEventSession: NSObject @objc public var hasReplay: NSNumber? @objc public var id: String @objc public var isActive: NSNumber? - @objc public var startReason: DDRUMViewEventSessionStartReason + @objc public var sampledForReplay: NSNumber? + @objc public var startPrecondition: DDRUMViewEventSessionStartPrecondition @objc public var type: DDRUMViewEventSessionSessionType -public enum DDRUMViewEventSessionStartReason: Int +public enum DDRUMViewEventSessionStartPrecondition: Int case none - case appStart + case appLaunch case inactivityTimeout case maxDuration - case stopApi + case explicitStop case backgroundEvent public enum DDRUMViewEventSessionSessionType: Int case user @@ -1219,6 +1259,7 @@ public class DDTelemetryConfigurationEventTelemetryConfiguration: NSObject @objc public var sessionReplaySampleRate: NSNumber? @objc public var sessionSampleRate: NSNumber? @objc public var silentMultipleInit: NSNumber? + @objc public var startSessionReplayRecordingManually: NSNumber? @objc public var telemetryConfigurationSampleRate: NSNumber? @objc public var telemetrySampleRate: NSNumber? @objc public var traceSampleRate: NSNumber? @@ -1274,8 +1315,8 @@ public class DDTraceConfiguration: NSObject @objc public var service: String? @objc public var tags: [String: Any]? public func setURLSessionTracking(_ tracking: DDTraceURLSessionTracking) - @objc public var bundleWithRUM: Bool - @objc public var sendNetworkInfo: Bool + @objc public var bundleWithRumEnabled: Bool + @objc public var networkInfoEnabled: Bool @objc public var customEndpoint: URL? public class DDTraceFirstPartyHostsTracing: NSObject public init(hostsWithHeaderTypes: [String: Set]) diff --git a/api-surface-swift b/api-surface-swift index 4389cff03d..8ad9b41d00 100644 --- a/api-surface-swift +++ b/api-surface-swift @@ -38,13 +38,13 @@ public struct Datadog public var bundle: Bundle public init(clientToken: String,env: String,site: DatadogSite = .us1,service: String? = nil,bundle: Bundle = .main,batchSize: BatchSize = .medium,uploadFrequency: UploadFrequency = .average,proxyConfiguration: [AnyHashable: Any]? = nil,encryption: DataEncryption? = nil,serverDateProvider: ServerDateProvider? = nil) public static var verbosityLevel: CoreLoggerLevel? = nil - public static var isInitialized: Bool + public static func isInitialized(instanceName name: String = CoreRegistry.defaultInstanceName) -> Bool public static func sdkInstance(named name: String) -> DatadogCoreProtocol public static func setUserInfo(id: String? = nil,name: String? = nil,email: String? = nil,extraInfo: [AttributeKey: AttributeValue] = [:],in core: DatadogCoreProtocol = CoreRegistry.default) public static func addUserExtraInfo(_ extraInfo: [AttributeKey: AttributeValue?],in core: DatadogCoreProtocol = CoreRegistry.default) public static func set(trackingConsent: TrackingConsent, in core: DatadogCoreProtocol = CoreRegistry.default) public static func clearAllData(in core: DatadogCoreProtocol = CoreRegistry.default) - public static func initialize(with configuration: Configuration,trackingConsent: TrackingConsent,instanceName: String = CoreRegistry.defaultInstanceName) + public static func initialize(with configuration: Configuration,trackingConsent: TrackingConsent,instanceName: String = CoreRegistry.defaultInstanceName) -> DatadogCoreProtocol # ---------------------------------- @@ -99,13 +99,13 @@ public struct Logger case shortWith(prefix: String) public var service: String? public var name: String? - public var sendNetworkInfo: Bool - public var bundleWithRUM: Bool - public var bundleWithTrace: Bool + public var networkInfoEnabled: Bool + public var bundleWithRumEnabled: Bool + public var bundleWithTraceEnabled: Bool public var remoteSampleRate: Float public var remoteLogThreshold: LogLevel public var consoleLogFormat: ConsoleLogFormat? - public init(service: String? = nil,name: String? = nil,sendNetworkInfo: Bool = false,bundleWithRUM: Bool = true,bundleWithTrace: Bool = true,remoteSampleRate: Float = 100,remoteLogThreshold: LogLevel = .debug,consoleLogFormat: ConsoleLogFormat? = nil) + public init(service: String? = nil,name: String? = nil,networkInfoEnabled: Bool = false,bundleWithRumEnabled: Bool = true,bundleWithTraceEnabled: Bool = true,remoteSampleRate: Float = 100,remoteLogThreshold: LogLevel = .debug,consoleLogFormat: ConsoleLogFormat? = nil) public static func create(with configuration: Configuration = .init(),in core: DatadogCoreProtocol = CoreRegistry.default) -> LoggerProtocol public protocol InternalLoggerProtocol func log(level: LogLevel,message: String,errorKind: String?,errorMessage: String?,stackTrace: String?,attributes: [String: Encodable]?) @@ -259,8 +259,8 @@ public struct Trace public var service: String? public var tags: [String: Encodable]? public var urlSessionTracking: URLSessionTracking? - public var bundleWithRUM: Bool - public var sendNetworkInfo: Bool + public var bundleWithRumEnabled: Bool + public var networkInfoEnabled: Bool public var eventMapper: EventMapper? public var customEndpoint: URL? public struct URLSessionTracking @@ -269,7 +269,7 @@ public struct Trace case trace(hosts: Set, sampleRate: Float = 20) case traceWithHeaders(hostsWithHeaders: [String: Set], sampleRate: Float = 20) public init(firstPartyHostsTracing: FirstPartyHostsTracing) - public init(sampleRate: Float = 100,service: String? = nil,tags: [String: Encodable]? = nil,urlSessionTracking: URLSessionTracking? = nil,bundleWithRUM: Bool = true,sendNetworkInfo: Bool = false,eventMapper: EventMapper? = nil,customEndpoint: URL? = nil) + public init(sampleRate: Float = 100,service: String? = nil,tags: [String: Encodable]? = nil,urlSessionTracking: URLSessionTracking? = nil,bundleWithRumEnabled: Bool = true,networkInfoEnabled: Bool = false,eventMapper: EventMapper? = nil,customEndpoint: URL? = nil) public enum SpanTags public static let resource = "resource.name" public class Tracer @@ -289,7 +289,7 @@ public struct RUMActionEvent: RUMDataModel public internal(set) var context: RUMEventAttributes? public let date: Int64 public let device: RUMDevice? - public let display: RUMDisplay? + public let display: Display? public let os: RUMOperatingSystem? public let service: String? public let session: Session @@ -315,7 +315,7 @@ public struct RUMActionEvent: RUMDataModel public let selector: String? public let width: Int64? public struct Session: Codable - public let plan: Plan + public let plan: Plan? public enum Plan: Int, Codable case plan1 = 1 case plan2 = 2 @@ -357,6 +357,11 @@ public struct RUMActionEvent: RUMDataModel case back = "back" public struct Application: Codable public let id: String + public struct Display: Codable + public let viewport: Viewport? + public struct Viewport: Codable + public let height: Double + public let width: Double public struct Session: Codable public let hasReplay: Bool? public let id: String @@ -391,7 +396,7 @@ public struct RUMErrorEvent: RUMDataModel public internal(set) var context: RUMEventAttributes? public let date: Int64 public let device: RUMDevice? - public let display: RUMDisplay? + public let display: Display? public var error: Error public internal(set) var featureFlags: FeatureFlags? public let os: RUMOperatingSystem? @@ -408,7 +413,7 @@ public struct RUMErrorEvent: RUMDataModel public let formatVersion: Int64 = 2 public let session: Session? public struct Session: Codable - public let plan: Plan + public let plan: Plan? public enum Plan: Int, Codable case plan1 = 1 case plan2 = 2 @@ -416,8 +421,14 @@ public struct RUMErrorEvent: RUMDataModel public let id: RUMActionID public struct Application: Codable public let id: String + public struct Display: Codable + public let viewport: Viewport? + public struct Viewport: Codable + public let height: Double + public let width: Double public struct Error: Codable public var causes: [Causes]? + public var fingerprint: String? public let handling: Handling? public let handlingStack: String? public let id: String? @@ -524,7 +535,7 @@ public struct RUMLongTaskEvent: RUMDataModel public internal(set) var context: RUMEventAttributes? public let date: Int64 public let device: RUMDevice? - public let display: RUMDisplay? + public let display: Display? public let longTask: LongTask public let os: RUMOperatingSystem? public let service: String? @@ -541,7 +552,7 @@ public struct RUMLongTaskEvent: RUMDataModel public let formatVersion: Int64 = 2 public let session: Session? public struct Session: Codable - public let plan: Plan + public let plan: Plan? public enum Plan: Int, Codable case plan1 = 1 case plan2 = 2 @@ -549,6 +560,11 @@ public struct RUMLongTaskEvent: RUMDataModel public let id: RUMActionID public struct Application: Codable public let id: String + public struct Display: Codable + public let viewport: Viewport? + public struct Viewport: Codable + public let height: Double + public let width: Double public struct LongTask: Codable public let duration: Int64 public let id: String? @@ -586,7 +602,7 @@ public struct RUMResourceEvent: RUMDataModel public internal(set) var context: RUMEventAttributes? public let date: Int64 public let device: RUMDevice? - public let display: RUMDisplay? + public let display: Display? public let os: RUMOperatingSystem? public var resource: Resource public let service: String? @@ -606,7 +622,7 @@ public struct RUMResourceEvent: RUMDataModel public let spanId: String? public let traceId: String? public struct Session: Codable - public let plan: Plan + public let plan: Plan? public enum Plan: Int, Codable case plan1 = 1 case plan2 = 2 @@ -614,11 +630,16 @@ public struct RUMResourceEvent: RUMDataModel public let id: RUMActionID public struct Application: Codable public let id: String + public struct Display: Codable + public let viewport: Viewport? + public struct Viewport: Codable + public let height: Double + public let width: Double public struct Resource: Codable public let connect: Connect? public let dns: DNS? public let download: Download? - public let duration: Int64 + public let duration: Int64? public let firstByte: FirstByte? public let id: String? public let method: RUMMethod? @@ -710,9 +731,10 @@ public struct RUMViewEvent: RUMDataModel public internal(set) var context: RUMEventAttributes? public let date: Int64 public let device: RUMDevice? - public let display: RUMDisplay? + public let display: Display? public internal(set) var featureFlags: FeatureFlags? public let os: RUMOperatingSystem? + public let privacy: Privacy? public let service: String? public let session: Session public let source: Source? @@ -725,27 +747,60 @@ public struct RUMViewEvent: RUMDataModel public let browserSdkVersion: String? public let documentVersion: Int64 public let formatVersion: Int64 = 2 + public let pageStates: [PageStates]? + public let replayStats: ReplayStats? public let session: Session? + public struct PageStates: Codable + public let start: Int64 + public let state: State + public enum State: String, Codable + case active = "active" + case passive = "passive" + case hidden = "hidden" + case frozen = "frozen" + case terminated = "terminated" + public struct ReplayStats: Codable + public let recordsCount: Int64? + public let segmentsCount: Int64? + public let segmentsTotalRawSize: Int64? public struct Session: Codable - public let plan: Plan + public let plan: Plan? public enum Plan: Int, Codable case plan1 = 1 case plan2 = 2 public struct Application: Codable public let id: String + public struct Display: Codable + public let scroll: Scroll? + public let viewport: Viewport? + public struct Scroll: Codable + public let maxDepth: Double + public let maxDepthScrollHeight: Double + public let maxDepthScrollTop: Double + public let maxDepthTime: Double + public struct Viewport: Codable + public let height: Double + public let width: Double public struct FeatureFlags: Codable public internal(set) var featureFlagsInfo: [String: Encodable] + public struct Privacy: Codable + public let replayLevel: ReplayLevel + public enum ReplayLevel: String, Codable + case allow = "allow" + case mask = "mask" + case maskUserInput = "mask-user-input" public struct Session: Codable public let hasReplay: Bool? public let id: String public let isActive: Bool? - public let startReason: StartReason? + public let sampledForReplay: Bool? + public let startPrecondition: StartPrecondition? public let type: SessionType - public enum StartReason: String, Codable - case appStart = "app_start" + public enum StartPrecondition: String, Codable + case appLaunch = "app_launch" case inactivityTimeout = "inactivity_timeout" case maxDuration = "max_duration" - case stopApi = "stop_api" + case explicitStop = "explicit_stop" case backgroundEvent = "background_event" public enum SessionType: String, Codable case user = "user" @@ -963,6 +1018,7 @@ public struct TelemetryConfigurationEvent: RUMDataModel public var sessionReplaySampleRate: Int64? public let sessionSampleRate: Int64? public let silentMultipleInit: Bool? + public var startSessionReplayRecordingManually: Bool? public let telemetryConfigurationSampleRate: Int64? public let telemetrySampleRate: Int64? public let traceSampleRate: Int64? @@ -1056,12 +1112,8 @@ public struct RUMDevice: Codable case gamingConsole = "gaming_console" case bot = "bot" case other = "other" -public struct RUMDisplay: Codable - public let viewport: Viewport? - public struct Viewport: Codable - public let height: Double - public let width: Double public struct RUMOperatingSystem: Codable + public let build: String? public let name: String public let version: String public let versionMajor: String @@ -1132,8 +1184,8 @@ public struct RUM public var uiKitViewsPredicate: UIKitRUMViewsPredicate? public var uiKitActionsPredicate: UIKitRUMActionsPredicate? public var urlSessionTracking: URLSessionTracking? - public var frustrationsTracking: Bool - public var backgroundEventsTracking: Bool + public var trackFrustrations: Bool + public var trackBackgroundEvents: Bool public var longTaskThreshold: TimeInterval? public var vitalsUpdateFrequency: VitalsFrequency? public var viewEventMapper: RUM.ViewEventMapper? @@ -1157,7 +1209,7 @@ public struct RUM case traceWithHeaders(hostsWithHeaders: [String: Set], sampleRate: Float = 20) public init(firstPartyHostsTracing: RUM.Configuration.URLSessionTracking.FirstPartyHostsTracing? = nil,resourceAttributesProvider: RUM.ResourceAttributesProvider? = nil) [?] extension RUM.Configuration - public init(applicationID: String,sessionSampleRate: Float = 100,uiKitViewsPredicate: UIKitRUMViewsPredicate? = nil,uiKitActionsPredicate: UIKitRUMActionsPredicate? = nil,urlSessionTracking: URLSessionTracking? = nil,frustrationsTracking: Bool = true,backgroundEventsTracking: Bool = false,longTaskThreshold: TimeInterval? = 0.1,vitalsUpdateFrequency: VitalsFrequency? = .average,viewEventMapper: RUM.ViewEventMapper? = nil,resourceEventMapper: RUM.ResourceEventMapper? = nil,actionEventMapper: RUM.ActionEventMapper? = nil,errorEventMapper: RUM.ErrorEventMapper? = nil,longTaskEventMapper: RUM.LongTaskEventMapper? = nil,onSessionStart: RUM.SessionListener? = nil,customEndpoint: URL? = nil,telemetrySampleRate: Float = 20) + public init(applicationID: String,sessionSampleRate: Float = 100,uiKitViewsPredicate: UIKitRUMViewsPredicate? = nil,uiKitActionsPredicate: UIKitRUMActionsPredicate? = nil,urlSessionTracking: URLSessionTracking? = nil,trackFrustrations: Bool = true,trackBackgroundEvents: Bool = false,longTaskThreshold: TimeInterval? = 0.1,vitalsUpdateFrequency: VitalsFrequency? = .average,viewEventMapper: RUM.ViewEventMapper? = nil,resourceEventMapper: RUM.ResourceEventMapper? = nil,actionEventMapper: RUM.ActionEventMapper? = nil,errorEventMapper: RUM.ErrorEventMapper? = nil,longTaskEventMapper: RUM.LongTaskEventMapper? = nil,onSessionStart: RUM.SessionListener? = nil,customEndpoint: URL? = nil,telemetrySampleRate: Float = 20) [?] extension InternalExtension where ExtendedType == RUM.Configuration public var configurationTelemetrySampleRate: Float public class RUMMonitor @@ -1229,24 +1281,6 @@ public enum PerformanceMetric case jsFrameTimeSeconds -# ---------------------------------- -# API surface for DatadogSessionReplay: -# ---------------------------------- - -public struct SessionReplay - public static func enable(with configuration: SessionReplay.Configuration, in core: DatadogCoreProtocol = CoreRegistry.default) -[?] extension SessionReplay - public struct Configuration - public var replaySampleRate: Float - public var defaultPrivacyLevel: PrivacyLevel - public enum PrivacyLevel - case allow - case mask - case maskUserInput - public var customEndpoint: URL? - public init(replaySampleRate: Float,defaultPrivacyLevel: PrivacyLevel = .mask,customEndpoint: URL? = nil) - - # ---------------------------------- # API surface for DatadogCrashReporting: # ---------------------------------- @@ -1260,6 +1294,10 @@ public static func enable() # API surface for DatadogWebViewTracking: # ---------------------------------- -public extension WKUserContentController - func startTrackingDatadogEvents(core: DatadogCoreProtocol = CoreRegistry.default, hosts: Set = []) - func stopTrackingDatadogEvents() +public enum WebViewTracking + public static func enable(webView: WKWebView,hosts: Set = [],in core: DatadogCoreProtocol = CoreRegistry.default) + public static func disable(webView: WKWebView) +[?] extension InternalExtension where ExtendedType == WebViewTracking + public class AbstractMessageEmitter + public func send(body: Any) throws + public static func messageEmitter(in core: DatadogCoreProtocol) -> AbstractMessageEmitter From 9504457a0d005bf4cc97a1974df93731646aa2e6 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 12 Jul 2023 13:48:07 +0200 Subject: [PATCH 87/87] Bumped version to 2.0.0-beta2 --- DatadogAlamofireExtension.podspec | 2 +- DatadogCore.podspec | 2 +- DatadogCore/Sources/Versioning.swift | 2 +- DatadogCrashReporting.podspec | 2 +- DatadogInternal.podspec | 2 +- DatadogLogs.podspec | 2 +- DatadogObjc.podspec | 2 +- DatadogRUM.podspec | 2 +- DatadogSDK.podspec | 2 +- DatadogSDKAlamofireExtension.podspec | 2 +- DatadogSDKCrashReporting.podspec | 2 +- DatadogSDKObjc.podspec | 2 +- DatadogSessionReplay.podspec | 2 +- DatadogTrace.podspec | 2 +- DatadogWebViewTracking.podspec | 2 +- TestUtilities.podspec | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/DatadogAlamofireExtension.podspec b/DatadogAlamofireExtension.podspec index b1cc0984b2..efa494b674 100644 --- a/DatadogAlamofireExtension.podspec +++ b/DatadogAlamofireExtension.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogAlamofireExtension" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "An Official Extensions of Datadog Swift SDK for Alamofire." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogCore.podspec b/DatadogCore.podspec index 3905adedef..e236f0caf0 100644 --- a/DatadogCore.podspec +++ b/DatadogCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogCore" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Official Datadog Swift SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogCore/Sources/Versioning.swift b/DatadogCore/Sources/Versioning.swift index e4226099bd..ddd5fcc72a 100644 --- a/DatadogCore/Sources/Versioning.swift +++ b/DatadogCore/Sources/Versioning.swift @@ -1,3 +1,3 @@ // GENERATED FILE: Do not edit directly -internal let __sdkVersion = "2.0.0-beta1" +internal let __sdkVersion = "2.0.0-beta2" diff --git a/DatadogCrashReporting.podspec b/DatadogCrashReporting.podspec index 6e081964cf..3ee964c68a 100644 --- a/DatadogCrashReporting.podspec +++ b/DatadogCrashReporting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogCrashReporting" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Official Datadog Crash Reporting SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogInternal.podspec b/DatadogInternal.podspec index 61aad4975f..06c7e13235 100644 --- a/DatadogInternal.podspec +++ b/DatadogInternal.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogInternal" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Datadog Internal Package. This module is not for public use." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogLogs.podspec b/DatadogLogs.podspec index 5b545a7122..2ca7a5c37c 100644 --- a/DatadogLogs.podspec +++ b/DatadogLogs.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogLogs" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Datadog Logs Module." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogObjc.podspec b/DatadogObjc.podspec index 5a1aedd2d4..8a250a7c82 100644 --- a/DatadogObjc.podspec +++ b/DatadogObjc.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogObjc" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Official Datadog Objective-C SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogRUM.podspec b/DatadogRUM.podspec index 453a1545d6..8a927f4402 100644 --- a/DatadogRUM.podspec +++ b/DatadogRUM.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogRUM" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Datadog Real User Monitoring Module." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSDK.podspec b/DatadogSDK.podspec index af87c7c5d9..138d69d60c 100644 --- a/DatadogSDK.podspec +++ b/DatadogSDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogSDK" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Official Datadog Swift SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSDKAlamofireExtension.podspec b/DatadogSDKAlamofireExtension.podspec index 148b68b594..2768cf4ed7 100644 --- a/DatadogSDKAlamofireExtension.podspec +++ b/DatadogSDKAlamofireExtension.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "DatadogSDKAlamofireExtension" s.module_name = "DatadogAlamofireExtension" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "An Official Extensions of Datadog Swift SDK for Alamofire." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSDKCrashReporting.podspec b/DatadogSDKCrashReporting.podspec index a44ee1002b..d1b42ebf57 100644 --- a/DatadogSDKCrashReporting.podspec +++ b/DatadogSDKCrashReporting.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "DatadogSDKCrashReporting" s.module_name = "DatadogCrashReporting" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Official Datadog Crash Reporting SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSDKObjc.podspec b/DatadogSDKObjc.podspec index 9d92a75488..79e0b289a0 100644 --- a/DatadogSDKObjc.podspec +++ b/DatadogSDKObjc.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "DatadogSDKObjc" s.module_name = "DatadogObjc" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Official Datadog Objective-C SDK for iOS." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogSessionReplay.podspec b/DatadogSessionReplay.podspec index 5ee2328ff0..6720354ae4 100644 --- a/DatadogSessionReplay.podspec +++ b/DatadogSessionReplay.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogSessionReplay" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Official Datadog Session Replay SDK for iOS. This module is currently in beta - contact Datadog to request a try." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogTrace.podspec b/DatadogTrace.podspec index f7c3d69799..3cc29b6e4c 100644 --- a/DatadogTrace.podspec +++ b/DatadogTrace.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogTrace" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Datadog Trace Module." s.homepage = "https://www.datadoghq.com" diff --git a/DatadogWebViewTracking.podspec b/DatadogWebViewTracking.podspec index e1e51d536c..6bdc1347e4 100644 --- a/DatadogWebViewTracking.podspec +++ b/DatadogWebViewTracking.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "DatadogWebViewTracking" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Datadog WebView Tracking Module." s.homepage = "https://www.datadoghq.com" diff --git a/TestUtilities.podspec b/TestUtilities.podspec index 6d1e94ca07..e98eaa2062 100644 --- a/TestUtilities.podspec +++ b/TestUtilities.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "TestUtilities" - s.version = "2.0.0-beta1" + s.version = "2.0.0-beta2" s.summary = "Datadog Testing Utilities. This module is for internal testing and should not be published." s.homepage = "https://www.datadoghq.com"