@@ -11,6 +11,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider {
11
11
struct Constants {
12
12
static let frozenFrameThresholdInNs = ( 0.7 ) . toInt64Nanoseconds // 700ms
13
13
static let slowRenderingThresholdFPS = 55.0
14
+ static let minimumTimeSpentForRates = 1.0 // 1s
14
15
/// The pre-warming detection attribute key
15
16
static let activePrewarm = " active_pre_warm "
16
17
}
@@ -116,6 +117,8 @@ internal class RUMViewScope: RUMScope, RUMContextProvider {
116
117
private let viewEndedMetric : ViewEndedMetricController
117
118
/// Tracks "View Hitches" for this view.
118
119
private let viewHitchesMetric : ( ViewHitchesMetric & RenderLoopReader ) ?
120
+ /// Tracks "View Hangs" for this view.
121
+ private var totalAppHangDuration : Double = 0.0
119
122
120
123
init (
121
124
isInitialView: Bool ,
@@ -546,6 +549,18 @@ internal class RUMViewScope: RUMScope, RUMContextProvider {
546
549
let isSlowRendered = refreshRateInfo? . meanValue. map { $0 < Constants . slowRenderingThresholdFPS }
547
550
let networkSettledTime = networkSettledMetric. value ( with: context. applicationStateHistory)
548
551
var interactionToNextViewTime = interactionToNextViewMetric? . value ( for: viewUUID) ?? . failure( . disabled)
552
+ var slowFramesRate : Double ?
553
+ var freezeRate : Double ?
554
+ if let command = command as? RUMStopViewCommand ,
555
+ command. identity == identity,
556
+ timeSpent >= Constants . minimumTimeSpentForRates {
557
+ if let totalHitchesDuration = viewHitchesMetric? . hitchesDataModel. hitchesDuration {
558
+ slowFramesRate = totalHitchesDuration / timeSpent * Double( 1 . toMilliseconds) // milliseconds/second
559
+ }
560
+ if dependencies. hasAppHangsEnabled {
561
+ freezeRate = totalAppHangDuration / timeSpent * 1 . hours // seconds/hour
562
+ }
563
+ }
549
564
// Only overwrite with a custom value if INV was disabled
550
565
if interactionToNextViewTime == . failure( . disabled) ,
551
566
let customInvValue = internalAttributes [ CrossPlatformAttributes . customINVValue] as? ( any BinaryInteger ) ,
@@ -636,7 +651,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider {
636
651
firstInputTime: nil ,
637
652
flutterBuildTime: viewPerformanceMetrics [ . flutterBuildTime] ? . asFlutterBuildTime ( ) ,
638
653
flutterRasterTime: viewPerformanceMetrics [ . flutterRasterTime] ? . asFlutterRasterTime ( ) ,
639
- freezeRate: nil ,
654
+ freezeRate: freezeRate ,
640
655
frozenFrame: . init( count: frozenFramesCount) ,
641
656
frustration: . init( count: frustrationCount) ,
642
657
id: viewUUID. toRUMDataFormat,
@@ -664,7 +679,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider {
664
679
refreshRateMin: refreshRateInfo? . minValue,
665
680
resource: . init( count: resourcesCount. toInt64) ,
666
681
slowFrames: viewHitchesMetric? . hitchesDataModel. hitches. map { . init( duration: $0. duration, start: $0. start) } ,
667
- slowFramesRate: nil ,
682
+ slowFramesRate: slowFramesRate ,
668
683
timeSpent: timeSpent. toInt64Nanoseconds,
669
684
url: viewPath
670
685
)
@@ -703,6 +718,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider {
703
718
704
719
private func sendErrorEvent( on command: RUMErrorCommand , context: DatadogContext , writer: Writer ) {
705
720
errorsCount += 1
721
+ totalAppHangDuration += ( command as? RUMAddCurrentViewAppHangCommand ) ? . hangDuration ?? 0
706
722
707
723
var commandAttributes = command. globalAttributes. merging ( command. attributes) { $1 }
708
724
let errorFingerprint : String ? = commandAttributes. removeValue ( forKey: RUM . Attributes. errorFingerprint) ? . dd. decode ( )
0 commit comments