diff --git a/CHANGELOG.md b/CHANGELOG.md index b13721c3fb..c484d74363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - [BUGFIX] Do not propagate attributes from Errors and LongTasks to Views. - [IMPROVEMENT] Upgrade to PLCrashReporter 1.11.1. - [FEATURE] Report session sample rate to the backend with RUM events. See [#1410][] +- [IMPROVEMENT] Expose Session Replay to Objective-C. see [#1419][] # 2.0.0 / 31-07-2023 @@ -497,6 +498,7 @@ Release `2.0` introduces breaking changes. Follow the [Migration Guide](MIGRATIO [#1410]: https://github.com/DataDog/dd-sdk-ios/pull/1410 [#1413]: https://github.com/DataDog/dd-sdk-ios/pull/1413 [#1418]: https://github.com/DataDog/dd-sdk-ios/pull/1418 +[#1419]: https://github.com/DataDog/dd-sdk-ios/pull/1419 [@00fa9a]: https://github.com/00FA9A [@britton-earnin]: https://github.com/Britton-Earnin [@hengyu]: https://github.com/Hengyu diff --git a/Datadog/Datadog.xcodeproj/project.pbxproj b/Datadog/Datadog.xcodeproj/project.pbxproj index f609d24fcc..302552f217 100644 --- a/Datadog/Datadog.xcodeproj/project.pbxproj +++ b/Datadog/Datadog.xcodeproj/project.pbxproj @@ -185,7 +185,7 @@ 61133C00242397DA00786299 /* DatadogObjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 61133BF2242397DA00786299 /* DatadogObjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; 61133C0E2423983800786299 /* Datadog+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C092423983800786299 /* Datadog+objc.swift */; }; 61133C0F2423983800786299 /* ObjcIntercompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C0B2423983800786299 /* ObjcIntercompatibility.swift */; }; - 61133C102423983800786299 /* DDLogs+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C0C2423983800786299 /* DDLogs+objc.swift */; }; + 61133C102423983800786299 /* Logs+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C0C2423983800786299 /* Logs+objc.swift */; }; 61133C112423983800786299 /* DatadogConfiguration+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C0D2423983800786299 /* DatadogConfiguration+objc.swift */; }; 61133C482423990D00786299 /* DDDatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C142423990D00786299 /* DDDatadogTests.swift */; }; 61133C4A2423990D00786299 /* DDConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C162423990D00786299 /* DDConfigurationTests.swift */; }; @@ -262,9 +262,7 @@ 6147989C2A459E2B0095CB02 /* DDTrace+apiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6147989B2A459E2B0095CB02 /* DDTrace+apiTests.m */; }; 6147989D2A459E2B0095CB02 /* DDTrace+apiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6147989B2A459E2B0095CB02 /* DDTrace+apiTests.m */; }; 6147989E2A45A42C0095CB02 /* DatadogTrace.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D25EE93429C4C3C300CE3839 /* DatadogTrace.framework */; }; - 6147989F2A45A4500095CB02 /* DatadogTrace.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D25EE93429C4C3C300CE3839 /* DatadogTrace.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 614798A02A45A46B0095CB02 /* DatadogTrace.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2C1A55A29C4F2DF00946C31 /* DatadogTrace.framework */; }; - 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 /* TraceConfigurationE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6147E3B2270486920092BC9F /* TraceConfigurationE2ETests.swift */; }; @@ -338,9 +336,7 @@ 61A2CC242A44454D0000FF25 /* DDRUMTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A2CC232A44454D0000FF25 /* DDRUMTests.swift */; }; 61A2CC252A44454D0000FF25 /* DDRUMTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A2CC232A44454D0000FF25 /* DDRUMTests.swift */; }; 61A2CC262A4449210000FF25 /* DatadogRUM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29A9F3429DD84AA005C54A4 /* DatadogRUM.framework */; }; - 61A2CC272A4449210000FF25 /* DatadogRUM.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D29A9F3429DD84AA005C54A4 /* DatadogRUM.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 61A2CC2B2A4449300000FF25 /* DatadogRUM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D23F8E9929DDCD28001CFAE8 /* DatadogRUM.framework */; }; - 61A2CC2C2A4449300000FF25 /* DatadogRUM.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D23F8E9929DDCD28001CFAE8 /* DatadogRUM.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 61A2CC302A4449CB0000FF25 /* DatadogRUM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29A9F3429DD84AA005C54A4 /* DatadogRUM.framework */; }; 61A2CC312A4449D70000FF25 /* DatadogRUM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D23F8E9929DDCD28001CFAE8 /* DatadogRUM.framework */; }; 61A2CC322A445D8A0000FF25 /* DatadogRUM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29A9F3429DD84AA005C54A4 /* DatadogRUM.framework */; }; @@ -478,9 +474,7 @@ D20605CA2875A83D0047275C /* ContextValueReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20605C62875A77D0047275C /* ContextValueReader.swift */; }; D20605CB2875A83F0047275C /* ContextValueReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20605C62875A77D0047275C /* ContextValueReader.swift */; }; D206BB852A41CA6800F43BA2 /* DatadogLogs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D207317C29A5226A00ECBF94 /* DatadogLogs.framework */; }; - D206BB862A41CA6800F43BA2 /* DatadogLogs.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D207317C29A5226A00ECBF94 /* DatadogLogs.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D206BB8A2A41CA7000F43BA2 /* DatadogLogs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D20731B429A5279D00ECBF94 /* DatadogLogs.framework */; }; - D206BB8B2A41CA7000F43BA2 /* DatadogLogs.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D20731B429A5279D00ECBF94 /* DatadogLogs.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D207318429A5226B00ECBF94 /* DatadogLogs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D207317C29A5226A00ECBF94 /* DatadogLogs.framework */; platformFilter = ios; }; D207319529A522F600ECBF94 /* LogsFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 616F1FAF283E227100651A3A /* LogsFeature.swift */; }; D207319629A522F600ECBF94 /* ConsoleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6194E4BB2878AF7600EB6307 /* ConsoleLogger.swift */; }; @@ -1001,6 +995,10 @@ D2A1EE3F2885D7EC00D28DFB /* LaunchTimePublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE3D2885D7EC00D28DFB /* LaunchTimePublisherTests.swift */; }; D2A1EE442886B8B400D28DFB /* UserInfoPublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE432886B8B400D28DFB /* UserInfoPublisherTests.swift */; }; D2A1EE452886B8B400D28DFB /* UserInfoPublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE432886B8B400D28DFB /* UserInfoPublisherTests.swift */; }; + D2A434A22A8E3F900028E329 /* DatadogSessionReplay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6133D1F52A6ED9E100384BEF /* DatadogSessionReplay.framework */; }; + D2A434AA2A8E40A20028E329 /* SessionReplay+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A434A82A8E402B0028E329 /* SessionReplay+objc.swift */; }; + D2A434AC2A8E416F0028E329 /* DDSessionReplay+apiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D2A434AB2A8E416F0028E329 /* DDSessionReplay+apiTests.m */; }; + D2A434AE2A8E426C0028E329 /* DDSessionReplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A434AD2A8E426C0028E329 /* DDSessionReplayTests.swift */; }; D2A783D429A5309F003B03BB /* SwiftExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BBA2423979B00786299 /* SwiftExtensions.swift */; }; D2A783D529A530A0003B03BB /* SwiftExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133BBA2423979B00786299 /* SwiftExtensions.swift */; }; D2A783D929A530EF003B03BB /* SwiftExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E36D92124373EA700BFBDB7 /* SwiftExtensionsTests.swift */; }; @@ -1216,7 +1214,7 @@ D2CB6F9B27C5217A00A62B57 /* DDSpanContext+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6132BF4824A49B6800D7BD17 /* DDSpanContext+objc.swift */; }; D2CB6F9C27C5217A00A62B57 /* OTTracer+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6132BF4124A38D2400D7BD17 /* OTTracer+objc.swift */; }; D2CB6F9E27C5217A00A62B57 /* Datadog+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C092423983800786299 /* Datadog+objc.swift */; }; - D2CB6F9F27C5217A00A62B57 /* DDLogs+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C0C2423983800786299 /* DDLogs+objc.swift */; }; + D2CB6F9F27C5217A00A62B57 /* Logs+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61133C0C2423983800786299 /* Logs+objc.swift */; }; D2CB6FA027C5217A00A62B57 /* Trace+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615A4A8224A3431600233986 /* Trace+objc.swift */; }; D2CB6FA127C5217A00A62B57 /* HTTPHeadersWriter+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6132BF4B24A49C8F00D7BD17 /* HTTPHeadersWriter+objc.swift */; }; D2CB6FA227C5217A00A62B57 /* DDSpan+objc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6132BF4624A498D800D7BD17 /* DDSpan+objc.swift */; }; @@ -1687,6 +1685,13 @@ remoteGlobalIDString = D23039A4298D513C001A1FA3; remoteInfo = "DatadogInternal iOS"; }; + D2A434A42A8E3F900028E329 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 61133B79242393DE00786299 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6133D1E52A6ED9E100384BEF; + remoteInfo = "DatadogSessionReplay iOS"; + }; D2A783E229A53414003B03BB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 61133B79242393DE00786299 /* Project object */; @@ -1751,32 +1756,6 @@ name = "⚙️ Embed Framework Dependencies"; runOnlyForDeploymentPostprocessing = 0; }; - 61A2CC2A2A4449210000FF25 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 6147989F2A45A4500095CB02 /* DatadogTrace.framework in Embed Frameworks */, - 61A2CC272A4449210000FF25 /* DatadogRUM.framework in Embed Frameworks */, - D206BB862A41CA6800F43BA2 /* DatadogLogs.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; - 61A2CC2F2A4449300000FF25 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 614798A12A45A4790095CB02 /* DatadogTrace.framework in Embed Frameworks */, - 61A2CC2C2A4449300000FF25 /* DatadogRUM.framework in Embed Frameworks */, - D206BB8B2A41CA7000F43BA2 /* DatadogLogs.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; D240684527CE6C9E00C04F44 /* ⚙️ Embed Framework Dependencies */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -2013,7 +1992,7 @@ 61133BF3242397DA00786299 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61133C092423983800786299 /* Datadog+objc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Datadog+objc.swift"; sourceTree = ""; }; 61133C0B2423983800786299 /* ObjcIntercompatibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjcIntercompatibility.swift; sourceTree = ""; }; - 61133C0C2423983800786299 /* DDLogs+objc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DDLogs+objc.swift"; sourceTree = ""; }; + 61133C0C2423983800786299 /* Logs+objc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Logs+objc.swift"; sourceTree = ""; }; 61133C0D2423983800786299 /* DatadogConfiguration+objc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DatadogConfiguration+objc.swift"; sourceTree = ""; }; 61133C142423990D00786299 /* DDDatadogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DDDatadogTests.swift; sourceTree = ""; }; 61133C162423990D00786299 /* DDConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DDConfigurationTests.swift; sourceTree = ""; }; @@ -2555,6 +2534,9 @@ D2A1EE3D2885D7EC00D28DFB /* LaunchTimePublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchTimePublisherTests.swift; sourceTree = ""; }; D2A1EE432886B8B400D28DFB /* UserInfoPublisherTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserInfoPublisherTests.swift; sourceTree = ""; }; D2A38DDA29C37E1B007C6900 /* TracingURLSessionHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TracingURLSessionHandlerTests.swift; sourceTree = ""; }; + D2A434A82A8E402B0028E329 /* SessionReplay+objc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionReplay+objc.swift"; sourceTree = ""; }; + D2A434AB2A8E416F0028E329 /* DDSessionReplay+apiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "DDSessionReplay+apiTests.m"; sourceTree = ""; }; + D2A434AD2A8E426C0028E329 /* DDSessionReplayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDSessionReplayTests.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 = ""; }; D2B249932A4598FE00DD4F9F /* LoggerProtocol+Internal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoggerProtocol+Internal.swift"; sourceTree = ""; }; @@ -2665,6 +2647,7 @@ 6147989E2A45A42C0095CB02 /* DatadogTrace.framework in Frameworks */, 61A2CC262A4449210000FF25 /* DatadogRUM.framework in Frameworks */, D206BB852A41CA6800F43BA2 /* DatadogLogs.framework in Frameworks */, + D2A434A22A8E3F900028E329 /* DatadogSessionReplay.framework in Frameworks */, 61133C702423993200786299 /* DatadogCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3032,7 +3015,6 @@ isa = PBXGroup; children = ( 61054E3B2A6EE10A00AAA894 /* Feature */, - 61054E0A2A6EE10A00AAA894 /* Metrics */, 61054E482A6EE10A00AAA894 /* Processor */, 61054E0D2A6EE10A00AAA894 /* Recorder */, 61054E0C2A6EE10A00AAA894 /* SessionReplay.swift */, @@ -3051,7 +3033,6 @@ 61054F922A6EE1BA00AAA894 /* Helpers */, 61054F7D2A6EE1BA00AAA894 /* Mocks */, 61054F4E2A6EE1BA00AAA894 /* Processor */, - 61054F942A6EE1BA00AAA894 /* Public */, 61054F592A6EE1BA00AAA894 /* Recorder */, 61054F3D2A6EE1B900AAA894 /* SessionReplayConfigurationTests.swift */, 61054F482A6EE1B900AAA894 /* SessionReplayTests.swift */, @@ -3082,13 +3063,6 @@ path = Models; sourceTree = ""; }; - 61054E0A2A6EE10A00AAA894 /* Metrics */ = { - isa = PBXGroup; - children = ( - ); - path = Metrics; - sourceTree = ""; - }; 61054E0D2A6EE10A00AAA894 /* Recorder */ = { isa = PBXGroup; children = ( @@ -3530,13 +3504,6 @@ path = Helpers; sourceTree = ""; }; - 61054F942A6EE1BA00AAA894 /* Public */ = { - isa = PBXGroup; - children = ( - ); - path = Public; - sourceTree = ""; - }; 610ABD492A69309900AFEA34 /* IntegrationUnitTests */ = { isa = PBXGroup; children = ( @@ -3567,6 +3534,7 @@ 6111C58025C0080C00F5C4A2 /* RUM */ = { isa = PBXGroup; children = ( + 9E55407B25812D1C00F6E3AD /* RUM+objc.swift */, 6111C58125C0081F00F5C4A2 /* RUMDataModels+objc.swift */, ); path = RUM; @@ -3778,13 +3746,12 @@ children = ( 61133C092423983800786299 /* Datadog+objc.swift */, 61133C0D2423983800786299 /* DatadogConfiguration+objc.swift */, - 61133C0C2423983800786299 /* DDLogs+objc.swift */, - 615A4A8224A3431600233986 /* Trace+objc.swift */, 611720D42524D9FB00634D9E /* DDURLSessionDelegate+objc.swift */, - 9E55407B25812D1C00F6E3AD /* RUM+objc.swift */, + D2A434A62A8E3FEA0028E329 /* Logs */, 6132BF4524A498B400D7BD17 /* Tracing */, 6111C58025C0080C00F5C4A2 /* RUM */, 6132BF4024A38D0600D7BD17 /* OpenTracing */, + D2A434A72A8E3FFB0028E329 /* SessionReplay */, 61133C0A2423983800786299 /* ObjcIntercompatibility */, ); name = DatadogObjc; @@ -3827,6 +3794,7 @@ 61A2CC202A443D330000FF25 /* DDRUMConfigurationTests.swift */, 61A2CC232A44454D0000FF25 /* DDRUMTests.swift */, 9EE5AD8126205B82001E699E /* DDNSURLSessionDelegateTests.swift */, + D2A434AD2A8E426C0028E329 /* DDSessionReplayTests.swift */, 61D03BDE273404BB00367DE0 /* RUM */, ); path = DatadogObjc; @@ -4032,6 +4000,7 @@ 6132BF4524A498B400D7BD17 /* Tracing */ = { isa = PBXGroup; children = ( + 615A4A8224A3431600233986 /* Trace+objc.swift */, 6132BF4624A498D800D7BD17 /* DDSpan+objc.swift */, 6132BF4824A49B6800D7BD17 /* DDSpanContext+objc.swift */, 6132BF4A24A49C7200D7BD17 /* Propagation */, @@ -4592,6 +4561,7 @@ D2B3F051282E826A00C2B5EE /* DDHTTPHeadersWriter+apiTests.m */, A79B0F63292BD074008742B3 /* DDOTelHTTPHeadersWriter+apiTests.m */, A728ADAD2934EB0300397996 /* DDW3CHTTPHeadersWriter+apiTests.m */, + D2A434AB2A8E416F0028E329 /* DDSessionReplay+apiTests.m */, ); path = ObjcAPITests; sourceTree = ""; @@ -5541,6 +5511,22 @@ path = SwiftUI; sourceTree = ""; }; + D2A434A62A8E3FEA0028E329 /* Logs */ = { + isa = PBXGroup; + children = ( + 61133C0C2423983800786299 /* Logs+objc.swift */, + ); + path = Logs; + sourceTree = ""; + }; + D2A434A72A8E3FFB0028E329 /* SessionReplay */ = { + isa = PBXGroup; + children = ( + D2A434A82A8E402B0028E329 /* SessionReplay+objc.swift */, + ); + path = SessionReplay; + sourceTree = ""; + }; D2A783D329A53049003B03BB /* Utils */ = { isa = PBXGroup; children = ( @@ -5945,7 +5931,6 @@ 61133BEC242397DA00786299 /* Sources */, 61133BED242397DA00786299 /* Frameworks */, 61133BEE242397DA00786299 /* Resources */, - 61A2CC2A2A4449210000FF25 /* Embed Frameworks */, ); buildRules = ( ); @@ -5953,6 +5938,7 @@ 61133C732423993200786299 /* PBXTargetDependency */, 61A2CC292A4449210000FF25 /* PBXTargetDependency */, D206BB882A41CA6800F43BA2 /* PBXTargetDependency */, + D2A434A52A8E3F900028E329 /* PBXTargetDependency */, ); name = "DatadogObjc iOS"; productName = DatadogObjc; @@ -6488,7 +6474,6 @@ D2CB6F9727C5217A00A62B57 /* Sources */, D2CB6FA927C5217A00A62B57 /* Frameworks */, D2CB6FAB27C5217A00A62B57 /* Resources */, - 61A2CC2F2A4449300000FF25 /* Embed Frameworks */, ); buildRules = ( ); @@ -7328,6 +7313,7 @@ 618C365F248E85B400520CDE /* DateFormattingTests.swift in Sources */, 61133C5A2423990D00786299 /* FileTests.swift in Sources */, 61133C6B2423990D00786299 /* LogMatcher.swift in Sources */, + D2A434AC2A8E416F0028E329 /* DDSessionReplay+apiTests.m in Sources */, 61DB33B225DEDFC200F7EA71 /* CustomObjcViewController.m in Sources */, D2EFA875286E011900F1FAA6 /* DatadogContextProviderTests.swift in Sources */, 61363D9F24D99BAA0084CD6F /* DDErrorTests.swift in Sources */, @@ -7347,6 +7333,7 @@ 61DA8CB2286215DE0074A606 /* CryptographyTests.swift in Sources */, 615A4A8924A34FD700233986 /* DDTracerTests.swift in Sources */, 61A2CC212A443D330000FF25 /* DDRUMConfigurationTests.swift in Sources */, + D2A434AE2A8E426C0028E329 /* DDSessionReplayTests.swift in Sources */, 61D03BE0273404E700367DE0 /* RUMDataModels+objcTests.swift in Sources */, E143CCAF27D236F600F4018A /* CITestIntegrationTests.swift in Sources */, D224430D29E95D6700274EC7 /* CrashReportReceiverTests.swift in Sources */, @@ -7458,13 +7445,14 @@ A728ADAB2934EA2100397996 /* W3CHTTPHeadersWriter+objc.swift in Sources */, A79B0F66292BD7CA008742B3 /* OTelHTTPHeadersWriter+objc.swift in Sources */, 61133C0E2423983800786299 /* Datadog+objc.swift in Sources */, - 61133C102423983800786299 /* DDLogs+objc.swift in Sources */, + 61133C102423983800786299 /* Logs+objc.swift in Sources */, 615A4A8324A3431600233986 /* Trace+objc.swift in Sources */, 6132BF4C24A49C8F00D7BD17 /* HTTPHeadersWriter+objc.swift in Sources */, 6132BF4724A498D800D7BD17 /* DDSpan+objc.swift in Sources */, 615A4A8B24A3568900233986 /* OTSpan+objc.swift in Sources */, 611720D52524D9FB00634D9E /* DDURLSessionDelegate+objc.swift in Sources */, 9E55407C25812D1C00F6E3AD /* RUM+objc.swift in Sources */, + D2A434AA2A8E40A20028E329 /* SessionReplay+objc.swift in Sources */, 615A4A8D24A356A000233986 /* OTSpanContext+objc.swift in Sources */, 61133C112423983800786299 /* DatadogConfiguration+objc.swift in Sources */, ); @@ -8528,7 +8516,7 @@ A728ADAC2934EA2100397996 /* W3CHTTPHeadersWriter+objc.swift in Sources */, A79B0F67292BD7CC008742B3 /* OTelHTTPHeadersWriter+objc.swift in Sources */, D2CB6F9E27C5217A00A62B57 /* Datadog+objc.swift in Sources */, - D2CB6F9F27C5217A00A62B57 /* DDLogs+objc.swift in Sources */, + D2CB6F9F27C5217A00A62B57 /* Logs+objc.swift in Sources */, D2CB6FA027C5217A00A62B57 /* Trace+objc.swift in Sources */, D2CB6FA127C5217A00A62B57 /* HTTPHeadersWriter+objc.swift in Sources */, D2CB6FA227C5217A00A62B57 /* DDSpan+objc.swift in Sources */, @@ -8945,6 +8933,11 @@ target = D23039A4298D513C001A1FA3 /* DatadogInternal iOS */; targetProxy = D29A9F4D29DD8525005C54A4 /* PBXContainerItemProxy */; }; + D2A434A52A8E3F900028E329 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 6133D1E52A6ED9E100384BEF /* DatadogSessionReplay iOS */; + targetProxy = D2A434A42A8E3F900028E329 /* PBXContainerItemProxy */; + }; D2A783E329A53414003B03BB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D2DA2355298D57AA00C6C7E6 /* DatadogInternal tvOS */; diff --git a/DatadogCore/Tests/DatadogObjc/DDSessionReplayTests.swift b/DatadogCore/Tests/DatadogObjc/DDSessionReplayTests.swift new file mode 100644 index 0000000000..735b50ab3d --- /dev/null +++ b/DatadogCore/Tests/DatadogObjc/DDSessionReplayTests.swift @@ -0,0 +1,78 @@ +/* + * 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(iOS) + +import XCTest +import TestUtilities +import DatadogInternal + +@testable import DatadogObjc +@testable import DatadogSessionReplay + +class DDSessionReplayTests: XCTestCase { + func testDefaultConfiguration() { + // Given + let sampleRate: Float = .mockRandom(min: 0, max: 100) + + // When + let config = DDSessionReplayConfiguration(replaySampleRate: sampleRate) + + // Then + XCTAssertEqual(config._swift.replaySampleRate, sampleRate) + XCTAssertEqual(config._swift.defaultPrivacyLevel, .mask) + XCTAssertNil(config._swift.customEndpoint) + } + + func testConfigurationOverrides() { + // Given + let sampleRate: Float = .mockRandom(min: 0, max: 100) + let privacy: DDSessionReplayConfigurationPrivacyLevel = [.allow, .mask, .maskUserInput].randomElement()! + let url: URL = .mockRandom() + + // When + let config = DDSessionReplayConfiguration(replaySampleRate: 100) + config.replaySampleRate = sampleRate + config.defaultPrivacyLevel = privacy + config.customEndpoint = url + + // Then + XCTAssertEqual(config._swift.replaySampleRate, sampleRate) + XCTAssertEqual(config._swift.defaultPrivacyLevel, privacy._swift) + XCTAssertEqual(config._swift.customEndpoint, url) + } + + func testPrivacyLevelsInterop() { + XCTAssertEqual(DDSessionReplayConfigurationPrivacyLevel.allow._swift, .allow) + XCTAssertEqual(DDSessionReplayConfigurationPrivacyLevel.mask._swift, .mask) + XCTAssertEqual(DDSessionReplayConfigurationPrivacyLevel.maskUserInput._swift, .maskUserInput) + + XCTAssertEqual(DDSessionReplayConfigurationPrivacyLevel(.allow), .allow) + XCTAssertEqual(DDSessionReplayConfigurationPrivacyLevel(.mask), .mask) + XCTAssertEqual(DDSessionReplayConfigurationPrivacyLevel(.maskUserInput), .maskUserInput) + } + + func testWhenEnabled() throws { + // Given + let core = FeatureRegistrationCoreMock() + CoreRegistry.register(default: core) + defer { CoreRegistry.unregisterDefault() } + + let config = DDSessionReplayConfiguration(replaySampleRate: 42) + + // When + DDSessionReplay.enable(with: config) + + // Then + let sr = try XCTUnwrap(core.get(feature: SessionReplayFeature.self)) + let requestBuilder = try XCTUnwrap(sr.requestBuilder as? DatadogSessionReplay.RequestBuilder) + XCTAssertEqual(sr.recordingCoordinator.sampler.samplingRate, 42) + XCTAssertEqual(sr.recordingCoordinator.privacy, .mask) + XCTAssertNil(requestBuilder.customUploadURL) + } +} + +#endif diff --git a/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDSessionReplay+apiTests.m b/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDSessionReplay+apiTests.m new file mode 100644 index 0000000000..19c187969d --- /dev/null +++ b/DatadogCore/Tests/DatadogObjc/ObjcAPITests/DDSessionReplay+apiTests.m @@ -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 + +#if TARGET_OS_IOS + +@import DatadogObjc; + +@interface DDSessionReplay_apiTests : XCTestCase +@end + +@implementation DDSessionReplay_apiTests + +- (void)testConfiguration { + DDSessionReplayConfiguration *configuration = [[DDSessionReplayConfiguration alloc] initWithReplaySampleRate:100]; + configuration.defaultPrivacyLevel = DDSessionReplayConfigurationPrivacyLevelAllow; + configuration.customEndpoint = [NSURL new]; + + [DDSessionReplay enableWith:configuration]; +} + +@end + +#endif diff --git a/DatadogObjc.podspec b/DatadogObjc.podspec index e28a4056e8..8d3f278cb5 100644 --- a/DatadogObjc.podspec +++ b/DatadogObjc.podspec @@ -25,4 +25,5 @@ Pod::Spec.new do |s| s.dependency 'DatadogRUM', s.version.to_s s.dependency 'DatadogLogs', s.version.to_s s.dependency 'DatadogTrace', s.version.to_s + s.dependency 'DatadogSessionReplay', s.version.to_s end diff --git a/DatadogObjc/Sources/DDLogs+objc.swift b/DatadogObjc/Sources/Logs/Logs+objc.swift similarity index 100% rename from DatadogObjc/Sources/DDLogs+objc.swift rename to DatadogObjc/Sources/Logs/Logs+objc.swift diff --git a/DatadogObjc/Sources/RUM+objc.swift b/DatadogObjc/Sources/RUM/RUM+objc.swift similarity index 100% rename from DatadogObjc/Sources/RUM+objc.swift rename to DatadogObjc/Sources/RUM/RUM+objc.swift diff --git a/DatadogObjc/Sources/SessionReplay/SessionReplay+objc.swift b/DatadogObjc/Sources/SessionReplay/SessionReplay+objc.swift new file mode 100644 index 0000000000..65c2c1f535 --- /dev/null +++ b/DatadogObjc/Sources/SessionReplay/SessionReplay+objc.swift @@ -0,0 +1,109 @@ +/* + * 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 +#if os(iOS) +import DatadogSessionReplay + +/// An entry point to Datadog Session Replay feature. +@objc +public final class DDSessionReplay: NSObject { + override private init() { } + + /// Enables Datadog Session Replay feature. + /// + /// Recording will start automatically after enabling Session Replay. + /// + /// Note: Session Replay requires the RUM feature to be enabled. + /// + /// - Parameters: + /// - configuration: Configuration of the feature. + @objc + public static func enable(with configuration: DDSessionReplayConfiguration) { + SessionReplay.enable(with: configuration._swift) + } +} + +/// Session Replay feature configuration. +@objc +public final class DDSessionReplayConfiguration: NSObject { + internal var _swift: SessionReplay.Configuration = .init(replaySampleRate: 0) + + /// The sampling rate for Session Replay. It is applied in addition to the RUM session sample rate. + /// + /// It must be a number between 0.0 and 100.0, where 0 means no replays will be recorded + /// and 100 means all RUM sessions will contain replay. + /// + /// Note: This sample rate is applied in addition to the RUM sample rate. For example, if RUM uses a sample rate of 80% + /// and Session Replay uses a sample rate of 20%, it means that out of all user sessions, 80% will be included in RUM, + /// and within those sessions, only 20% will have replays. + @objc public var replaySampleRate: Float { + set { _swift.replaySampleRate = newValue } + get { _swift.replaySampleRate } + } + + /// Defines the way sensitive content (e.g. text) should be masked. + /// + /// Default: `.mask`. + @objc public var defaultPrivacyLevel: DDSessionReplayConfigurationPrivacyLevel { + set { _swift.defaultPrivacyLevel = newValue._swift } + get { .init(_swift.defaultPrivacyLevel) } + } + + /// Custom server url for sending replay data. + /// + /// Default: `nil`. + @objc public var customEndpoint: URL? { + set { _swift.customEndpoint = newValue } + get { _swift.customEndpoint } + } + + /// Creates Session Replay configuration. + /// + /// - Parameters: + /// - replaySampleRate: The sampling rate for Session Replay. It is applied in addition to the RUM session sample rate. + @objc + public required init( + replaySampleRate: Float + ) { + _swift = SessionReplay.Configuration( + replaySampleRate: replaySampleRate + ) + super.init() + } +} + +/// Available privacy levels for content masking. +@objc +public enum DDSessionReplayConfigurationPrivacyLevel: Int { + /// Record all content. + case allow + + /// Mask all content. + case mask + + /// Mask input elements, but record all other content. + case maskUserInput + + internal var _swift: SessionReplay.Configuration.PrivacyLevel { + switch self { + case .allow: return .allow + case .mask: return .mask + case .maskUserInput: return .maskUserInput + default: return .mask + } + } + + internal init(_ swift: SessionReplay.Configuration.PrivacyLevel) { + switch swift { + case .allow: self = .allow + case .mask: self = .mask + case .maskUserInput: self = .maskUserInput + } + } +} + +#endif diff --git a/DatadogObjc/Sources/Trace+objc.swift b/DatadogObjc/Sources/Tracing/Trace+objc.swift similarity index 100% rename from DatadogObjc/Sources/Trace+objc.swift rename to DatadogObjc/Sources/Tracing/Trace+objc.swift diff --git a/DatadogSDKObjc.podspec b/DatadogSDKObjc.podspec index d705b520b8..911df3d89e 100644 --- a/DatadogSDKObjc.podspec +++ b/DatadogSDKObjc.podspec @@ -28,4 +28,5 @@ Pod::Spec.new do |s| s.dependency 'DatadogRUM', s.version.to_s s.dependency 'DatadogLogs', s.version.to_s s.dependency 'DatadogTrace', s.version.to_s + s.dependency 'DatadogSessionReplay', s.version.to_s end diff --git a/Package.swift b/Package.swift index 38f136fb4d..0e542a9f40 100644 --- a/Package.swift +++ b/Package.swift @@ -63,6 +63,7 @@ let package = Package( .target(name: "DatadogLogs"), .target(name: "DatadogTrace"), .target(name: "DatadogRUM"), + .target(name: "DatadogSessionReplay"), ], path: "DatadogObjc/Sources" ),