Skip to content

Commit

Permalink
RUM-5248 feat: send memory warning as RUM error
Browse files Browse the repository at this point in the history
  • Loading branch information
ganeshnj committed Jul 17, 2024
1 parent 216873d commit 3f527c3
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- [FEATURE] Enable DatadogCore, DatadogLogs and DatadogTrace to compile on watchOS platform. See [#1918][] (Thanks [@jfiser-paylocity][]) [#1946][]
- [IMPROVEMENT] Ability to clear feature data storage using `clearAllData` API. See [#1940][]
- [IMPROVEMENT] Send memory warning as RUM error.

# 2.14.1 / 09-07-2024

Expand Down
46 changes: 46 additions & 0 deletions Datadog/Datadog.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@
3C41693C29FBF4D50042B9D2 /* DatadogWebViewTracking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CE119FE29F7BE0100202522 /* DatadogWebViewTracking.framework */; };
3C43A3882C188974000BFB21 /* WatchdogTerminationMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C43A3862C188970000BFB21 /* WatchdogTerminationMonitorTests.swift */; };
3C43A3892C188975000BFB21 /* WatchdogTerminationMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C43A3862C188970000BFB21 /* WatchdogTerminationMonitorTests.swift */; };
3C4CF9912C47BE07006DE1C0 /* MemoryWarningMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8C12C3EBA1700B12303 /* MemoryWarningMonitor.swift */; };
3C4CF9922C47BE07006DE1C0 /* MemoryWarningMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8C12C3EBA1700B12303 /* MemoryWarningMonitor.swift */; };
3C4CF9942C47CAE9006DE1C0 /* MemoryWarning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8C42C3EC61500B12303 /* MemoryWarning.swift */; };
3C4CF9952C47CAEA006DE1C0 /* MemoryWarning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8C42C3EC61500B12303 /* MemoryWarning.swift */; };
3C4CF9982C47CC91006DE1C0 /* MemoryWarningMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4CF9972C47CC8C006DE1C0 /* MemoryWarningMonitorTests.swift */; };
3C4CF9992C47CC92006DE1C0 /* MemoryWarningMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4CF9972C47CC8C006DE1C0 /* MemoryWarningMonitorTests.swift */; };
3C4CF99B2C47DAA5006DE1C0 /* MemoryWarningMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4CF99A2C47DAA5006DE1C0 /* MemoryWarningMocks.swift */; };
3C4CF99C2C47DAA5006DE1C0 /* MemoryWarningMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4CF99A2C47DAA5006DE1C0 /* MemoryWarningMocks.swift */; };
3C5CD8CD2C3ECB9400B12303 /* MemoryWarningReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8CA2C3ECB4800B12303 /* MemoryWarningReporter.swift */; };
3C5CD8CE2C3ECB9400B12303 /* MemoryWarningReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5CD8CA2C3ECB4800B12303 /* MemoryWarningReporter.swift */; };
3C5D63692B55512B00FEB4BA /* OTelTraceState+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5D63682B55512B00FEB4BA /* OTelTraceState+Datadog.swift */; };
3C5D636A2B55512B00FEB4BA /* OTelTraceState+Datadog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5D63682B55512B00FEB4BA /* OTelTraceState+Datadog.swift */; };
3C5D636C2B55513500FEB4BA /* OTelTraceState+DatadogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C5D636B2B55513500FEB4BA /* OTelTraceState+DatadogTests.swift */; };
Expand Down Expand Up @@ -2107,6 +2117,11 @@
3C33E4062BEE35A7003B2988 /* RUMContextMocks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RUMContextMocks.swift; sourceTree = "<group>"; };
3C3EF2AF2C1AEBAB009E9E57 /* LaunchReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchReport.swift; sourceTree = "<group>"; };
3C43A3862C188970000BFB21 /* WatchdogTerminationMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchdogTerminationMonitorTests.swift; sourceTree = "<group>"; };
3C4CF9972C47CC8C006DE1C0 /* MemoryWarningMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryWarningMonitorTests.swift; sourceTree = "<group>"; };
3C4CF99A2C47DAA5006DE1C0 /* MemoryWarningMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryWarningMocks.swift; sourceTree = "<group>"; };
3C5CD8C12C3EBA1700B12303 /* MemoryWarningMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryWarningMonitor.swift; sourceTree = "<group>"; };
3C5CD8C42C3EC61500B12303 /* MemoryWarning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryWarning.swift; sourceTree = "<group>"; };
3C5CD8CA2C3ECB4800B12303 /* MemoryWarningReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryWarningReporter.swift; sourceTree = "<group>"; };
3C5D63682B55512B00FEB4BA /* OTelTraceState+Datadog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OTelTraceState+Datadog.swift"; sourceTree = "<group>"; };
3C5D636B2B55513500FEB4BA /* OTelTraceState+DatadogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OTelTraceState+DatadogTests.swift"; sourceTree = "<group>"; };
3C6C7FE02B459AAA006F5CBC /* OTelSpan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OTelSpan.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3404,6 +3419,25 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
3C4CF9932C47BE10006DE1C0 /* MemoryWarnings */ = {
isa = PBXGroup;
children = (
3C5CD8C42C3EC61500B12303 /* MemoryWarning.swift */,
3C5CD8C12C3EBA1700B12303 /* MemoryWarningMonitor.swift */,
3C5CD8CA2C3ECB4800B12303 /* MemoryWarningReporter.swift */,
);
path = MemoryWarnings;
sourceTree = "<group>";
};
3C4CF9962C47CC72006DE1C0 /* MemoryWarnings */ = {
isa = PBXGroup;
children = (
3C4CF9972C47CC8C006DE1C0 /* MemoryWarningMonitorTests.swift */,
3C4CF99A2C47DAA5006DE1C0 /* MemoryWarningMocks.swift */,
);
path = MemoryWarnings;
sourceTree = "<group>";
};
3C68FCD12C05EE8E00723696 /* WatchdogTerminations */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4811,6 +4845,7 @@
616CCE11250A181C009FED46 /* Instrumentation */ = {
isa = PBXGroup;
children = (
3C4CF9932C47BE10006DE1C0 /* MemoryWarnings */,
616CCE12250A1868009FED46 /* RUMCommandSubscriber.swift */,
616CCE15250A467E009FED46 /* RUMInstrumentation.swift */,
61F3CDA1251118DD00C816E5 /* Views */,
Expand Down Expand Up @@ -5478,6 +5513,7 @@
61F3CDA825121F8F00C816E5 /* Instrumentation */ = {
isa = PBXGroup;
children = (
3C4CF9962C47CC72006DE1C0 /* MemoryWarnings */,
61F3CDA925121FA100C816E5 /* Views */,
6141014C251A577D00E3C2D9 /* Actions */,
613F23EF252B1287006CD2D7 /* Resources */,
Expand Down Expand Up @@ -8706,8 +8742,10 @@
61C713AB2A3B790B00FA735A /* Monitor.swift in Sources */,
D23F8E6429DDCD28001CFAE8 /* SwiftUIViewHandler.swift in Sources */,
3CFF4F922C09E630006F191D /* WatchdogTerminationAppStateManager.swift in Sources */,
3C4CF9952C47CAEA006DE1C0 /* MemoryWarning.swift in Sources */,
D23F8E6529DDCD28001CFAE8 /* RUMFeature.swift in Sources */,
D23F8E6629DDCD28001CFAE8 /* RUMDebugging.swift in Sources */,
3C4CF9912C47BE07006DE1C0 /* MemoryWarningMonitor.swift in Sources */,
D23F8E6729DDCD28001CFAE8 /* RUMUUID.swift in Sources */,
D23F8E6829DDCD28001CFAE8 /* UIKitExtensions.swift in Sources */,
61C713A82A3B78F900FA735A /* RUMMonitorProtocol+Convenience.swift in Sources */,
Expand Down Expand Up @@ -8751,6 +8789,7 @@
D23F8E8229DDCD28001CFAE8 /* RUMSessionScope.swift in Sources */,
D23F8E8329DDCD28001CFAE8 /* RUMUser.swift in Sources */,
D23F8E8429DDCD28001CFAE8 /* UIKitRUMUserActionsPredicate.swift in Sources */,
3C5CD8CE2C3ECB9400B12303 /* MemoryWarningReporter.swift in Sources */,
D23F8E8529DDCD28001CFAE8 /* SwiftUIExtensions.swift in Sources */,
3CFF4F952C09E63C006F191D /* WatchdogTerminationChecker.swift in Sources */,
D23F8E8629DDCD28001CFAE8 /* RUMDataModelsMapping.swift in Sources */,
Expand Down Expand Up @@ -8778,6 +8817,7 @@
D23F8EA029DDCD38001CFAE8 /* RUMOffViewEventsHandlingRuleTests.swift in Sources */,
61C4534B2C0A0BBF00CC4C17 /* TelemetryInterceptorTests.swift in Sources */,
D23F8EA229DDCD38001CFAE8 /* RUMSessionScopeTests.swift in Sources */,
3C4CF9992C47CC92006DE1C0 /* MemoryWarningMonitorTests.swift in Sources */,
D23F8EA329DDCD38001CFAE8 /* RUMUserActionScopeTests.swift in Sources */,
615B0F8C2BB33C2800E9ED6C /* AppHangsMonitorTests.swift in Sources */,
61C713B42A3C3A0B00FA735A /* RUMMonitorProtocol+InternalTests.swift in Sources */,
Expand All @@ -8797,6 +8837,7 @@
61C713B72A3C600400FA735A /* RUMMonitorProtocol+ConvenienceTests.swift in Sources */,
D23F8EB129DDCD38001CFAE8 /* RUMViewScopeTests.swift in Sources */,
D224431029E977A100274EC7 /* TelemetryReceiverTests.swift in Sources */,
3C4CF99C2C47DAA5006DE1C0 /* MemoryWarningMocks.swift in Sources */,
3C43A3892C188975000BFB21 /* WatchdogTerminationMonitorTests.swift in Sources */,
D23F8EB229DDCD38001CFAE8 /* ValuePublisherTests.swift in Sources */,
6174D61B2BFE449300EC7469 /* SessionEndedMetricTests.swift in Sources */,
Expand Down Expand Up @@ -9035,8 +9076,10 @@
61C713AA2A3B790B00FA735A /* Monitor.swift in Sources */,
D29A9F8529DD85BB005C54A4 /* SwiftUIViewHandler.swift in Sources */,
3CFF4F912C09E630006F191D /* WatchdogTerminationAppStateManager.swift in Sources */,
3C4CF9942C47CAE9006DE1C0 /* MemoryWarning.swift in Sources */,
D29A9F7429DD85BB005C54A4 /* RUMFeature.swift in Sources */,
D29A9F7729DD85BB005C54A4 /* RUMDebugging.swift in Sources */,
3C4CF9922C47BE07006DE1C0 /* MemoryWarningMonitor.swift in Sources */,
D29A9F6E29DD85BB005C54A4 /* RUMUUID.swift in Sources */,
D29A9F8D29DD8665005C54A4 /* UIKitExtensions.swift in Sources */,
61C713A72A3B78F900FA735A /* RUMMonitorProtocol+Convenience.swift in Sources */,
Expand Down Expand Up @@ -9080,6 +9123,7 @@
D29A9F5C29DD85BB005C54A4 /* RUMSessionScope.swift in Sources */,
D29A9F6629DD85BB005C54A4 /* RUMUser.swift in Sources */,
D29A9F8229DD85BB005C54A4 /* UIKitRUMUserActionsPredicate.swift in Sources */,
3C5CD8CD2C3ECB9400B12303 /* MemoryWarningReporter.swift in Sources */,
D29A9F8E29DD8665005C54A4 /* SwiftUIExtensions.swift in Sources */,
3CFF4F942C09E63C006F191D /* WatchdogTerminationChecker.swift in Sources */,
D29A9F7829DD85BB005C54A4 /* RUMDataModelsMapping.swift in Sources */,
Expand Down Expand Up @@ -9107,6 +9151,7 @@
D29A9FA629DDB483005C54A4 /* RUMOffViewEventsHandlingRuleTests.swift in Sources */,
61C4534A2C0A0BBF00CC4C17 /* TelemetryInterceptorTests.swift in Sources */,
D29A9FBD29DDB483005C54A4 /* RUMSessionScopeTests.swift in Sources */,
3C4CF9982C47CC91006DE1C0 /* MemoryWarningMonitorTests.swift in Sources */,
D29A9FAB29DDB483005C54A4 /* RUMUserActionScopeTests.swift in Sources */,
615B0F8B2BB33C2800E9ED6C /* AppHangsMonitorTests.swift in Sources */,
61C713B32A3C3A0B00FA735A /* RUMMonitorProtocol+InternalTests.swift in Sources */,
Expand All @@ -9126,6 +9171,7 @@
61C713B62A3C600400FA735A /* RUMMonitorProtocol+ConvenienceTests.swift in Sources */,
D29A9FB829DDB483005C54A4 /* RUMViewScopeTests.swift in Sources */,
D224430F29E9779F00274EC7 /* TelemetryReceiverTests.swift in Sources */,
3C4CF99B2C47DAA5006DE1C0 /* MemoryWarningMocks.swift in Sources */,
3C43A3882C188974000BFB21 /* WatchdogTerminationMonitorTests.swift in Sources */,
D29A9F9D29DDB483005C54A4 /* ValuePublisherTests.swift in Sources */,
6174D61A2BFE449300EC7469 /* SessionEndedMetricTests.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion DatadogCore/Sources/Core/MessageBus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ internal final class MessageBus {
}

/// Removes the given key and its associated receiver from the bus.
///
///
/// - Parameter key: The key to remove along with its associated receiver.
func removeReceiver(forKey key: String) {
queue.async { self.bus.removeValue(forKey: key) }
Expand Down
5 changes: 4 additions & 1 deletion DatadogObjc/Sources/RUM/RUMDataModels+objc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1732,6 +1732,7 @@ public enum DDRUMErrorEventErrorCategory: Int {
case .appHang?: self = .appHang
case .exception?: self = .exception
case .watchdogTermination?: self = .watchdogTermination
case .memoryWarning?: self = .memoryWarning
}
}

Expand All @@ -1742,6 +1743,7 @@ public enum DDRUMErrorEventErrorCategory: Int {
case .appHang: return .appHang
case .exception: return .exception
case .watchdogTermination: return .watchdogTermination
case .memoryWarning: return .memoryWarning
}
}

Expand All @@ -1750,6 +1752,7 @@ public enum DDRUMErrorEventErrorCategory: Int {
case appHang
case exception
case watchdogTermination
case memoryWarning
}

@objc
Expand Down Expand Up @@ -7707,4 +7710,4 @@ public class DDTelemetryConfigurationEventView: NSObject {

// swiftlint:enable force_unwrapping

// Generated from https://github.com/DataDog/rum-events-format/tree/ae8c30a094339995e234fd55831ade0999bf0612
// Generated from https://github.com/DataDog/rum-events-format/tree/c853be6db33125c8767ae563d2af47b92636c4e1
3 changes: 2 additions & 1 deletion DatadogRUM/Sources/DataModels/RUMDataModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,7 @@ public struct RUMErrorEvent: RUMDataModel {
case appHang = "App Hang"
case exception = "Exception"
case watchdogTermination = "Watchdog Termination"
case memoryWarning = "Memory Warning"
}

/// Properties for one of the error causes
Expand Down Expand Up @@ -4334,4 +4335,4 @@ public struct RUMTelemetryOperatingSystem: Codable {
}
}

// Generated from https://github.com/DataDog/rum-events-format/tree/ae8c30a094339995e234fd55831ade0999bf0612
// Generated from https://github.com/DataDog/rum-events-format/tree/c853be6db33125c8767ae563d2af47b92636c4e1
9 changes: 8 additions & 1 deletion DatadogRUM/Sources/Feature/RUMFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ internal final class RUMFeature: DatadogRemoteFeature {
dateProvider: configuration.dateProvider
)

let memoryWarningReporter = MemoryWarningReporter()
let memoryWarningMonitor = MemoryWarningMonitor(
backtraceReporter: core.backtraceReporter,
memoryWarningReporter: memoryWarningReporter
)

self.instrumentation = RUMInstrumentation(
featureScope: featureScope,
uiKitRUMViewsPredicate: configuration.uiKitViewsPredicate,
Expand All @@ -119,7 +125,8 @@ internal final class RUMFeature: DatadogRemoteFeature {
backtraceReporter: core.backtraceReporter,
fatalErrorContext: dependencies.fatalErrorContext,
processID: configuration.processID,
watchdogTermination: watchdogTermination
watchdogTermination: watchdogTermination,
memoryWarningMonitor: memoryWarningMonitor
)
self.requestBuilder = RequestBuilder(
customIntakeURL: configuration.customEndpoint,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 UIKit

/// Represents a memory warning
internal struct MemoryWarning {
/// The date when the memory warning was received.
let date: Date

/// The backtrace at the moment of memory warning.
let backtrace: BacktraceReport?

/// Creates a new instance of `MemoryWarning
/// - Parameters:
/// - date: Date when the memory warning was received.
/// - backtrace: Backtrace at the moment of memory warning.
init(
date: Date,
backtrace: BacktraceReport?
) {
self.date = date
self.backtrace = backtrace
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 UIKit

/// Tracks the memory warnings history and publishes it to the subscribers.
internal final class MemoryWarningMonitor {
let notificationCenter: NotificationCenter
let backtraceReporter: BacktraceReporting?
let reporter: MemoryWarningReporting

init(
backtraceReporter: BacktraceReporting?,
memoryWarningReporter: MemoryWarningReporting,
notificationCenter: NotificationCenter = .default
) {
self.notificationCenter = notificationCenter
self.backtraceReporter = backtraceReporter
self.reporter = memoryWarningReporter
}

/// Starts monitoring memory warnings by subscribing to `UIApplication.didReceiveMemoryWarningNotification`.
func start() {
notificationCenter.addObserver(self, selector: #selector(didReceiveMemoryWarning), name: UIApplication.didReceiveMemoryWarningNotification, object: nil)
}

@objc
func didReceiveMemoryWarning() {
let date: Date = .init()
let backtrace: BacktraceReport?
do {
backtrace = try backtraceReporter?.generateBacktrace()
} catch {
backtrace = nil
}
let warning = MemoryWarning(date: date, backtrace: backtrace)

reporter.report(warning: warning)
}

/// Stops monitoring memory warnings.
func stop() {
notificationCenter.removeObserver(self)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2019-2020 Datadog, Inc.
*/

import Foundation
import DatadogInternal
import UIKit

/// Defines operations used for reporting memory warnings.
internal protocol MemoryWarningReporting: RUMCommandPublisher {
/// Reports the given memory warning.
/// - Parameter warning: The memory warning to report.
func report(warning: MemoryWarning)
}

/// Receives memory warnings and reports them as RUM errors.
internal class MemoryWarningReporter: MemoryWarningReporting {
enum Constants {
/// The standardized `error.message` for RUM errors describing a memory warning.
static let memoryWarningErrorMessage = "Memory Warning"
/// The standardized `error.type` for RUM errors describing a memory warning.
static let memoryWarningErrorType = "MemoryWarning"
/// The standardized `error.stack` when backtrace generation was not available.
static let memoryWarningStackNotAvailableErrorMessage = "Stack trace was not generated because `DatadogCrashReporting` had not been enabled."
}

private(set) weak var subscriber: RUMCommandSubscriber?

/// Reports the given memory warning as a RUM error.
/// - Parameter warning: The memory warning to report.
func report(warning: MemoryWarning) {
let command = RUMAddCurrentViewMemoryWarningCommand(
time: warning.date,
attributes: [:],
message: Constants.memoryWarningErrorMessage,
type: Constants.memoryWarningErrorType,
stack: warning.backtrace?.stack ?? Constants.memoryWarningStackNotAvailableErrorMessage,
threads: warning.backtrace?.threads,
binaryImages: warning.backtrace?.binaryImages,
isStackTraceTruncated: warning.backtrace?.wasTruncated
)
subscriber?.process(command: command)
}

func publish(to subscriber: any RUMCommandSubscriber) {
self.subscriber = subscriber
}
}
Loading

0 comments on commit 3f527c3

Please sign in to comment.