Skip to content

Commit

Permalink
🚩RUM-1755 Add config overrides for debug launch arguments
Browse files Browse the repository at this point in the history
Adds two launch arguments:
DD_DEBUG sets sampling to 100%, verbosity to debug, and upload frequency to freqeunt
DD_DEBUG_RUM enables Datadog.debugRUM

All of these settings are changed during initialization to override whatever configuration the user set
  • Loading branch information
fuzzybinary committed Dec 2, 2021
1 parent f7c7a3a commit 6e3da95
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 20 deletions.
10 changes: 10 additions & 0 deletions Datadog/Datadog.xcodeproj/xcshareddata/xcschemes/Example.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@
ReferencedContainer = "container:Datadog.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "DD_DEBUG"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "DD_DEBUG_RUM"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
<EnvironmentVariables>
<EnvironmentVariable
key = "DD_TEST_SCENARIO_CLASS_NAME"
Expand Down
63 changes: 45 additions & 18 deletions Sources/Datadog/Core/System/MobileDevice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ internal class MobileDevice {
let model: String
let osName: String
let osVersion: String
let processInfo: ProcessInfo

// MARK: - Battery status monitoring

Expand Down Expand Up @@ -40,13 +41,15 @@ internal class MobileDevice {
model: String,
osName: String,
osVersion: String,
processInfo: ProcessInfo,
enableBatteryStatusMonitoring: @escaping () -> Void,
resetBatteryStatusMonitoring: @escaping () -> Void,
currentBatteryStatus: @escaping () -> BatteryStatus
) {
self.model = model
self.osName = osName
self.osVersion = osVersion
self.processInfo = processInfo
self.enableBatteryStatusMonitoring = enableBatteryStatusMonitoring
self.resetBatteryStatusMonitoring = resetBatteryStatusMonitoring
self.currentBatteryStatus = currentBatteryStatus
Expand All @@ -63,6 +66,7 @@ internal class MobileDevice {
model: uiDevice.model,
osName: uiDevice.systemName,
osVersion: uiDevice.systemVersion,
processInfo: processInfo,
enableBatteryStatusMonitoring: { uiDevice.isBatteryMonitoringEnabled = true },
resetBatteryStatusMonitoring: { uiDevice.isBatteryMonitoringEnabled = wasBatteryMonitoringEnabled },
currentBatteryStatus: {
Expand All @@ -74,28 +78,51 @@ internal class MobileDevice {
}
)
}

// MARK: - Singleton
private static var _instance: MobileDevice?

/// Returns current mobile device if `UIDevice` is available on this platform.
/// On other platforms returns `nil`.
static var current: MobileDevice {
#if !targetEnvironment(simulator)
// Real device
return MobileDevice(
uiDevice: UIDevice.current,
processInfo: ProcessInfo.processInfo,
notificationCenter: .default
)
#else
// iOS Simulator - battery monitoring doesn't work on Simulator, so return "always OK" value
return MobileDevice(
model: UIDevice.current.model,
osName: UIDevice.current.systemName,
osVersion: UIDevice.current.systemVersion,
enableBatteryStatusMonitoring: {},
resetBatteryStatusMonitoring: {},
currentBatteryStatus: { BatteryStatus(state: .full, level: 1, isLowPowerModeEnabled: false) }
)
#endif
get {
if let instance = _instance {
return instance
}

#if !targetEnvironment(simulator)
// Real device
_instance = MobileDevice(
uiDevice: UIDevice.current,
processInfo: ProcessInfo.processInfo,
notificationCenter: .default
)
#else
// iOS Simulator - battery monitoring doesn't work on Simulator, so return "always OK" value
_instance = MobileDevice(
model: UIDevice.current.model,
osName: UIDevice.current.systemName,
osVersion: UIDevice.current.systemVersion,
processInfo: ProcessInfo.processInfo,
enableBatteryStatusMonitoring: {},
resetBatteryStatusMonitoring: {},
currentBatteryStatus: { BatteryStatus(state: .full, level: 1, isLowPowerModeEnabled: false) }
)
#endif

// swiftlint:disable:next force_unwrapping
return _instance!
}
set(newInstance) {
_instance = newInstance
}
}

#if DD_SDK_COMPILED_FOR_TESTING
static func clearForTesting() {
_instance = nil
}
#endif

private static func toBatteryState(_ uiDeviceBatteryState: UIDevice.BatteryState) -> BatteryStatus.State {
switch uiDeviceBatteryState {
Expand Down
28 changes: 27 additions & 1 deletion Sources/Datadog/Datadog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,40 @@ public class Datadog {
trackingConsent: TrackingConsent,
configuration: Configuration
) {
var mutableConfiguration = configuration

// TODO: RUMM-511 remove this warning
#if targetEnvironment(macCatalyst)
consolePrint("⚠️ Catalyst is not officially supported by Datadog SDK: some features may NOT be functional!")
#endif

let mobileDevice = MobileDevice.current
let debugOverride = mobileDevice.processInfo.arguments.contains(LaunchArguments.Debug)
if debugOverride {
consolePrint("⚠️ Overriding sampling, verbosity, and upload frequency due to \(LaunchArguments.Debug) launch argument")
let rebuilder = Configuration.Builder(configuration: mutableConfiguration)
.set(rumSessionsSamplingRate: 100)
.set(batchSize: .small)
.set(uploadFrequency: .frequent)
mutableConfiguration = rebuilder.build()
Datadog.verbosityLevel = .debug
}

do {
try initializeOrThrow(
initialTrackingConsent: trackingConsent,
configuration: try FeaturesConfiguration(
configuration: configuration,
configuration: mutableConfiguration,
appContext: appContext
)
)

// Now that RUM is potentially initialized, override the debugRUM value
let debugRumOverride = mobileDevice.processInfo.arguments.contains(LaunchArguments.DebugRUM)
if debugRumOverride {
consolePrint("⚠️ Overriding RUM debugging due to \(LaunchArguments.DebugRUM) launch argument")
Datadog.debugRUM = true
}
} catch {
consolePrint("\(error)")
}
Expand Down Expand Up @@ -140,6 +162,10 @@ public class Datadog {
}

// MARK: - Internal
internal struct LaunchArguments {
static let Debug = "DD_DEBUG"
static let DebugRUM = "DD_DEBUG_RUM"
}

internal static var instance: Datadog?

Expand Down
5 changes: 5 additions & 0 deletions Sources/Datadog/DatadogConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ extension Datadog {
)
}

/// Used internally to rebuild a configuration based on launch arguments
internal init(configuration: Configuration) {
self.configuration = configuration
}

/// Sets the Datadog server endpoint where data is sent.
///
/// If set, it will override values set by any of these deprecated APIs:
Expand Down
63 changes: 63 additions & 0 deletions Tests/DatadogTests/Datadog/DatadogTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class DatadogTests: XCTestCase {

override func setUp() {
super.setUp()
MobileDevice.clearForTesting()

XCTAssertFalse(Datadog.isInitialized)
printFunction = PrintFunctionMock()
consolePrint = printFunction.print
Expand Down Expand Up @@ -329,6 +331,67 @@ class DatadogTests: XCTestCase {
}
}

func testSupplyingDebugLaunchArgument_itOverridesUserSettings() {
let mockProcessInfo = ProcessInfoMock(
arguments: [Datadog.LaunchArguments.Debug]
)

MobileDevice.current = MobileDevice.mockWith(
processInfo: mockProcessInfo
)

let configuration = rumBuilder
.set(uploadFrequency: .rare)
.set(rumSessionsSamplingRate: 20.0)
.set(batchSize: .medium)
.build()

Datadog.initialize(
appContext: .mockAny(),
trackingConsent: .pending,
configuration: configuration
)

let expectedPerformancePreset = PerformancePreset(
batchSize: .small,
uploadFrequency: .frequent,
bundleType: .iOSApp
)
XCTAssertEqual(RUMFeature.instance?.configuration.sessionSamplingRate, 100)
XCTAssertEqual(TracingFeature.instance?.configuration.common.performance, expectedPerformancePreset)
XCTAssertEqual(LoggingFeature.instance?.configuration.common.performance, expectedPerformancePreset)
XCTAssertEqual(Datadog.verbosityLevel, .debug)

// Clear default verbosity after this test
Datadog.verbosityLevel = nil
Datadog.flushAndDeinitialize()
}

func testSupplyingRumDebugLaunchArgument_itSetsRumDebug() {
let mockProcessInfo = ProcessInfoMock(
arguments: [Datadog.LaunchArguments.DebugRUM]
)

MobileDevice.current = MobileDevice.mockWith(
processInfo: mockProcessInfo
)

let configuration = rumBuilder
.build()

Datadog.initialize(
appContext: .mockAny(),
trackingConsent: .pending,
configuration: configuration
)

XCTAssertTrue(Datadog.debugRUM)

// Clear debug after test
Datadog.debugRUM = false
Datadog.flushAndDeinitialize()
}

// MARK: - Public APIs

func testTrackingConsent() {
Expand Down
2 changes: 2 additions & 0 deletions Tests/DatadogTests/Datadog/Mocks/CoreMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,7 @@ extension MobileDevice {
model: String = .mockAny(),
osName: String = .mockAny(),
osVersion: String = .mockAny(),
processInfo: ProcessInfo = ProcessInfoMock(),
enableBatteryStatusMonitoring: @escaping () -> Void = {},
resetBatteryStatusMonitoring: @escaping () -> Void = {},
currentBatteryStatus: @escaping () -> BatteryStatus = { .mockAny() }
Expand All @@ -794,6 +795,7 @@ extension MobileDevice {
model: model,
osName: osName,
osVersion: osVersion,
processInfo: processInfo,
enableBatteryStatusMonitoring: enableBatteryStatusMonitoring,
resetBatteryStatusMonitoring: resetBatteryStatusMonitoring,
currentBatteryStatus: currentBatteryStatus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,12 +408,16 @@ extension URLRequest: AnyMockable {

class ProcessInfoMock: ProcessInfo {
private var _isLowPowerModeEnabled: Bool
private var _arguments: [String]

init(isLowPowerModeEnabled: Bool = .mockAny()) {
init(isLowPowerModeEnabled: Bool = .mockAny(), arguments: [String] = []) {
_isLowPowerModeEnabled = isLowPowerModeEnabled
_arguments = arguments
}

override var isLowPowerModeEnabled: Bool { _isLowPowerModeEnabled }

override var arguments: [String] { _arguments }
}

// MARK: - URLSession
Expand Down

0 comments on commit 6e3da95

Please sign in to comment.