diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5e067ec131..143c90cb0e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -5,6 +5,7 @@ stages:
- ui-test
- smoke-test
- e2e-test
+ - benchmark-test
- dogfood
- release-build
- release-publish
@@ -266,6 +267,24 @@ E2E Test (upload to s8s):
- export DRY_RUN=${DRY_RUN:-0} # default to 0 if not specified
- make e2e-build-upload ARTIFACTS_PATH="artifacts/e2e"
+# ┌────────────────────────────┐
+# │ Benchmark Test app upload: │
+# └────────────────────────────┘
+
+Benchmark Test (upload to s8s):
+ stage: benchmark-test
+ rules:
+ - if: '$CI_COMMIT_BRANCH == $DEVELOP_BRANCH'
+ artifacts:
+ paths:
+ - artifacts
+ expire_in: 2 weeks
+ script:
+ - ./tools/runner-setup.sh --xcode "$DEFAULT_XCODE" --datadog-ci
+ - make clean
+ - export DRY_RUN=${DRY_RUN:-0} # default to 0 if not specified
+ - make benchmark-build-upload ARTIFACTS_PATH="artifacts/benchmark"
+
# ┌─────────────────┐
# │ SDK dogfooding: │
# └─────────────────┘
diff --git a/BenchmarkTests/BenchmarkTests.xcodeproj/.xcodesamplecode.plist b/BenchmarkTests/BenchmarkTests.xcodeproj/.xcodesamplecode.plist
new file mode 100644
index 0000000000..4bc741ca64
--- /dev/null
+++ b/BenchmarkTests/BenchmarkTests.xcodeproj/.xcodesamplecode.plist
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/BenchmarkTests/BenchmarkTests.xcodeproj/project.pbxproj b/BenchmarkTests/BenchmarkTests.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..4cb16fa4c4
--- /dev/null
+++ b/BenchmarkTests/BenchmarkTests.xcodeproj/project.pbxproj
@@ -0,0 +1,544 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 56;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ D23DD32D2C58D80C00B90C4C /* DatadogBenchmarks in Frameworks */ = {isa = PBXBuildFile; productRef = D23DD32C2C58D80C00B90C4C /* DatadogBenchmarks */; };
+ D276069F2C514F37002D2A14 /* SessionReplay.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D27606962C514F37002D2A14 /* SessionReplay.storyboard */; };
+ D27606A02C514F37002D2A14 /* SessionReplayController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27606972C514F37002D2A14 /* SessionReplayController.swift */; };
+ D27606A12C514F37002D2A14 /* SessionReplayScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27606982C514F37002D2A14 /* SessionReplayScenario.swift */; };
+ D27606A22C514F37002D2A14 /* DefaultScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = D276069A2C514F37002D2A14 /* DefaultScenario.swift */; };
+ D27606A32C514F37002D2A14 /* Scenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = D276069B2C514F37002D2A14 /* Scenario.swift */; };
+ D27606A42C514F37002D2A14 /* AppConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D276069D2C514F37002D2A14 /* AppConfiguration.swift */; };
+ D27606A72C514F77002D2A14 /* DatadogCore in Frameworks */ = {isa = PBXBuildFile; productRef = D27606A62C514F77002D2A14 /* DatadogCore */; };
+ D27606A92C514F77002D2A14 /* DatadogLogs in Frameworks */ = {isa = PBXBuildFile; productRef = D27606A82C514F77002D2A14 /* DatadogLogs */; };
+ D27606AB2C514F77002D2A14 /* DatadogRUM in Frameworks */ = {isa = PBXBuildFile; productRef = D27606AA2C514F77002D2A14 /* DatadogRUM */; };
+ D27606AD2C514F77002D2A14 /* DatadogSessionReplay in Frameworks */ = {isa = PBXBuildFile; productRef = D27606AC2C514F77002D2A14 /* DatadogSessionReplay */; };
+ D27606AF2C514F77002D2A14 /* DatadogTrace in Frameworks */ = {isa = PBXBuildFile; productRef = D27606AE2C514F77002D2A14 /* DatadogTrace */; };
+ D29F75502C4AA07E00288638 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29F754F2C4AA07E00288638 /* AppDelegate.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ D29F75872C4AA98F00288638 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ D27606962C514F37002D2A14 /* SessionReplay.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SessionReplay.storyboard; sourceTree = ""; };
+ D27606972C514F37002D2A14 /* SessionReplayController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionReplayController.swift; sourceTree = ""; };
+ D27606982C514F37002D2A14 /* SessionReplayScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionReplayScenario.swift; sourceTree = ""; };
+ D276069A2C514F37002D2A14 /* DefaultScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultScenario.swift; sourceTree = ""; };
+ D276069B2C514F37002D2A14 /* Scenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scenario.swift; sourceTree = ""; };
+ D276069D2C514F37002D2A14 /* AppConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConfiguration.swift; sourceTree = ""; };
+ D27606B22C526908002D2A14 /* Benchmarks.local.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Benchmarks.local.xcconfig; sourceTree = ""; };
+ D27606B32C526908002D2A14 /* Runner.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Runner.xcconfig; sourceTree = ""; };
+ D27606B42C526908002D2A14 /* Synthetics.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Synthetics.xcconfig; sourceTree = ""; };
+ D277C84A2C58D3210072343C /* Benchmarks */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Benchmarks; sourceTree = ""; };
+ D29F754D2C4AA07E00288638 /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ D29F754F2C4AA07E00288638 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ D29F755D2C4AA08000288638 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ D2CA7E862C57F9B800AAB380 /* dd-sdk-ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "dd-sdk-ios"; path = ..; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ D29F754A2C4AA07E00288638 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D27606A92C514F77002D2A14 /* DatadogLogs in Frameworks */,
+ D27606AF2C514F77002D2A14 /* DatadogTrace in Frameworks */,
+ D27606AD2C514F77002D2A14 /* DatadogSessionReplay in Frameworks */,
+ D23DD32D2C58D80C00B90C4C /* DatadogBenchmarks in Frameworks */,
+ D27606AB2C514F77002D2A14 /* DatadogRUM in Frameworks */,
+ D27606A72C514F77002D2A14 /* DatadogCore in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ D27606992C514F37002D2A14 /* SessionReplay */ = {
+ isa = PBXGroup;
+ children = (
+ D27606962C514F37002D2A14 /* SessionReplay.storyboard */,
+ D27606972C514F37002D2A14 /* SessionReplayController.swift */,
+ D27606982C514F37002D2A14 /* SessionReplayScenario.swift */,
+ );
+ path = SessionReplay;
+ sourceTree = "";
+ };
+ D276069C2C514F37002D2A14 /* Scenarios */ = {
+ isa = PBXGroup;
+ children = (
+ D27606992C514F37002D2A14 /* SessionReplay */,
+ D276069A2C514F37002D2A14 /* DefaultScenario.swift */,
+ D276069B2C514F37002D2A14 /* Scenario.swift */,
+ );
+ path = Scenarios;
+ sourceTree = "";
+ };
+ D27606B52C526908002D2A14 /* xcconfigs */ = {
+ isa = PBXGroup;
+ children = (
+ D27606B22C526908002D2A14 /* Benchmarks.local.xcconfig */,
+ D27606B32C526908002D2A14 /* Runner.xcconfig */,
+ D27606B42C526908002D2A14 /* Synthetics.xcconfig */,
+ );
+ path = xcconfigs;
+ sourceTree = "";
+ };
+ D29F75272C4A9EFA00288638 = {
+ isa = PBXGroup;
+ children = (
+ D27606B52C526908002D2A14 /* xcconfigs */,
+ D29F754E2C4AA07E00288638 /* Runner */,
+ D29F75482C4A9F9500288638 /* Frameworks */,
+ D29F75312C4A9EFA00288638 /* Products */,
+ );
+ sourceTree = "";
+ };
+ D29F75312C4A9EFA00288638 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ D29F754D2C4AA07E00288638 /* Runner.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ D29F75482C4A9F9500288638 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ D277C84A2C58D3210072343C /* Benchmarks */,
+ D2CA7E862C57F9B800AAB380 /* dd-sdk-ios */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ D29F754E2C4AA07E00288638 /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ D29F754F2C4AA07E00288638 /* AppDelegate.swift */,
+ D276069D2C514F37002D2A14 /* AppConfiguration.swift */,
+ D276069C2C514F37002D2A14 /* Scenarios */,
+ D29F755D2C4AA08000288638 /* Info.plist */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ D29F754C2C4AA07E00288638 /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D29F75602C4AA08000288638 /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ D29F75492C4AA07E00288638 /* Sources */,
+ D29F754A2C4AA07E00288638 /* Frameworks */,
+ D29F754B2C4AA07E00288638 /* Resources */,
+ D29F75872C4AA98F00288638 /* Embed Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ packageProductDependencies = (
+ D27606A62C514F77002D2A14 /* DatadogCore */,
+ D27606A82C514F77002D2A14 /* DatadogLogs */,
+ D27606AA2C514F77002D2A14 /* DatadogRUM */,
+ D27606AC2C514F77002D2A14 /* DatadogSessionReplay */,
+ D27606AE2C514F77002D2A14 /* DatadogTrace */,
+ D23DD32C2C58D80C00B90C4C /* DatadogBenchmarks */,
+ );
+ productName = Runner;
+ productReference = D29F754D2C4AA07E00288638 /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ D29F75282C4A9EFA00288638 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1540;
+ LastUpgradeCheck = 1540;
+ TargetAttributes = {
+ D29F754C2C4AA07E00288638 = {
+ CreatedOnToolsVersion = 15.4;
+ };
+ };
+ };
+ buildConfigurationList = D29F752B2C4A9EFA00288638 /* Build configuration list for PBXProject "BenchmarkTests" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = D29F75272C4A9EFA00288638;
+ packageReferences = (
+ );
+ productRefGroup = D29F75312C4A9EFA00288638 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ D29F754C2C4AA07E00288638 /* Runner */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ D29F754B2C4AA07E00288638 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D276069F2C514F37002D2A14 /* SessionReplay.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ D29F75492C4AA07E00288638 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D27606A42C514F37002D2A14 /* AppConfiguration.swift in Sources */,
+ D29F75502C4AA07E00288638 /* AppDelegate.swift in Sources */,
+ D27606A22C514F37002D2A14 /* DefaultScenario.swift in Sources */,
+ D27606A12C514F37002D2A14 /* SessionReplayScenario.swift in Sources */,
+ D27606A32C514F37002D2A14 /* Scenario.swift in Sources */,
+ D27606A02C514F37002D2A14 /* SessionReplayController.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ D27606B62C526925002D2A14 /* Synthetics */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 17.5;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Synthetics;
+ };
+ D27606B72C526925002D2A14 /* Synthetics */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = D27606B42C526908002D2A14 /* Synthetics.xcconfig */;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CURRENT_PROJECT_VERSION = f34790fea;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.benchmarks.Runner;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Synthetics;
+ };
+ D29F75422C4A9EFB00288638 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 17.5;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ D29F75432C4A9EFB00288638 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 17.5;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ D29F755E2C4AA08000288638 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = D27606B32C526908002D2A14 /* Runner.xcconfig */;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CURRENT_PROJECT_VERSION = f34790fea;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.benchmarks.Runner;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ D29F755F2C4AA08000288638 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = D27606B32C526908002D2A14 /* Runner.xcconfig */;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CURRENT_PROJECT_VERSION = f34790fea;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.datadoghq.benchmarks.Runner;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ D29F752B2C4A9EFA00288638 /* Build configuration list for PBXProject "BenchmarkTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D29F75422C4A9EFB00288638 /* Debug */,
+ D29F75432C4A9EFB00288638 /* Release */,
+ D27606B62C526925002D2A14 /* Synthetics */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ D29F75602C4AA08000288638 /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D29F755E2C4AA08000288638 /* Debug */,
+ D29F755F2C4AA08000288638 /* Release */,
+ D27606B72C526925002D2A14 /* Synthetics */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ D23DD32C2C58D80C00B90C4C /* DatadogBenchmarks */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DatadogBenchmarks;
+ };
+ D27606A62C514F77002D2A14 /* DatadogCore */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DatadogCore;
+ };
+ D27606A82C514F77002D2A14 /* DatadogLogs */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DatadogLogs;
+ };
+ D27606AA2C514F77002D2A14 /* DatadogRUM */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DatadogRUM;
+ };
+ D27606AC2C514F77002D2A14 /* DatadogSessionReplay */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DatadogSessionReplay;
+ };
+ D27606AE2C514F77002D2A14 /* DatadogTrace */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DatadogTrace;
+ };
+/* End XCSwiftPackageProductDependency section */
+ };
+ rootObject = D29F75282C4A9EFA00288638 /* Project object */;
+}
diff --git a/BenchmarkTests/BenchmarkTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/BenchmarkTests/BenchmarkTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..919434a625
--- /dev/null
+++ b/BenchmarkTests/BenchmarkTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/BenchmarkTests/BenchmarkTests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/BenchmarkTests/BenchmarkTests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000000..18d981003d
--- /dev/null
+++ b/BenchmarkTests/BenchmarkTests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/BenchmarkTests/BenchmarkTests.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/BenchmarkTests/BenchmarkTests.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000000..47396a3dc5
--- /dev/null
+++ b/BenchmarkTests/BenchmarkTests.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BenchmarkTests/Benchmarks/Package.swift b/BenchmarkTests/Benchmarks/Package.swift
new file mode 100644
index 0000000000..8f08cf4eca
--- /dev/null
+++ b/BenchmarkTests/Benchmarks/Package.swift
@@ -0,0 +1,57 @@
+// swift-tools-version: 5.9
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+import Foundation
+
+let package = Package(
+ name: "DatadogBenchmarks",
+ products: [
+ .library(
+ name: "DatadogBenchmarks",
+ targets: ["Benchmarks"]
+ )
+ ]
+)
+
+func addOpenTelemetryDependency(_ version: Version) {
+ // The project must be open with the 'OTEL_SWIFT' env variable.
+ // Please run 'make benchmark-tests-open' from the root directory.
+ //
+ // Note: Carthage will still try to resolve dependencies of Xcode projects in
+ // sub directories, in this case the project will depend on the default
+ // 'DataDog/opentelemetry-swift-packages' depedency.
+ if ProcessInfo.processInfo.environment["OTEL_SWIFT"] != nil {
+ package.dependencies = [
+ .package(url: "https://github.com/open-telemetry/opentelemetry-swift", exact: version)
+ ]
+
+ package.targets = [
+ .target(
+ name: "Benchmarks",
+ dependencies: [
+ .product(name: "OpenTelemetryApi", package: "opentelemetry-swift"),
+ .product(name: "OpenTelemetrySdk", package: "opentelemetry-swift")
+ ],
+ swiftSettings: [.unsafeFlags(["-DOTEL_SWIFT"])]
+ )
+ ]
+
+ } else {
+ package.dependencies = [
+ .package(url: "https://github.com/DataDog/opentelemetry-swift-packages", exact: version)
+ ]
+
+ package.targets = [
+ .target(
+ name: "Benchmarks",
+ dependencies: [
+ .product(name: "OpenTelemetryApi", package: "opentelemetry-swift-packages")
+ ],
+ swiftSettings: [.unsafeFlags(["-DOTEL_API"])]
+ )
+ ]
+ }
+}
+
+addOpenTelemetryDependency("1.6.0")
diff --git a/BenchmarkTests/Benchmarks/Sources/DatadogExporter.swift b/BenchmarkTests/Benchmarks/Sources/DatadogExporter.swift
new file mode 100644
index 0000000000..9d32d57e4b
--- /dev/null
+++ b/BenchmarkTests/Benchmarks/Sources/DatadogExporter.swift
@@ -0,0 +1,46 @@
+/*
+ * 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 OTEL_API
+#error("Benchmarks depends on opentelemetry-swift. Please open the project with 'make benchmark-tests-open'.")
+#endif
+
+#if OTEL_SWIFT
+import OpenTelemetrySdk
+
+public final class DatadogExporter: SpanExporter, MetricExporter {
+ private let session: URLSession
+
+ public convenience init() {
+ let configuration: URLSessionConfiguration = .ephemeral
+ configuration.urlCache = nil
+ self.init(session: URLSession(configuration: configuration))
+ }
+
+ public init(session: URLSession) {
+ self.session = session
+ }
+
+ public func export(spans: [SpanData]) -> SpanExporterResultCode {
+ return .success
+ }
+
+ public func export(metrics: [Metric], shouldCancel: (() -> Bool)?) -> MetricExporterResultCode {
+ return .success
+ }
+
+ public func flush() -> SpanExporterResultCode {
+ return .success
+ }
+
+ public func shutdown() {
+
+ }
+}
+
+#endif
diff --git a/BenchmarkTests/Makefile b/BenchmarkTests/Makefile
new file mode 100644
index 0000000000..9606e4187f
--- /dev/null
+++ b/BenchmarkTests/Makefile
@@ -0,0 +1,61 @@
+.PHONY: clean archive export upload
+
+REPO_ROOT := ../
+include ../tools/utils/common.mk
+
+BUILD_DIR := .build
+ARCHIVE_PATH := $(BUILD_DIR)/Runner.xcarchive
+IPA_PATH := $(ARTIFACTS_PATH)/Runner.ipa
+
+clean:
+ @$(ECHO_SUBTITLE2) "make clean"
+ rm -rf "$(BUILD_DIR)"
+ifdef ARTIFACTS_PATH
+ rm -rf "$(IPA_PATH)"
+endif
+
+archive:
+ @:$(eval VERSION ?= $(CURRENT_GIT_COMMIT_SHORT))
+ @$(ECHO_SUBTITLE2) "make archive VERSION='$(VERSION)'"
+ @xcrun agvtool new-version "$(VERSION)"
+ set -eo pipefail; \
+ OTEL_SWIFT=1 xcodebuild \
+ -project BenchmarkTests.xcodeproj \
+ -scheme Runner \
+ -sdk iphoneos \
+ -configuration Synthetics \
+ -destination generic/platform=iOS \
+ -archivePath $(ARCHIVE_PATH) \
+ archive | xcbeautify
+ @$(ECHO_SUCCESS) "Archive ready in '$(ARCHIVE_PATH)'"
+
+export:
+ @$(call require_param,ARTIFACTS_PATH)
+ @:$(eval VERSION ?= $(CURRENT_GIT_COMMIT_SHORT))
+ @$(ECHO_SUBTITLE2) "make export VERSION='$(VERSION)' ARTIFACTS_PATH='$(ARTIFACTS_PATH)'"
+ set -o pipefaill; \
+ xcodebuild -exportArchive \
+ -archivePath $(ARCHIVE_PATH) \
+ -exportOptionsPlist exportOptions.plist \
+ -exportPath $(BUILD_DIR) \
+ | xcbeautify
+ mkdir -p "$(ARTIFACTS_PATH)"
+ cp -v "$(BUILD_DIR)/Runner.ipa" "$(IPA_PATH)"
+ @$(ECHO_SUCCESS) "IPA exported to '$(IPA_PATH)'"
+
+upload:
+ @$(call require_param,ARTIFACTS_PATH)
+ @$(call require_param,DATADOG_API_KEY)
+ @$(call require_param,DATADOG_APP_KEY)
+ @$(call require_param,S8S_APPLICATION_ID)
+ @:$(eval VERSION ?= $(CURRENT_GIT_COMMIT_SHORT))
+ @$(ECHO_SUBTITLE2) "make upload VERSION='$(VERSION)' ARTIFACTS_PATH='$(ARTIFACTS_PATH)'"
+ datadog-ci synthetics upload-application \
+ --mobileApp "$(IPA_PATH)" \
+ --mobileApplicationId "${S8S_APPLICATION_ID}" \
+ --versionName "$(VERSION)" \
+ --latest
+
+open:
+ @$(ECHO_SUBTITLE2) "make open"
+ @open --new --env OTEL_SWIFT BenchmarkTests.xcodeproj
diff --git a/BenchmarkTests/README.md b/BenchmarkTests/README.md
new file mode 100644
index 0000000000..3d40e49f35
--- /dev/null
+++ b/BenchmarkTests/README.md
@@ -0,0 +1,73 @@
+# Benchmark Tests
+
+[Synthetics for Mobile](https://docs.datadoghq.com/mobile_app_testing/) runs Benchmark test scenarios to collect metrics of the SDK performances.
+
+
+## CI
+
+CI continuously builds, signs, and uploads a runner application to Synthetics which runs predefined tests.
+
+### Build
+
+Before building the application, make sure the `BenchmarkTests/xcconfigs/Benchmark.local.xcconfig` configuration file is present and contains the `Mobile - Integration Org` client token, RUM application ID, and API Key. These values are sensitive and must be securely stored.
+
+```ini
+CLIENT_TOKEN=
+RUM_APPLICATION_ID=
+API_KEY=
+```
+
+### Sign
+
+To sign the runner application, the certificate and provision profile defined in [Synthetics.xcconfig](xcconfigs/Synthetics.xcconfig) and in [exportOptions.plist](exportOptions.plist) needs to be installed on the build machine. The certificate and profile are sensitive files and must be securely stored. Make sure to update both files when updating the certificate and provisioning profile, otherwise signing fails.
+
+> [!NOTE]
+> Certificate & Provisioning Profile are also available through the [App Store Connect API](https://developer.apple.com/documentation/appstoreconnectapi). But we don't have the tooling in place.
+
+### Upload
+
+The application version (build number) is set to the commit SHA of the current job, and the build is uploaded to Synthetics using the [datadog-ci](https://github.com/DataDog/datadog-ci) CLI. This step expects environment variables to authenticate with the `Mobile - Integration Org`:
+
+```bash
+export DATADOG_API_KEY=
+export DATADOG_APP_KEY=
+export S8S_APPLICATION_ID=
+```
+
+## Development
+
+Each scenario is independent and can be considered as an app within the runner.
+
+### Create a scenario
+
+A scenario must comply with the [`Scenario`](Runner/Scenarios/Scenario.swift) protocol. Upon start, a scenario initializes the SDK, enables features, and returns a root view-controller.
+
+Here is a simple example of a scenario using Logs:
+```swift
+import Foundation
+import UIKit
+
+import DatadogCore
+import DatadogLogs
+
+struct LogsScenario: Scenario {
+
+ func start(info: TestInfo) -> UIViewController {
+
+ Datadog.initialize(
+ with: .benchmark(info: info), // SDK init with the benchmark configuration
+ trackingConsent: .granted
+ )
+
+ Logs.enable()
+
+ return LoggerViewController()
+ }
+}
+```
+
+Add the test to the [`SyntheticScenario`](Runner/Scenarios/Scenario.swift) enumeration so it can be selected, either manually or by setting the `BENCHMARK_SCENARIO` environment variable.
+
+### Synthetics Configuration
+
+Please refer to [Confluence page (internal)](https://datadoghq.atlassian.net/wiki/spaces/RUMP/pages/3981476482/Benchmarks+iOS)
\ No newline at end of file
diff --git a/BenchmarkTests/Runner/AppConfiguration.swift b/BenchmarkTests/Runner/AppConfiguration.swift
new file mode 100644
index 0000000000..d6e13ccdec
--- /dev/null
+++ b/BenchmarkTests/Runner/AppConfiguration.swift
@@ -0,0 +1,76 @@
+/*
+ * 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
+import DatadogCore
+
+/// Test info reads configuration from `Info.plist`.
+///
+/// The expected format is as follow:
+///
+///
+/// DatadogConfiguration
+///
+/// ClientToken
+/// $(CLIENT_TOKEN)
+/// ApplicationID
+/// $(RUM_APPLICATION_ID)
+/// ApiKey
+/// $(API_KEY)
+/// Environment
+/// $(DD_ENV)
+/// Site
+/// $(DD_SITE)
+///
+///
+struct TestInfo: Decodable {
+ let clientToken: String
+ let applicationID: String
+ let apiKey: String
+ let site: DatadogSite
+ let env: String
+
+ enum CodingKeys: String, CodingKey {
+ case clientToken = "ClientToken"
+ case applicationID = "ApplicationID"
+ case apiKey = "ApiKey"
+ case site = "Site"
+ case env = "Environment"
+ }
+}
+
+extension TestInfo {
+ init(bundle: Bundle = .main) throws {
+ let decoder = AnyDecoder()
+ let obj = bundle.object(forInfoDictionaryKey: "DatadogConfiguration")
+ self = try decoder.decode(from: obj)
+ }
+}
+
+extension TestInfo {
+ static var empty: Self {
+ .init(
+ clientToken: "",
+ applicationID: "",
+ apiKey: "",
+ site: .us1,
+ env: "benchmarks"
+ )
+ }
+}
+
+extension DatadogSite: Decodable {}
+
+extension Datadog.Configuration {
+ static func benchmark(info: TestInfo) -> Self {
+ .init(
+ clientToken: info.clientToken,
+ env: info.env,
+ site: info.site
+ )
+ }
+}
diff --git a/BenchmarkTests/Runner/AppDelegate.swift b/BenchmarkTests/Runner/AppDelegate.swift
new file mode 100644
index 0000000000..212ec75bad
--- /dev/null
+++ b/BenchmarkTests/Runner/AppDelegate.swift
@@ -0,0 +1,24 @@
+/*
+ * 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 UIKit
+
+@main
+class AppDelegate: UIResponder, UIApplicationDelegate {
+ var window: UIWindow?
+
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+ let info = try! TestInfo() // crash if test info are missing or malformed
+
+ let scenario: Scenario = SyntheticScenario() ?? DefaultScenario()
+
+ window = UIWindow(frame: UIScreen.main.bounds)
+ window?.rootViewController = scenario.start(info: info)
+ window?.makeKeyAndVisible()
+
+ return true
+ }
+}
diff --git a/BenchmarkTests/Runner/Info.plist b/BenchmarkTests/Runner/Info.plist
new file mode 100644
index 0000000000..1c5a6ca83d
--- /dev/null
+++ b/BenchmarkTests/Runner/Info.plist
@@ -0,0 +1,19 @@
+
+
+
+
+ DatadogConfiguration
+
+ ApiKey
+ $(API_KEY)
+ ApplicationID
+ $(RUM_APPLICATION_ID)
+ ClientToken
+ $(CLIENT_TOKEN)
+ Environment
+ $(DD_ENV)
+ Site
+ $(DD_SITE)
+
+
+
diff --git a/BenchmarkTests/Runner/Scenarios/DefaultScenario.swift b/BenchmarkTests/Runner/Scenarios/DefaultScenario.swift
new file mode 100644
index 0000000000..d6760fed82
--- /dev/null
+++ b/BenchmarkTests/Runner/Scenarios/DefaultScenario.swift
@@ -0,0 +1,54 @@
+/*
+ * 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 UIKit
+import SwiftUI
+
+/// The default scenario will present the list of Synthetic scenarios to run in development mode.
+/// To skip this screen, you can set the `E2E_SCENARIO` environment variable with the name
+/// the desired scenario.
+struct DefaultScenario: Scenario {
+ func start(info: TestInfo) -> UIViewController {
+ UIHostingController(rootView: ContentView(info: info))
+ }
+
+ struct ContentView: View {
+ let info: TestInfo
+
+ var body: some View {
+ NavigationView {
+ List(SyntheticScenario.allCases, id: \.rawValue) { scenario in
+ NavigationLink {
+ ScenarioView(info: info, scenario: scenario)
+ } label: {
+ Text(scenario.rawValue)
+ }
+ }
+ .navigationBarTitle("Scenarios")
+ }
+ }
+ }
+
+ struct ScenarioView: UIViewControllerRepresentable {
+ let info: TestInfo
+ let scenario: Scenario
+
+ func makeUIViewController(context: Context) -> UIViewController {
+ scenario.start(info: info)
+ }
+
+ func updateUIViewController(_ uiViewController: UIViewController, context: Context) { }
+ }
+}
+
+#if DEBUG
+struct DefaultScenario_Previews: PreviewProvider {
+ static var previews: some View {
+ DefaultScenario.ContentView(info: .empty)
+ }
+}
+#endif
diff --git a/BenchmarkTests/Runner/Scenarios/Scenario.swift b/BenchmarkTests/Runner/Scenarios/Scenario.swift
new file mode 100644
index 0000000000..7a5abd9f85
--- /dev/null
+++ b/BenchmarkTests/Runner/Scenarios/Scenario.swift
@@ -0,0 +1,67 @@
+/*
+ * 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 UIKit
+
+/// A `Scenario` is the entry-point of the E2E runner application.
+///
+/// The compliant objects are responsible for initializing the SDK, enabling
+/// Features, and create the root view-controller.
+protocol Scenario {
+ /// Starts the scenario.
+ ///
+ /// Starting the scenario should intialize the SDK and enable Features based on
+ /// the provided ``TestInfo`` and scenario's needs.
+ ///
+ /// The returned view-controller will be used as the root view controller of the
+ /// application window.
+ ///
+ /// - Parameter info: The test info for configuring the SDK.
+ /// - Returns: The root view-controller.
+ func start(info: TestInfo) -> UIViewController
+}
+
+/// A Synthetic scenario can be initialized by defining a Synthetic Test Process Argument
+/// named `BENCHMARK_SCENARIO`.
+///
+/// Note: The raw value of enum case must match the test name defined in Synthetics.
+enum SyntheticScenario: String, CaseIterable {
+ case sessionReplay
+
+ /// Creates the scenario defined by the`BENCHMARK_SCENARIO` environment variable.
+ ///
+ /// - Parameter processInfo: The process info holding the environment variables.
+ init?(processInfo: ProcessInfo = .processInfo) {
+ guard
+ processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == nil, // skip SwiftUI preview
+ let rawValue = processInfo.environment["BENCHMARK_SCENARIO"],
+ let scenario = Self(rawValue: rawValue)
+ else {
+ return nil
+ }
+
+ self = scenario
+ }
+
+ /// Returns the scenario defined by the environment variable.
+ var scenario: Scenario {
+ switch self {
+ case .sessionReplay:
+ return SessionReplayScenario()
+ }
+ }
+}
+
+extension SyntheticScenario: Scenario {
+ /// Starts the underlying scenario.
+ ///
+ /// - Parameter info: The test info for configuring the SDK.
+ /// - Returns: The root view-controller.
+ func start(info: TestInfo) -> UIViewController {
+ scenario.start(info: info)
+ }
+}
diff --git a/BenchmarkTests/Runner/Scenarios/SessionReplay/SessionReplay.storyboard b/BenchmarkTests/Runner/Scenarios/SessionReplay/SessionReplay.storyboard
new file mode 100644
index 0000000000..53add6285f
--- /dev/null
+++ b/BenchmarkTests/Runner/Scenarios/SessionReplay/SessionReplay.storyboard
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BenchmarkTests/Runner/Scenarios/SessionReplay/SessionReplayController.swift b/BenchmarkTests/Runner/Scenarios/SessionReplay/SessionReplayController.swift
new file mode 100644
index 0000000000..8b7ebbad0c
--- /dev/null
+++ b/BenchmarkTests/Runner/Scenarios/SessionReplay/SessionReplayController.swift
@@ -0,0 +1,10 @@
+/*
+ * 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 UIKit
+
+class SessionReplayController: UIViewController {
+}
diff --git a/BenchmarkTests/Runner/Scenarios/SessionReplay/SessionReplayScenario.swift b/BenchmarkTests/Runner/Scenarios/SessionReplay/SessionReplayScenario.swift
new file mode 100644
index 0000000000..6b3b33ff96
--- /dev/null
+++ b/BenchmarkTests/Runner/Scenarios/SessionReplay/SessionReplayScenario.swift
@@ -0,0 +1,41 @@
+/*
+ * 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 UIKit
+
+import DatadogCore
+import DatadogRUM
+import DatadogSessionReplay
+
+struct SessionReplayScenario: Scenario {
+ func start(info: TestInfo) -> UIViewController {
+ Datadog.initialize(
+ with: .benchmark(info: info),
+ trackingConsent: .granted
+ )
+
+ RUM.enable(
+ with: RUM.Configuration(
+ applicationID: info.applicationID,
+ uiKitViewsPredicate: DefaultUIKitRUMViewsPredicate(),
+ uiKitActionsPredicate: DefaultUIKitRUMActionsPredicate()
+ )
+ )
+
+ SessionReplay.enable(
+ with: SessionReplay.Configuration(
+ replaySampleRate: 100,
+ defaultPrivacyLevel: .allow
+ )
+ )
+
+ RUMMonitor.shared().addAttribute(forKey: "scenario", value: "SessionReplay")
+
+ let storyboard = UIStoryboard(name: "SessionReplay", bundle: nil)
+ return storyboard.instantiateInitialViewController()!
+ }
+}
diff --git a/BenchmarkTests/exportOptions.plist b/BenchmarkTests/exportOptions.plist
new file mode 100644
index 0000000000..00cd98869b
--- /dev/null
+++ b/BenchmarkTests/exportOptions.plist
@@ -0,0 +1,19 @@
+
+
+
+
+ distributionBundleIdentifier
+ com.datadoghq.benchmarks.Runner
+ method
+ development
+ provisioningProfiles
+
+ com.datadoghq.benchmarks.Runner
+ Datadog Benchmark Runner
+
+ signingCertificate
+ Apple Development: Robot Bitrise (9HKDHCMCGH)
+ teamID
+ JKFCB4CN7C
+
+
diff --git a/BenchmarkTests/xcconfigs/Runner.xcconfig b/BenchmarkTests/xcconfigs/Runner.xcconfig
new file mode 100644
index 0000000000..251d60c004
--- /dev/null
+++ b/BenchmarkTests/xcconfigs/Runner.xcconfig
@@ -0,0 +1,9 @@
+CLIENT_TOKEN = // the Client Token on Mobile Integration Org
+RUM_APPLICATION_ID = // the RUM Application ID on Mobile Integration Org
+API_KEY = // the API Key on Mobile Integration Org
+
+DD_ENV[config=*] = benchmarks
+DD_ENV[config=Debug] = development
+DD_SITE = us1
+
+#include? "Benchmarks.local.xcconfig"
diff --git a/BenchmarkTests/xcconfigs/Synthetics.xcconfig b/BenchmarkTests/xcconfigs/Synthetics.xcconfig
new file mode 100644
index 0000000000..b7e14c3c51
--- /dev/null
+++ b/BenchmarkTests/xcconfigs/Synthetics.xcconfig
@@ -0,0 +1,6 @@
+#include "Runner.xcconfig"
+
+CODE_SIGN_STYLE = Manual
+CODE_SIGN_IDENTITY = Apple Development: Robot Bitrise (9HKDHCMCGH)
+DEVELOPMENT_TEAM = JKFCB4CN7C
+PROVISIONING_PROFILE_SPECIFIER = Datadog Benchmark Runner
diff --git a/CHANGELOG.md b/CHANGELOG.md
index defe97c5a3..6c78431b0d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
# Unreleased
+# 2.16.0 / 20-08-2024
+
+- [FIX] Refresh rate vital for variable refresh rate displays when over performing. See [#1973][]
+- [FIX] Alamofire extension types are deprecated now. See [#1988][]
+
+# 2.14.2 / 26-07-2024
+
+- [FIX] Fix CPU spikes when Watchdog Terminations tracking is enabled. See #1968
+- [FIX] Fix CPU spike when recording UITabBar using SessionReplay. See #1967
+
# 2.15.0 / 25-07-2024
- [FEATURE] Enable DatadogCore, DatadogLogs and DatadogTrace to compile on watchOS platform. See [#1918][] (Thanks [@jfiser-paylocity][]) [#1946][]
@@ -733,6 +743,8 @@ Release `2.0` introduces breaking changes. Follow the [Migration Guide](MIGRATIO
[#1963]: https://github.com/DataDog/dd-sdk-ios/pull/1963
[#1968]: https://github.com/DataDog/dd-sdk-ios/pull/1968
[#1967]: https://github.com/DataDog/dd-sdk-ios/pull/1967
+[#1973]: https://github.com/DataDog/dd-sdk-ios/pull/1973
+[#1988]: https://github.com/DataDog/dd-sdk-ios/pull/1988
[@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 42c37ce795..a33bfa4a6e 100644
--- a/Datadog/Datadog.xcodeproj/project.pbxproj
+++ b/Datadog/Datadog.xcodeproj/project.pbxproj
@@ -738,8 +738,6 @@
D20605BA2875729E0047275C /* ContextValuePublisherMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20605B82875729E0047275C /* ContextValuePublisherMock.swift */; };
D20605C42875895C0047275C /* KronosClockMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20605BB28757BFB0047275C /* KronosClockMock.swift */; };
D20605C52875895E0047275C /* KronosClockMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20605BB28757BFB0047275C /* KronosClockMock.swift */; };
- 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 */; };
D206BB8A2A41CA7000F43BA2 /* DatadogLogs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D20731B429A5279D00ECBF94 /* DatadogLogs.framework */; };
D207318429A5226B00ECBF94 /* DatadogLogs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D207317C29A5226A00ECBF94 /* DatadogLogs.framework */; platformFilter = ios; };
@@ -1270,8 +1268,6 @@
D29CDD3328211A2200F7DAA5 /* TLVBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29CDD3128211A2200F7DAA5 /* TLVBlock.swift */; };
D2A1EE23287740B500D28DFB /* ApplicationStatePublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE22287740B500D28DFB /* ApplicationStatePublisher.swift */; };
D2A1EE24287740B500D28DFB /* ApplicationStatePublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE22287740B500D28DFB /* ApplicationStatePublisher.swift */; };
- D2A1EE26287C35DE00D28DFB /* ContextValueReaderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE25287C35DE00D28DFB /* ContextValueReaderMock.swift */; };
- D2A1EE27287C35DE00D28DFB /* ContextValueReaderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE25287C35DE00D28DFB /* ContextValueReaderMock.swift */; };
D2A1EE32287DA51900D28DFB /* UserInfoPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE31287DA51900D28DFB /* UserInfoPublisher.swift */; };
D2A1EE33287DA51900D28DFB /* UserInfoPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE31287DA51900D28DFB /* UserInfoPublisher.swift */; };
D2A1EE35287EB8DB00D28DFB /* ServerOffsetPublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A1EE34287EB8DB00D28DFB /* ServerOffsetPublisherTests.swift */; };
@@ -2782,7 +2778,6 @@
D20605B5287572640047275C /* DatadogContextProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatadogContextProviderMock.swift; sourceTree = ""; };
D20605B82875729E0047275C /* ContextValuePublisherMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextValuePublisherMock.swift; sourceTree = ""; };
D20605BB28757BFB0047275C /* KronosClockMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KronosClockMock.swift; sourceTree = ""; };
- D20605C62875A77D0047275C /* ContextValueReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextValueReader.swift; sourceTree = ""; };
D207317C29A5226A00ECBF94 /* DatadogLogs.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogLogs.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D207318329A5226A00ECBF94 /* DatadogLogsTests iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "DatadogLogsTests iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
D20731B429A5279D00ECBF94 /* DatadogLogs.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DatadogLogs.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -2960,7 +2955,6 @@
D29CDD3128211A2200F7DAA5 /* TLVBlock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TLVBlock.swift; sourceTree = ""; };
D29D5A4C273BF8B400A687C1 /* SwiftUIActionModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIActionModifier.swift; sourceTree = ""; };
D2A1EE22287740B500D28DFB /* ApplicationStatePublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationStatePublisher.swift; sourceTree = ""; };
- D2A1EE25287C35DE00D28DFB /* ContextValueReaderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextValueReaderMock.swift; sourceTree = ""; };
D2A1EE31287DA51900D28DFB /* UserInfoPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoPublisher.swift; sourceTree = ""; };
D2A1EE34287EB8DB00D28DFB /* ServerOffsetPublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerOffsetPublisherTests.swift; sourceTree = ""; };
D2A1EE37287EBE4200D28DFB /* NetworkConnectionInfoPublisherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkConnectionInfoPublisherTests.swift; sourceTree = ""; };
@@ -5712,7 +5706,6 @@
children = (
D20605B5287572640047275C /* DatadogContextProviderMock.swift */,
D20605B82875729E0047275C /* ContextValuePublisherMock.swift */,
- D2A1EE25287C35DE00D28DFB /* ContextValueReaderMock.swift */,
);
path = DatadogCore;
sourceTree = "";
@@ -6467,7 +6460,6 @@
children = (
D2EFA867286DA85700F1FAA6 /* DatadogContextProvider.swift */,
D20605A2287464F40047275C /* ContextValuePublisher.swift */,
- D20605C62875A77D0047275C /* ContextValueReader.swift */,
D20605A5287476230047275C /* ServerOffsetPublisher.swift */,
D20605A82874C1CD0047275C /* NetworkConnectionInfoPublisher.swift */,
D20605B12874E1660047275C /* CarrierInfoPublisher.swift */,
@@ -8047,7 +8039,6 @@
9E68FB55244707FD0013A8AA /* ObjcExceptionHandler.m in Sources */,
D2FB125D292FBB56005B13F8 /* Datadog+Internal.swift in Sources */,
D2A7840F29A53B2F003B03BB /* Directory.swift in Sources */,
- D20605CB2875A83F0047275C /* ContextValueReader.swift in Sources */,
61D3E0DB277B23F1008BE766 /* KronosNSTimer+ClosureKit.swift in Sources */,
D20605A92874C1CD0047275C /* NetworkConnectionInfoPublisher.swift in Sources */,
614396722A67D74F00197326 /* BatchMetrics.swift in Sources */,
@@ -8236,7 +8227,6 @@
61F930C52BA1C4EB005F0EE2 /* TLVBlockReaderTests.swift in Sources */,
6172472725D673D7007085B3 /* CrashContextTests.swift in Sources */,
61A2CC242A44454D0000FF25 /* DDRUMTests.swift in Sources */,
- D2A1EE26287C35DE00D28DFB /* ContextValueReaderMock.swift in Sources */,
D25CFAA329C8644E00E3A43D /* Casting+Tracing.swift in Sources */,
61BAD46A26415FCE001886CA /* OTSpanTests.swift in Sources */,
61B5E42726DFB145000B0A5F /* DDDatadog+apiTests.m in Sources */,
@@ -9304,7 +9294,6 @@
D29CDD3328211A2200F7DAA5 /* TLVBlock.swift in Sources */,
D2612F48290197C700509B7D /* LaunchTimePublisher.swift in Sources */,
A70A82662A935F210072F5DC /* BackgroundTaskCoordinator.swift in Sources */,
- D20605CA2875A83D0047275C /* ContextValueReader.swift in Sources */,
D2A1EE24287740B500D28DFB /* ApplicationStatePublisher.swift in Sources */,
D2CB6E2927C50EAE00A62B57 /* KronosInternetAddress.swift in Sources */,
6128F5722BA223D100D35B08 /* DataStore+TLV.swift in Sources */,
@@ -9511,7 +9500,6 @@
D28F836629C9E6A200EF8EA2 /* DatadogTraceFeatureTests.swift in Sources */,
612C13D72AAB35EB0086B5D1 /* SRSegmentMatcher.swift in Sources */,
6147989A2A459B2E0095CB02 /* DDTraceConfigurationTests.swift in Sources */,
- D2A1EE27287C35DE00D28DFB /* ContextValueReaderMock.swift in Sources */,
D2CB6F7E27C520D400A62B57 /* OTSpanTests.swift in Sources */,
D2CB6F7F27C520D400A62B57 /* DDDatadog+apiTests.m in Sources */,
D2CB6F8027C520D400A62B57 /* TracingWithLoggingIntegrationTests.swift in Sources */,
diff --git a/DatadogAlamofireExtension.podspec b/DatadogAlamofireExtension.podspec
index 85331f4ad0..34021697ff 100644
--- a/DatadogAlamofireExtension.podspec
+++ b/DatadogAlamofireExtension.podspec
@@ -1,7 +1,12 @@
Pod::Spec.new do |s|
s.name = "DatadogAlamofireExtension"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "An Official Extensions of Datadog Swift SDK for Alamofire."
+ s.description = <<-DESC
+ The DatadogAlamofireExtension pod is deprecated and will no longer be maintained.
+ Please refer to the following documentation on how to instrument Alamofire with the Datadog iOS SDK:
+ https://docs.datadoghq.com/real_user_monitoring/mobile_and_tv_monitoring/integrated_libraries/ios
+ DESC
s.homepage = "https://www.datadoghq.com"
s.social_media_url = "https://twitter.com/datadoghq"
@@ -14,6 +19,8 @@ Pod::Spec.new do |s|
"Maciej Burda" => "maciej.burda@datadoghq.com"
}
+ s.deprecated = true
+
s.swift_version = '5.9'
s.ios.deployment_target = '12.0'
s.tvos.deployment_target = '12.0'
diff --git a/DatadogCore.podspec b/DatadogCore.podspec
index 05149b6f28..118ce2496a 100644
--- a/DatadogCore.podspec
+++ b/DatadogCore.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogCore"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Official Datadog Swift SDK for iOS."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogCore/Sources/Core/Context/ContextValueReader.swift b/DatadogCore/Sources/Core/Context/ContextValueReader.swift
deleted file mode 100644
index e64dc0546e..0000000000
--- a/DatadogCore/Sources/Core/Context/ContextValueReader.swift
+++ /dev/null
@@ -1,120 +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
-
-/// Defines a read closure for mutating value.
-private typealias ContextValueMutation = (inout Value) -> Void
-
-/// Declares that a type can read values on demand.
-///
-/// A reader delivers elements to the receiver callback synchronously.
-/// The receiver's ``ContextValueReceiver/Value`` generic type must match the
-/// ``ContextValueReader/Value`` types declared by the reader.
-///
-/// The reader implements the ``ContextValuePublisher/read(_:)`` method
-/// to read the value and call the receiver.
-internal protocol ContextValueReader {
- /// The kind of values this reader reads.
- associatedtype Value
-
- /// Reads the value synchronously and mutate the value.
- ///
- /// - Parameter receiver: The value to mutate on read.
- func read(to receiver: inout Value)
-}
-
-// MARK: - Type-Erasure
-
-/// A reader that performs type erasure by wrapping another reader.
-///
-/// ``AnyContextValueReader`` is a concrete implementation of ``ContextValueReader``
-/// that has no significant properties of its own, and passes through value to its upstream
-/// reader.
-///
-/// Use ``AnyContextValueReader`` to wrap a reader whose type has details
-/// you don’t want to expose across API boundaries, such as different modules
-///
-/// You can use extension method ``ContextValueReader/eraseToAnyReader()``
-/// operator to wrap a publisher with ``ContextValueReader``.
-internal struct AnyContextValueReader: ContextValueReader {
- private var mutation: ContextValueMutation
-
- /// Creates a type-erasing reader to wrap the provided reader.
- ///
- /// - Parameter reader: A reader to wrap with a type-eraser.
- init(_ reader: Reader) where Reader: ContextValueReader, Reader.Value == Value {
- self.mutation = reader.read
- }
-
- /// Reads the value synchronously and mutate the value.
- ///
- /// - Parameter receiver: The value to mutate on read.
- func read(to receiver: inout Value) {
- mutation(&receiver)
- }
-}
-
-extension ContextValueReader {
- /// Wraps this reader with a type eraser.
- ///
- /// Use ``ContextValueReader/eraseToAnyReader()`` to expose an instance of
- /// ``AnyContextValueReader`` to the downstream subscriber, rather than this reader’s
- /// actual type. This form of _type erasure_ preserves abstraction across API boundaries.
- ///
- /// - Returns: An ``AnyContextValueReader`` wrapping this reader.
- func eraseToAnyReader() -> AnyContextValueReader {
- return AnyContextValueReader(self)
- }
-}
-
-// MARK: - Key-path Reader
-
-/// A reader that performs key-path mutations by wrapping other readers.
-///
-/// ``KeyPathContextValueReader`` keeps an array of mutation operations by calling
-/// ``ContextValueReader/read`` to write to a value's property at given ``WritableKeyPath``.
-///
-/// Use ``KeyPathContextValueReader`` to wrap readers to mutate properties of
-/// a value.
-internal struct KeyPathContextValueReader {
- private var mutations: [ContextValueMutation] = []
-
- /// Appends a ``ContextValueReader`` instance to set the value's property at a given
- /// `keyPath`.
- ///
- /// - Parameters:
- /// - reader: The reader to append.
- /// - keyPath: The value's writable `keyPath`.
- mutating func append(reader: Reader, receiver keyPath: WritableKeyPath) where Reader: ContextValueReader {
- mutations.append { value in
- reader.read(to: &value[keyPath: keyPath])
- }
- }
-
- /// Reads the value synchronously and mutate the value.
- ///
- /// - Parameter receiver: The value to mutate on read.
- func read(to receiver: inout Value) {
- mutations.forEach { mutation in
- mutation(&receiver)
- }
- }
-}
-
-// MARK: - No-op
-
-/// A no-operation reader.
-///
-/// ``NOPContextValueReader`` is a concrete implementation of ``ContextValueReader``
-/// that has no effect when invoking ``ContextValueReader/read``.
-///
-/// You can use ``NOPContextValueReader`` as a placeholder.
-internal struct NOPContextValueReader: ContextValueReader {
- func read(to receiver: inout Value) {
- // no-op
- }
-}
diff --git a/DatadogCore/Sources/Core/Context/DatadogContextProvider.swift b/DatadogCore/Sources/Core/Context/DatadogContextProvider.swift
index f779bfb3ee..61980e0cf0 100644
--- a/DatadogCore/Sources/Core/Context/DatadogContextProvider.swift
+++ b/DatadogCore/Sources/Core/Context/DatadogContextProvider.swift
@@ -54,9 +54,6 @@ internal final class DatadogContextProvider {
/// List of subscription of context values.
private var subscriptions: [ContextValueSubscription]
- /// A reader for key-path values of the context.
- private var reader: KeyPathContextValueReader
-
/// Creates a context provider to perform reads and writes on the
/// shared Datadog context.
///
@@ -65,21 +62,12 @@ internal final class DatadogContextProvider {
self.context = context
self.receivers = []
self.subscriptions = []
- self.reader = KeyPathContextValueReader()
}
deinit {
subscriptions.forEach { $0.cancel() }
}
- /// Reads current context.
- ///
- /// **Warning:** Must be called from the `queue`.
- private func unsafeRead() -> DatadogContext {
- reader.read(to: &self.context)
- return context
- }
-
/// Publishes context changes to the given receiver.
///
/// - Parameter receiver: The receiver closure.
@@ -94,14 +82,14 @@ internal final class DatadogContextProvider {
///
/// - Returns: The current context.
func read() -> DatadogContext {
- queue.sync(execute: unsafeRead)
+ queue.sync { context }
}
/// Reads to the `context` asynchronously, without blocking the caller thread.
///
/// - Parameter block: The block closure called with the current context.
func read(block: @escaping (DatadogContext) -> Void) {
- queue.async { block(self.unsafeRead()) }
+ queue.async { block(self.context) }
}
/// Writes to the `context` asynchronously, without blocking the caller thread.
@@ -138,23 +126,6 @@ internal final class DatadogContextProvider {
}
}
- /// Assigns a value reader to a context property.
- ///
- /// The context provider has the ability to a assign a value reader that complies to
- /// ``ContextValueReader`` to a specific context property. e.g.:
- ///
- /// let reader = ServerOffsetReader()
- /// provider.assign(reader: reader, to: \.serverTimeOffset)
- ///
- /// - Parameters:
- /// - reader: The value reader.
- /// - keyPath: A context's key path that supports reading from and writing to the resulting value.
- func assign(reader: Reader, to keyPath: WritableKeyPath) where Reader: ContextValueReader {
- queue.async {
- self.reader.append(reader: reader, receiver: keyPath)
- }
- }
-
#if DD_SDK_COMPILED_FOR_TESTING
func replace(context newContext: DatadogContext) {
queue.async {
diff --git a/DatadogCore/Sources/Versioning.swift b/DatadogCore/Sources/Versioning.swift
index 98d63c0e19..39369d25ed 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.15.0"
+internal let __sdkVersion = "2.16.0"
diff --git a/DatadogCore/Tests/Datadog/DatadogCore/Context/DatadogContextProviderTests.swift b/DatadogCore/Tests/Datadog/DatadogCore/Context/DatadogContextProviderTests.swift
index 66818267d2..c63b3de5b4 100644
--- a/DatadogCore/Tests/Datadog/DatadogCore/Context/DatadogContextProviderTests.swift
+++ b/DatadogCore/Tests/Datadog/DatadogCore/Context/DatadogContextProviderTests.swift
@@ -41,34 +41,6 @@ class DatadogContextProviderTests: XCTestCase {
XCTAssertEqual(context.carrierInfo, carrierInfo)
}
- func testReaderPropagation() throws {
- // Given
- let serverOffsetReader = ContextValueReaderMock(initialValue: 0)
- let networkConnectionInfoReader = ContextValueReaderMock()
- let carrierInfoReader = ContextValueReaderMock()
-
- let provider = DatadogContextProvider(context: context)
- provider.assign(reader: serverOffsetReader, to: \.serverTimeOffset)
- provider.assign(reader: networkConnectionInfoReader, to: \.networkConnectionInfo)
- provider.assign(reader: carrierInfoReader, to: \.carrierInfo)
-
- // When
- let serverTimeOffset: TimeInterval = .mockRandomInThePast()
- serverOffsetReader.value = serverTimeOffset
-
- let networkConnectionInfo: NetworkConnectionInfo = .mockRandom()
- networkConnectionInfoReader.value = networkConnectionInfo
-
- let carrierInfo: CarrierInfo = .mockRandom()
- carrierInfoReader.value = carrierInfo
-
- // Then
- let context = provider.read()
- XCTAssertEqual(context.serverTimeOffset, serverTimeOffset)
- XCTAssertEqual(context.networkConnectionInfo, networkConnectionInfo)
- XCTAssertEqual(context.carrierInfo, carrierInfo)
- }
-
func testPublishNewContextOnValueChange() throws {
let expectation = self.expectation(description: "publish new context")
expectation.expectedFulfillmentCount = 3
@@ -98,26 +70,15 @@ class DatadogContextProviderTests: XCTestCase {
let networkConnectionInfoPublisher = ContextValuePublisherMock()
let carrierInfoPublisher = ContextValuePublisherMock()
- let serverOffsetReader = ContextValueReaderMock(initialValue: 0)
- let networkConnectionInfoReader = ContextValueReaderMock()
- let carrierInfoReader = ContextValueReaderMock()
-
let provider = DatadogContextProvider(context: context)
provider.subscribe(\.serverTimeOffset, to: serverOffsetPublisher)
provider.subscribe(\.networkConnectionInfo, to: networkConnectionInfoPublisher)
provider.subscribe(\.carrierInfo, to: carrierInfoPublisher)
- provider.assign(reader: serverOffsetReader, to: \.serverTimeOffset)
- provider.assign(reader: networkConnectionInfoReader, to: \.networkConnectionInfo)
- provider.assign(reader: carrierInfoReader, to: \.carrierInfo)
-
// swiftlint:disable opening_brace
callConcurrently(
closures: [
- { serverOffsetReader.value = .mockRandom() },
- { networkConnectionInfoReader.value = .mockRandom() },
- { carrierInfoReader.value = .mockRandom() },
{ serverOffsetPublisher.value = .mockRandom() },
{ networkConnectionInfoPublisher.value = .mockRandom() },
{ carrierInfoPublisher.value = .mockRandom() },
diff --git a/DatadogCore/Tests/Datadog/Mocks/DatadogCore/ContextValueReaderMock.swift b/DatadogCore/Tests/Datadog/Mocks/DatadogCore/ContextValueReaderMock.swift
deleted file mode 100644
index 45685dbfff..0000000000
--- a/DatadogCore/Tests/Datadog/Mocks/DatadogCore/ContextValueReaderMock.swift
+++ /dev/null
@@ -1,43 +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
-@testable import DatadogCore
-
-internal class ContextValueReaderMock: ContextValueReader {
- private let queue = DispatchQueue(
- label: "com.datadoghq.context-value-reader-mock"
- )
-
- var value: Value {
- get { queue.sync { _value } }
- set { queue.sync { _value = newValue } }
- }
-
- private var _value: Value
-
- init(initialValue: Value) {
- self._value = initialValue
- }
-
- init() where Value: ExpressibleByNilLiteral {
- _value = nil
- }
-
- func read(to receiver: inout Value) {
- receiver = queue.sync { _value }
- }
-}
-
-extension ContextValueReader {
- static func mockAny() -> ContextValueReaderMock where Value: ExpressibleByNilLiteral {
- .init()
- }
-
- static func mockWith(initialValue: Value) -> ContextValueReaderMock {
- .init(initialValue: initialValue)
- }
-}
diff --git a/DatadogCore/Tests/Datadog/RUM/RUMVitals/VitalRefreshRateReaderTests.swift b/DatadogCore/Tests/Datadog/RUM/RUMVitals/VitalRefreshRateReaderTests.swift
index 09707f7c1a..357c5bc23e 100644
--- a/DatadogCore/Tests/Datadog/RUM/RUMVitals/VitalRefreshRateReaderTests.swift
+++ b/DatadogCore/Tests/Datadog/RUM/RUMVitals/VitalRefreshRateReaderTests.swift
@@ -220,6 +220,34 @@ class VitalRefreshRateReaderTests: XCTestCase {
let thirdFps = reader.framesPerSecond(provider: frameInfoProvider)
XCTAssertEqual(thirdFps, 42.85714285714286)
}
+
+ /* Rate representation
+ *
+ * 0----------8ms---------16ms--------24ms--------32ms
+ * | 6ms | 6ms | 6ms | 6ms |
+ *
+ */
+ func testFramesPerSecond_givenAdaptiveSyncDisplayWithQuickerThanExpectedFrames() {
+ let reader = VitalRefreshRateReader(notificationCenter: mockNotificationCenter)
+ var frameInfoProvider = FrameInfoProviderMock(maximumDeviceFramesPerSecond: 120)
+
+ // first frame recorded
+ frameInfoProvider.currentFrameTimestamp = 0
+ frameInfoProvider.nextFrameTimestamp = 0.008
+ let firstFps = reader.framesPerSecond(provider: frameInfoProvider)
+ XCTAssertNil(firstFps)
+
+ // second frame recorded
+ frameInfoProvider.currentFrameTimestamp = 0.006
+ frameInfoProvider.nextFrameTimestamp = 0.014
+ let secondFps = reader.framesPerSecond(provider: frameInfoProvider)
+ XCTAssertEqual(secondFps, 60)
+
+ // third frame recorded
+ frameInfoProvider.currentFrameTimestamp = 0.012
+ let thirdFps = reader.framesPerSecond(provider: frameInfoProvider)
+ XCTAssertEqual(thirdFps, 60)
+ }
}
struct FrameInfoProviderMock: FrameInfoProvider {
diff --git a/DatadogCrashReporting.podspec b/DatadogCrashReporting.podspec
index b123502e8b..46ebe77e2f 100644
--- a/DatadogCrashReporting.podspec
+++ b/DatadogCrashReporting.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogCrashReporting"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Official Datadog Crash Reporting SDK for iOS."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogExtensions/Alamofire/DatadogAlamofireExtension.swift b/DatadogExtensions/Alamofire/DatadogAlamofireExtension.swift
index 840b88474b..7cd5b7f3ca 100644
--- a/DatadogExtensions/Alamofire/DatadogAlamofireExtension.swift
+++ b/DatadogExtensions/Alamofire/DatadogAlamofireExtension.swift
@@ -8,6 +8,7 @@ import DatadogInternal
import Alamofire
/// An `Alamofire.EventMonitor` which instruments `Alamofire.Session` with Datadog RUM and Tracing.
+@available(*, deprecated, message: "Use `URLSessionInstrumentation.enable(with:)` instead.")
public class DDEventMonitor: EventMonitor {
/// The instance of the SDK core notified by this monitor.
private weak var core: DatadogCoreProtocol?
@@ -39,6 +40,7 @@ public class DDEventMonitor: EventMonitor {
}
/// An `Alamofire.RequestInterceptor` which instruments `Alamofire.Session` with Datadog RUM and Tracing.
+@available(*, deprecated, message: "Use `URLSessionInstrumentation.enable(with:)` instead.")
public class DDRequestInterceptor: RequestInterceptor {
/// The instance of the SDK core notified by this monitor.
private weak var core: DatadogCoreProtocol?
diff --git a/DatadogExtensions/Alamofire/README.md b/DatadogExtensions/Alamofire/README.md
index cb7aed5e5b..e843d3bc11 100644
--- a/DatadogExtensions/Alamofire/README.md
+++ b/DatadogExtensions/Alamofire/README.md
@@ -1,3 +1,9 @@
+## **Deprecated**
+
+**Note:** The `DatadogAlamofireExtension` pod is deprecated and will no longer be maintained. Please refer to the [Integrated Libraries][6] documentation on how to instrument Alamofire with the Datadog iOS SDK.
+
+---
+
# Datadog Integration for Alamofire
`DatadogAlamofireExtension` enables `Alamofire.Session` auto instrumentation with Datadog SDK.
@@ -49,3 +55,4 @@ Pull requests are welcome. First, open an issue to discuss what you would like t
[3]: https://swift.org/package-manager/
[4]: https://docs.datadoghq.com/tracing/setup_overview/setup/ios/
[5]: https://docs.datadoghq.com/real_user_monitoring/ios
+[6]: https://docs.datadoghq.com/real_user_monitoring/mobile_and_tv_monitoring/integrated_libraries/ios
diff --git a/DatadogInternal.podspec b/DatadogInternal.podspec
index a5ce0b1709..a8c8e87dc2 100644
--- a/DatadogInternal.podspec
+++ b/DatadogInternal.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogInternal"
- s.version = "2.15.0"
+ s.version = "2.16.0"
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 eba17710ba..79c8c63a55 100644
--- a/DatadogLogs.podspec
+++ b/DatadogLogs.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogLogs"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Datadog Logs Module."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogObjc.podspec b/DatadogObjc.podspec
index 5ff3db89b7..5dc939d3c2 100644
--- a/DatadogObjc.podspec
+++ b/DatadogObjc.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogObjc"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Official Datadog Objective-C SDK for iOS."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogObjc/Sources/RUM/RUMDataModels+objc.swift b/DatadogObjc/Sources/RUM/RUMDataModels+objc.swift
index 19c898ea78..0aa46461cb 100644
--- a/DatadogObjc/Sources/RUM/RUMDataModels+objc.swift
+++ b/DatadogObjc/Sources/RUM/RUMDataModels+objc.swift
@@ -7299,6 +7299,11 @@ public class DDTelemetryConfigurationEventTelemetryConfiguration: NSObject {
root.swiftModel.telemetry.configuration.silentMultipleInit as NSNumber?
}
+ @objc public var startRecordingImmediately: NSNumber? {
+ set { root.swiftModel.telemetry.configuration.startRecordingImmediately = newValue?.boolValue }
+ get { root.swiftModel.telemetry.configuration.startRecordingImmediately as NSNumber? }
+ }
+
@objc public var startSessionReplayRecordingManually: NSNumber? {
set { root.swiftModel.telemetry.configuration.startSessionReplayRecordingManually = newValue?.boolValue }
get { root.swiftModel.telemetry.configuration.startSessionReplayRecordingManually as NSNumber? }
@@ -7710,4 +7715,4 @@ public class DDTelemetryConfigurationEventView: NSObject {
// swiftlint:enable force_unwrapping
-// Generated from https://github.com/DataDog/rum-events-format/tree/31c73753ff5c954cf9aef475c91ec0b413743f77
+// Generated from https://github.com/DataDog/rum-events-format/tree/41d2cb901a87fa025843c85568c16d3e199fea4c
diff --git a/DatadogRUM.podspec b/DatadogRUM.podspec
index 318973ebeb..f21ef0068a 100644
--- a/DatadogRUM.podspec
+++ b/DatadogRUM.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogRUM"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Datadog Real User Monitoring Module."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogRUM/Sources/DataModels/RUMDataModels.swift b/DatadogRUM/Sources/DataModels/RUMDataModels.swift
index 59bb13fd7a..b013fb5382 100644
--- a/DatadogRUM/Sources/DataModels/RUMDataModels.swift
+++ b/DatadogRUM/Sources/DataModels/RUMDataModels.swift
@@ -3594,6 +3594,9 @@ public struct TelemetryConfigurationEvent: RUMDataModel {
/// Whether initialization fails silently if the SDK is already initialized
public let silentMultipleInit: Bool?
+ /// Whether Session Replay should automatically start a recording when enabled
+ public var startRecordingImmediately: Bool?
+
/// Whether the session replay start is handled manually
public var startSessionReplayRecordingManually: Bool?
@@ -3742,6 +3745,7 @@ public struct TelemetryConfigurationEvent: RUMDataModel {
case sessionReplaySampleRate = "session_replay_sample_rate"
case sessionSampleRate = "session_sample_rate"
case silentMultipleInit = "silent_multiple_init"
+ case startRecordingImmediately = "start_recording_immediately"
case startSessionReplayRecordingManually = "start_session_replay_recording_manually"
case storeContextsAcrossPages = "store_contexts_across_pages"
case telemetryConfigurationSampleRate = "telemetry_configuration_sample_rate"
@@ -4335,4 +4339,4 @@ public struct RUMTelemetryOperatingSystem: Codable {
}
}
-// Generated from https://github.com/DataDog/rum-events-format/tree/31c73753ff5c954cf9aef475c91ec0b413743f77
+// Generated from https://github.com/DataDog/rum-events-format/tree/41d2cb901a87fa025843c85568c16d3e199fea4c
diff --git a/DatadogRUM/Sources/RUMVitals/VitalRefreshRateReader.swift b/DatadogRUM/Sources/RUMVitals/VitalRefreshRateReader.swift
index 021a3a1133..900ca922ee 100644
--- a/DatadogRUM/Sources/RUMVitals/VitalRefreshRateReader.swift
+++ b/DatadogRUM/Sources/RUMVitals/VitalRefreshRateReader.swift
@@ -77,7 +77,8 @@ internal class VitalRefreshRateReader: ContinuousVitalReader {
return nil
}
let expectedFPS = 1.0 / expectedCurrentFrameDuration
- fps = currentFPS * (Self.backendSupportedFrameRate / expectedFPS)
+ let normalizedFPS = currentFPS * (Self.backendSupportedFrameRate / expectedFPS)
+ fps = min(normalizedFPS, Self.backendSupportedFrameRate)
} else {
fps = currentFPS
}
diff --git a/DatadogSDK.podspec b/DatadogSDK.podspec
index 6a5052c845..d4c676bae7 100644
--- a/DatadogSDK.podspec
+++ b/DatadogSDK.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogSDK"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Official Datadog Swift SDK for iOS."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogSDKAlamofireExtension.podspec b/DatadogSDKAlamofireExtension.podspec
index 3e122a071d..5bbfb37c6c 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.15.0"
+ s.version = "2.16.0"
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 048bf48a1a..dc190d0be6 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.15.0"
+ s.version = "2.16.0"
s.summary = "Official Datadog Crash Reporting SDK for iOS."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogSDKObjc.podspec b/DatadogSDKObjc.podspec
index 3346436810..b79b7fbb69 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.15.0"
+ s.version = "2.16.0"
s.summary = "Official Datadog Objective-C SDK for iOS."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogSessionReplay.podspec b/DatadogSessionReplay.podspec
index efeae4525c..4a2dccc1f1 100644
--- a/DatadogSessionReplay.podspec
+++ b/DatadogSessionReplay.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogSessionReplay"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Official Datadog Session Replay SDK for iOS."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogTrace.podspec b/DatadogTrace.podspec
index 69be9b3518..eb08b1a986 100644
--- a/DatadogTrace.podspec
+++ b/DatadogTrace.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogTrace"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Datadog Trace Module."
s.homepage = "https://www.datadoghq.com"
diff --git a/DatadogWebViewTracking.podspec b/DatadogWebViewTracking.podspec
index cc5ecb8f38..dd4aeade3e 100644
--- a/DatadogWebViewTracking.podspec
+++ b/DatadogWebViewTracking.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DatadogWebViewTracking"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Datadog WebView Tracking Module."
s.homepage = "https://www.datadoghq.com"
diff --git a/Makefile b/Makefile
index 5105b5cb58..e6fd5172d3 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,7 @@ all: env-check repo-setup templates
smoke-test smoke-test-ios smoke-test-ios-all smoke-test-tvos smoke-test-tvos-all \
spm-build spm-build-ios spm-build-tvos spm-build-visionos spm-build-macos spm-build-watchos \
e2e-build-upload \
+ benchmark-build-upload \
models-generate rum-models-generate sr-models-generate models-verify rum-models-verify sr-models-verify \
dogfood-shopist dogfood-datadog-app \
release-build release-validate release-publish-github \
@@ -268,6 +269,18 @@ e2e-build-upload:
@$(ECHO_TITLE) "make e2e-build-upload ARTIFACTS_PATH='$(ARTIFACTS_PATH)' DRY_RUN='$(DRY_RUN)'"
DRY_RUN=$(DRY_RUN) ./tools/e2e-build-upload.sh --artifacts-path "$(ARTIFACTS_PATH)"
+# Builds a new version of the Benchmark app and publishes it to synthetics.
+benchmark-build-upload:
+ @$(call require_param,ARTIFACTS_PATH)
+ @:$(eval DRY_RUN ?= 1)
+ @$(ECHO_TITLE) "make benchmark-build-upload ARTIFACTS_PATH='$(ARTIFACTS_PATH)' DRY_RUN='$(DRY_RUN)'"
+ DRY_RUN=$(DRY_RUN) ./tools/benchmark-build-upload.sh --artifacts-path "$(ARTIFACTS_PATH)"
+
+# Opens `BenchmarkTests` project with passing required ENV variables
+benchmark-tests-open:
+ @$(ECHO_TITLE) "make benchmark-tests-open"
+ @$(MAKE) -C BenchmarkTests open
+
xcodeproj-session-replay:
@echo "⚙️ Generating 'DatadogSessionReplay.xcodeproj'..."
@cd DatadogSessionReplay/ && swift package generate-xcodeproj
@@ -445,9 +458,9 @@ set-ci-secret:
@./tools/secrets/set-secret.sh
bump:
- @read -p "Enter version number: " version; \
- echo "// GENERATED FILE: Do not edit directly\n\ninternal let __sdkVersion = \"$$version\"" > DatadogCore/Sources/Versioning.swift; \
- ./tools/podspec_bump_version.sh $$version; \
- git add . ; \
- git commit -m "Bumped version to $$version"; \
- echo Bumped version to $$version
+ @read -p "Enter version number: " version; \
+ echo "// GENERATED FILE: Do not edit directly\n\ninternal let __sdkVersion = \"$$version\"" > DatadogCore/Sources/Versioning.swift; \
+ ./tools/podspec_bump_version.sh $$version; \
+ git add . ; \
+ git commit -m "Bumped version to $$version"; \
+ echo Bumped version to $$version
diff --git a/Package.swift b/Package.swift
index 4175171f79..9a2b4c5bd7 100644
--- a/Package.swift
+++ b/Package.swift
@@ -3,6 +3,10 @@
import PackageDescription
import Foundation
+let opentelemetry = ProcessInfo.processInfo.environment["OTEL_SWIFT"] != nil ?
+ (name: "opentelemetry-swift", url: "https://github.com/open-telemetry/opentelemetry-swift.git") :
+ (name: "opentelemetry-swift-packages", url: "https://github.com/DataDog/opentelemetry-swift-packages.git")
+
let package = Package(
name: "Datadog",
platforms: [
@@ -47,7 +51,7 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/microsoft/plcrashreporter.git", from: "1.11.2"),
- .package(url: "https://github.com/DataDog/opentelemetry-swift-packages.git", exact: "1.6.0")
+ .package(url: opentelemetry.url, exact: "1.6.0"),
],
targets: [
.target(
@@ -112,7 +116,7 @@ let package = Package(
name: "DatadogTrace",
dependencies: [
.target(name: "DatadogInternal"),
- .product(name: "OpenTelemetryApi", package: "opentelemetry-swift-packages")
+ .product(name: "OpenTelemetryApi", package: opentelemetry.name)
],
path: "DatadogTrace/Sources"
),
@@ -207,7 +211,6 @@ let package = Package(
]
)
-
// If the `DD_TEST_UTILITIES_ENABLED` development ENV is set, export additional utility packages.
// To set this ENV for Xcode projects that fetch this package locally, use `open --env DD_TEST_UTILITIES_ENABLED path/to/`.
if ProcessInfo.processInfo.environment["DD_TEST_UTILITIES_ENABLED"] != nil {
diff --git a/README.md b/README.md
index 0a78f7067e..4e0e8ae57e 100644
--- a/README.md
+++ b/README.md
@@ -44,9 +44,7 @@ RUM allows you to monitor web views and eliminate blind spots in your hybrid mob
## Integrations
-### Alamofire
-
-If you use [Alamofire][4], review the [`Datadog Alamofire Extension` library](DatadogExtensions/Alamofire/) to learn how to automatically instrument requests with the Datadog iOS SDK.
+If you use [Alamofire][7] or [Apollo GraphQL][8], see [Integrated Libraries][4] to learn how to instrument requests automatically.
## Contributing
@@ -63,6 +61,8 @@ See the [Supported Versions][6] documentation for more details.
[1]: https://docs.datadoghq.com/logs/log_collection/ios
[2]: https://docs.datadoghq.com/tracing/setup_overview/setup/ios
[3]: https://docs.datadoghq.com/real_user_monitoring/ios
-[4]: https://github.com/Alamofire/Alamofire
+[4]: https://docs.datadoghq.com/real_user_monitoring/mobile_and_tv_monitoring/integrated_libraries/ios
[5]: https://docs.datadoghq.com/real_user_monitoring/mobile_and_tv_monitoring/web_view_tracking?tab=ios
-[6]: https://docs.datadoghq.com/real_user_monitoring/mobile_and_tv_monitoring/supported_versions/ios/
\ No newline at end of file
+[6]: https://docs.datadoghq.com/real_user_monitoring/mobile_and_tv_monitoring/supported_versions/ios/
+[7]: https://github.com/Alamofire/Alamofire
+[8]: https://github.com/apollographql/apollo-ios
diff --git a/TestUtilities.podspec b/TestUtilities.podspec
index 9207ebe004..cb6483dbd2 100644
--- a/TestUtilities.podspec
+++ b/TestUtilities.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "TestUtilities"
- s.version = "2.15.0"
+ s.version = "2.16.0"
s.summary = "Datadog Testing Utilities. This module is for internal testing and should not be published."
s.homepage = "https://www.datadoghq.com"
diff --git a/tools/benchmark-build-upload.sh b/tools/benchmark-build-upload.sh
new file mode 100755
index 0000000000..5b44778242
--- /dev/null
+++ b/tools/benchmark-build-upload.sh
@@ -0,0 +1,72 @@
+#!/bin/zsh
+
+# Usage:
+# $ ./tools/benchmark-build-upload.sh -h
+# Publishes IPA of a new version of the Benchmark app to synthetics.
+
+# Options:
+# --artifacts-path: Path where the IPA artifact will be exported.
+
+# ENVs:
+# - DRY_RUN: Set to '1' to do everything except uploading the IPA to synthetics.
+
+set +x
+set -eo pipefail
+source ./tools/utils/argparse.sh
+source ./tools/utils/echo-color.sh
+source ./tools/utils/code-sign.sh
+source ./tools/secrets/get-secret.sh
+
+set_description "Publishes IPA a new version of the Benchamrk app to synthetics."
+define_arg "artifacts-path" "" "Path where the IPA artifact will be exported." "string" "true"
+
+check_for_help "$@"
+parse_args "$@"
+
+BENCHMARK_DIR="BenchmarkTests"
+BENCHMARK_XCCONFIG_PATH="$BENCHMARK_DIR/xcconfigs/Benchmarks.local.xcconfig"
+BENCHMARK_CODESIGN_DIR="$BENCHMARK_DIR/benchmark-signing"
+P12_PATH="$BENCHMARK_CODESIGN_DIR/cert.p12"
+PP_PATH="$BENCHMARK_CODESIGN_DIR/runner.mobileprovision"
+
+ARTIFACTS_PATH="$(realpath .)/$artifacts_path"
+
+create_xcconfig() {
+ echo_subtitle "Create '$BENCHMARK_XCCONFIG_PATH'"
+ get_secret $DD_IOS_SECRET__BENCHMARK_XCCONFIG_BASE64 | base64 --decode -o $BENCHMARK_XCCONFIG_PATH
+ echo_succ "▸ '$BENCHMARK_XCCONFIG_PATH' ready"
+}
+
+create_codesign_files() {
+ echo_subtitle "Create codesign files in '$BENCHMARK_CODESIGN_DIR'"
+ rm -rf "$BENCHMARK_CODESIGN_DIR"
+ mkdir -p "$BENCHMARK_CODESIGN_DIR"
+ get_secret $DD_IOS_SECRET__DEV_CERTIFICATE_P12_BASE64 | base64 --decode -o $P12_PATH
+ echo_succ "▸ $P12_PATH - ready"
+ get_secret $DD_IOS_SECRET__BENCHMARK_PROVISIONING_PROFILE_BASE64 | base64 --decode -o $PP_PATH
+ echo_succ "▸ $PP_PATH - ready"
+}
+
+trap cleanup_codesigning EXIT INT # clean up keychain on exit
+
+create_xcconfig
+create_codesign_files
+install_provisioning_profile $PP_PATH
+
+create_keychain
+keychain_import \
+ --p12 $P12_PATH \
+ --p12-password $(get_secret "$DD_IOS_SECRET__DEV_CERTIFICATE_P12_PASSWORD")
+
+echo_subtitle "Run 'make clean archive export upload ARTIFACTS_PATH=\"$ARTIFACTS_PATH\"' in '$BENCHMARK_DIR'"
+cd "$BENCHMARK_DIR"
+make clean archive export ARTIFACTS_PATH="$ARTIFACTS_PATH"
+
+if [ "$DRY_RUN" = "1" ] || [ "$DRY_RUN" = "true" ]; then
+ echo_warn "Running in DRY RUN mode. Skipping 'make upload'."
+else
+ export DATADOG_API_KEY=$(get_secret $DD_IOS_SECRET__MI_S8S_API_KEY)
+ export DATADOG_APP_KEY=$(get_secret $DD_IOS_SECRET__MI_S8S_APP_KEY)
+ export S8S_APPLICATION_ID=$(get_secret $DD_IOS_SECRET__BENCHMARK_S8S_APPLICATION_ID)
+ make upload ARTIFACTS_PATH="$ARTIFACTS_PATH"
+fi
diff --git a/tools/clean.sh b/tools/clean.sh
index 54d27188f7..d3377b468b 100755
--- a/tools/clean.sh
+++ b/tools/clean.sh
@@ -17,6 +17,7 @@ clean_dir() {
}
clean_dir ~/Library/Developer/Xcode/DerivedData
+clean_dir ~/Library/Caches/org.carthage.CarthageKit/dependencies/
clean_dir ./Carthage/Build
clean_dir ./Carthage/Checkouts
clean_dir ./IntegrationTests/Pods
diff --git a/tools/e2e-build-upload.sh b/tools/e2e-build-upload.sh
index 2064e39ff8..fc1feca3cb 100755
--- a/tools/e2e-build-upload.sh
+++ b/tools/e2e-build-upload.sh
@@ -14,6 +14,7 @@ set +x
set -eo pipefail
source ./tools/utils/argparse.sh
source ./tools/utils/echo-color.sh
+source ./tools/utils/code-sign.sh
source ./tools/secrets/get-secret.sh
set_description "Publishes IPA a new version of the E2E app to synthetics."
@@ -22,21 +23,15 @@ define_arg "artifacts-path" "" "Path where the IPA artifact will be exported." "
check_for_help "$@"
parse_args "$@"
-KEYCHAIN=datadog.e2e.keychain
-KEYCHAIN_PASSWORD="$(openssl rand -base64 32)"
-PROFILE=datadog.e2e.mobileprovision
-
E2E_DIR="E2ETests"
E2E_XCCONFIG_PATH="$E2E_DIR/xcconfigs/E2E.local.xcconfig"
E2E_CODESIGN_DIR="$E2E_DIR/code-signing"
P12_PATH="$E2E_CODESIGN_DIR/e2e_cert.p12"
PP_PATH="$E2E_CODESIGN_DIR/e2e.mobileprovision"
-PP_INSTALL_DIR="$HOME/Library/MobileDevice/Provisioning Profiles"
-PP_INSTALL_PATH="$PP_INSTALL_DIR/$PROFILE"
ARTIFACTS_PATH="$(realpath .)/$artifacts_path"
-create_e2e_xcconfig() {
+create_xcconfig() {
echo_subtitle "Create '$E2E_XCCONFIG_PATH'"
get_secret $DD_IOS_SECRET__E2E_XCCONFIG_BASE64 | base64 --decode -o $E2E_XCCONFIG_PATH
echo_succ "▸ '$E2E_XCCONFIG_PATH' ready"
@@ -46,79 +41,22 @@ create_codesign_files() {
echo_subtitle "Create codesign files in '$E2E_CODESIGN_DIR'"
rm -rf "$E2E_CODESIGN_DIR"
mkdir -p "$E2E_CODESIGN_DIR"
- get_secret $DD_IOS_SECRET__E2E_CERTIFICATE_P12_BASE64 | base64 --decode -o $P12_PATH
+ get_secret $DD_IOS_SECRET__DEV_CERTIFICATE_P12_BASE64 | base64 --decode -o $P12_PATH
echo_succ "▸ $P12_PATH - ready"
get_secret $DD_IOS_SECRET__E2E_PROVISIONING_PROFILE_BASE64 | base64 --decode -o $PP_PATH
echo_succ "▸ $PP_PATH - ready"
}
-setup_codesigning() {
- echo_subtitle "Setup code signing"
-
- # Create temporary keychain
- if ! security delete-keychain "$KEYCHAIN" 2>/dev/null; then
- echo_warn "▸ Keychain '$KEYCHAIN' not found, nothing to delete"
- fi
- if ! security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN"; then
- echo_err "▸ Error:" "Failed to create keychain '$KEYCHAIN'"
- return 1
- fi
- if ! security set-keychain-settings -lut 21600 "$KEYCHAIN"; then
- echo_err "▸ Error:" "Failed to set keychain settings for '$KEYCHAIN'"
- return 1
- fi
- if ! security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN"; then
- echo "▸ Error:" "Failed to unlock keychain '$KEYCHAIN'"
- return 1
- fi
- echo_succ "▸ '$KEYCHAIN' created and unlocked"
-
- # Import certificate to keychain
- P12_PASSWORD=$(get_secret "$DD_IOS_SECRET__E2E_CERTIFICATE_P12_PASSWORD")
- if ! security import "$P12_PATH" -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN"; then
- echo_err "▸ Error:" "Failed to import certificate from '$P12_PATH' to '$KEYCHAIN'"
- return 1
- fi
- echo_succ "▸ '$P12_PATH' certificate imported to '$KEYCHAIN'"
-
- if ! security list-keychain -d user -s "$KEYCHAIN" "login.keychain" "System.keychain"; then
- echo_err "▸ Error:" "Failed to configure keychain search list for '$KEYCHAIN'"
- return 1
- fi
- echo_succ "▸ '$KEYCHAIN' keychain search configured"
-
- if ! security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN" >/dev/null 2>&1; then
- echo_err "▸ Error:" "Failed to set key partition list for '$KEYCHAIN'"
- return 1
- fi
- echo_succ "▸ Permission granted for '$KEYCHAIN' keychain"
-
- # Install provisioning profile
- mkdir -p "$PP_INSTALL_DIR"
- if ! cp "$PP_PATH" "$PP_INSTALL_PATH"; then
- echo_err "▸ Error:" "Failed to install provisioning profile from '$PP_PATH' to '$PP_INSTALL_PATH'"
- return 1
- fi
- echo_succ "▸ '$PP_PATH' provisioning profile installed in '$PP_INSTALL_PATH'"
-}
-
-cleanup_codesigning() {
- echo_subtitle "Cleanup code signing"
-
- rm -f "$PP_INSTALL_PATH"
- echo_info "▸ '$PP_INSTALL_PATH' deleted"
-
- if security delete-keychain "$KEYCHAIN" 2>/dev/null; then
- echo_info "▸ '$KEYCHAIN' deleted"
- else
- echo_warn "▸ Keychain '$KEYCHAIN' not found or failed to delete"
- fi
-}
+trap cleanup_codesigning EXIT INT # clean up keychain on exit
-create_e2e_xcconfig
+create_xcconfig
create_codesign_files
-trap cleanup_codesigning EXIT INT # clean up keychain on exit
-setup_codesigning
+install_provisioning_profile $PP_PATH
+
+create_keychain
+keychain_import \
+ --p12 $P12_PATH \
+ --p12-password $(get_secret "$DD_IOS_SECRET__DEV_CERTIFICATE_P12_PASSWORD")
echo_subtitle "Run 'make clean archive export upload ARTIFACTS_PATH=\"$ARTIFACTS_PATH\"' in '$E2E_DIR'"
cd "$E2E_DIR"
@@ -127,8 +65,8 @@ make clean archive export ARTIFACTS_PATH="$ARTIFACTS_PATH"
if [ "$DRY_RUN" = "1" ] || [ "$DRY_RUN" = "true" ]; then
echo_warn "Running in DRY RUN mode. Skipping 'make upload'."
else
- export DATADOG_API_KEY=$(get_secret $DD_IOS_SECRET__E2E_S8S_API_KEY)
- export DATADOG_APP_KEY=$(get_secret $DD_IOS_SECRET__E2E_S8S_APP_KEY)
+ export DATADOG_API_KEY=$(get_secret $DD_IOS_SECRET__MI_S8S_API_KEY)
+ export DATADOG_APP_KEY=$(get_secret $DD_IOS_SECRET__MI_S8S_APP_KEY)
export S8S_APPLICATION_ID=$(get_secret $DD_IOS_SECRET__E2E_S8S_APPLICATION_ID)
make upload ARTIFACTS_PATH="$ARTIFACTS_PATH"
fi
diff --git a/tools/secrets/check-secrets.sh b/tools/secrets/check-secrets.sh
index 76e87b28df..794509b378 100755
--- a/tools/secrets/check-secrets.sh
+++ b/tools/secrets/check-secrets.sh
@@ -3,7 +3,7 @@
# Checks if all secret values are available in current env.
#
# Usage:
-# $ ./tools/secrets/set-secret.sh
+# $ ./tools/secrets/check-secrets.sh
#
# Note:
# - Requires `vault` to be installed
diff --git a/tools/secrets/config.sh b/tools/secrets/config.sh
index aa987198ac..8b281fc216 100644
--- a/tools/secrets/config.sh
+++ b/tools/secrets/config.sh
@@ -16,13 +16,16 @@ DD_IOS_SECRET__GH_CLI_TOKEN="gh.cli.token"
DD_IOS_SECRET__CARTHAGE_GH_TOKEN="carthage.gh.token"
DD_IOS_SECRET__CP_TRUNK_TOKEN="cocoapods.trunk.token"
DD_IOS_SECRET__SSH_KEY="ssh.key"
-DD_IOS_SECRET__E2E_CERTIFICATE_P12_BASE64="e2e.certificate.p12.base64"
-DD_IOS_SECRET__E2E_CERTIFICATE_P12_PASSWORD="e2e.certificate.p12.password"
+DD_IOS_SECRET__DEV_CERTIFICATE_P12_BASE64="dev.certificate.p12.base64"
+DD_IOS_SECRET__DEV_CERTIFICATE_P12_PASSWORD="dev.certificate.p12.password"
+DD_IOS_SECRET__MI_S8S_API_KEY="mi.s8s.api.key"
+DD_IOS_SECRET__MI_S8S_APP_KEY="mi.s8s.app.key"
DD_IOS_SECRET__E2E_PROVISIONING_PROFILE_BASE64="e2e.provisioning.profile.base64"
DD_IOS_SECRET__E2E_XCCONFIG_BASE64="e2e.xcconfig.base64"
-DD_IOS_SECRET__E2E_S8S_API_KEY="e2e.s8s.api.key"
-DD_IOS_SECRET__E2E_S8S_APP_KEY="e2e.s8s.app.key"
DD_IOS_SECRET__E2E_S8S_APPLICATION_ID="e2e.s8s.app.id"
+DD_IOS_SECRET__BENCHMARK_PROVISIONING_PROFILE_BASE64="benchmark.provisioning.profile.base64"
+DD_IOS_SECRET__BENCHMARK_XCCONFIG_BASE64="benchmark.xcconfig.base64"
+DD_IOS_SECRET__BENCHMARK_S8S_APPLICATION_ID="benchmark.s8s.app.id"
idx=0
declare -A DD_IOS_SECRETS
@@ -31,10 +34,13 @@ DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__GH_CLI_TOKEN | GitHub token to authe
DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__CARTHAGE_GH_TOKEN | GitHub token to avoid rate limiting Carthage commands (https://github.com/Carthage/Carthage/pull/605)"
DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__CP_TRUNK_TOKEN | Cocoapods token to authenticate 'pod trunk' operations (https://guides.cocoapods.org/terminal/commands.html)"
DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__SSH_KEY | SSH key to authenticate 'git clone git@github.com:...' operations"
-DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__E2E_CERTIFICATE_P12_BASE64 | Base64-encoded '.p12' certificate file for signing E2E app"
-DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__E2E_CERTIFICATE_P12_PASSWORD | Password to '$DD_IOS_SECRET__E2E_CERTIFICATE_P12_BASE64' certificate"
+DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__DEV_CERTIFICATE_P12_BASE64 | Base64-encoded '.p12' developer certificate file for signing apps"
+DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__DEV_CERTIFICATE_P12_PASSWORD | Password to '$DD_IOS_SECRET__DEV_CERTIFICATE_P12_PASSWORD' certificate"
+DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__MI_S8S_API_KEY | DATADOG_API_KEY for uploading app to synthetics in Mobile - Integration org"
+DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__MI_S8S_APP_KEY | DATADOG_APP_KEY for uploading app to synthetics in Mobile - Integration org"
DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__E2E_PROVISIONING_PROFILE_BASE64 | Base64-encoded provisioning profile file for signing E2E app"
DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__E2E_XCCONFIG_BASE64 | Base64-encoded xcconfig file for E2E app"
-DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__E2E_S8S_API_KEY | DATADOG_API_KEY for uploading E2E app to synthetics"
-DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__E2E_S8S_APP_KEY | DATADOG_APP_KEY for uploading E2E app to synthetics"
DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__E2E_S8S_APPLICATION_ID | Synthetics app ID for E2E tests"
+DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__BENCHMARK_PROVISIONING_PROFILE_BASE64 | Base64-encoded provisioning profile file for signing Benchmark app"
+DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__BENCHMARK_XCCONFIG_BASE64 | Base64-encoded xcconfig file for Benchmark app"
+DD_IOS_SECRETS[$((idx++))]="$DD_IOS_SECRET__BENCHMARK_S8S_APPLICATION_ID | Synthetics app ID for Benchmark tests"
diff --git a/tools/sr-snapshot-test.sh b/tools/sr-snapshot-test.sh
index 380b438776..63a1c30828 100755
--- a/tools/sr-snapshot-test.sh
+++ b/tools/sr-snapshot-test.sh
@@ -75,9 +75,7 @@ test_snapshots() {
open_snapshot_tests_project() {
echo_info "Opening SRSnapshotTests with DD_TEST_UTILITIES_ENABLED ..."
- pgrep -q Xcode && killall Xcode && echo_warn "- Xcode killed" || echo_succ "- Xcode not running"
- sleep 0.5 && echo "- launching" # Sleep, otherwise, if Xcode was running it often fails with "procNotFound: no eligible process with specified descriptor"
- open --env DD_TEST_UTILITIES_ENABLED "$TEST_WORKSPACE"
+ open --new --env DD_TEST_UTILITIES_ENABLED "$TEST_WORKSPACE"
}
if [ "$open_project" = "true" ]; then
diff --git a/tools/utils/code-sign.sh b/tools/utils/code-sign.sh
new file mode 100755
index 0000000000..4a7cc53c06
--- /dev/null
+++ b/tools/utils/code-sign.sh
@@ -0,0 +1,90 @@
+#!/bin/zsh
+
+set +x
+set -eo pipefail
+source ./tools/utils/echo-color.sh
+
+KEYCHAIN=datadog.keychain
+KEYCHAIN_PASSWORD="$(openssl rand -base64 32)"
+
+PROFILE=datadog.mobileprovision
+USER_PP_DIR="$HOME/Library/MobileDevice/Provisioning Profiles"
+USER_PP_PATH="$USER_PP_DIR/$PROFILE"
+
+cleanup_codesigning() {
+ echo_subtitle "Cleanup code signing"
+
+ rm -f "$PP_PATH"
+ echo_info "▸ '$PP_PATH' deleted"
+
+ if security delete-keychain "$KEYCHAIN" 2>/dev/null; then
+ echo_info "▸ '$KEYCHAIN' deleted"
+ else
+ echo_warn "▸ Keychain '$KEYCHAIN' not found or failed to delete"
+ fi
+}
+
+create_keychain() {
+ # Create temporary keychain
+ if ! security delete-keychain "$KEYCHAIN" 2>/dev/null; then
+ echo_warn "▸ Keychain '$KEYCHAIN' not found, nothing to delete"
+ fi
+ if ! security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN"; then
+ echo_err "▸ Error:" "Failed to create keychain '$KEYCHAIN'"
+ return 1
+ fi
+ if ! security set-keychain-settings -lut 21600 "$KEYCHAIN"; then
+ echo_err "▸ Error:" "Failed to set keychain settings for '$KEYCHAIN'"
+ return 1
+ fi
+ if ! security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN"; then
+ echo "▸ Error:" "Failed to unlock keychain '$KEYCHAIN'"
+ return 1
+ fi
+ echo_succ "▸ '$KEYCHAIN' created and unlocked"
+}
+
+keychain_import() {
+ # read cmd arguments
+ while :; do
+ case $1 in
+ --p12) P12_PATH=$2
+ shift
+ ;;
+ --p12-password) P12_PASSWORD=$2
+ shift
+ ;;
+ *) break
+ esac
+ shift
+ done
+
+ # Import certificate to keychain
+ if ! security import "$P12_PATH" -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN"; then
+ echo_err "▸ Error:" "Failed to import certificate from '$p12' to '$KEYCHAIN'"
+ return 1
+ fi
+ echo_succ "▸ '$P12_PATH' certificate imported to '$KEYCHAIN'"
+
+ if ! security list-keychain -d user -s "$KEYCHAIN" "login.keychain" "System.keychain"; then
+ echo_err "▸ Error:" "Failed to configure keychain search list for '$KEYCHAIN'"
+ return 1
+ fi
+ echo_succ "▸ '$KEYCHAIN' keychain search configured"
+
+ if ! security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN" >/dev/null 2>&1; then
+ echo_err "▸ Error:" "Failed to set key partition list for '$KEYCHAIN'"
+ return 1
+ fi
+ echo_succ "▸ Permission granted for '$KEYCHAIN' keychain"
+}
+
+install_provisioning_profile() {
+ # Install provisioning profile
+ mkdir -p "$USER_PP_DIR"
+ if ! cp "$1" "$USER_PP_PATH"; then
+ echo_err "▸ Error:" "Failed to install provisioning profile from '$1' to '$USER_PP_PATH'"
+ return 1
+ fi
+ echo_succ "▸ '$1' provisioning profile installed in '$USER_PP_PATH'"
+}