Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add slow and frozen frames to spans #3450

Merged
merged 11 commits into from
Dec 5, 2023
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

## Features

- Add slow and frozen frames to spans (#3450)

## 8.17.1

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion SentryTestUtils/TestDisplayLinkWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public class TestDisplayLinkWrapper: SentryDisplayLinkWrapper {
call()
}

public func givenFrames(_ slow: Int, _ frozen: Int, _ normal: Int) {
public func renderFrames(_ slow: Int, _ frozen: Int, _ normal: Int) {
self.call()

for _ in 0..<slow {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryBuildAppStartSpans.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
origin:SentryTraceOriginAutoAppStart
sampled:tracer.sampled];

return [[SentrySpan alloc] initWithTracer:tracer context:context];
return [[SentrySpan alloc] initWithTracer:tracer context:context framesTracker:nil];
}

NSArray<SentrySpan *> *
Expand Down
10 changes: 10 additions & 0 deletions Sources/Sentry/SentryFramesTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,14 @@ - (void)dealloc

@end

BOOL
sentryShouldAddSlowFrozenFramesData(
NSInteger totalFrames, NSInteger slowFrames, NSInteger frozenFrames)
{
BOOL allBiggerThanOrEqualToZero = totalFrames >= 0 && slowFrames >= 0 && frozenFrames >= 0;
BOOL oneBiggerThanZero = totalFrames > 0 || slowFrames > 0 || frozenFrames > 0;

return allBiggerThanOrEqualToZero && oneBiggerThanZero;
}

#endif // SENTRY_HAS_UIKIT
56 changes: 55 additions & 1 deletion Sources/Sentry/SentrySpan.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#import "SentryTraceHeader.h"
#import "SentryTracer.h"

#if SENTRY_HAS_UIKIT
# import <SentryFramesTracker.h>
# import <SentryScreenFrames.h>
#endif // SENTRY_HAS_UIKIT

NS_ASSUME_NONNULL_BEGIN

@interface
Expand All @@ -30,9 +35,18 @@ @implementation SentrySpan {
NSMutableDictionary<NSString *, id> *_tags;
NSObject *_stateLock;
BOOL _isFinished;
#if SENTRY_HAS_UIKIT
NSUInteger initTotalFrames;
NSUInteger initSlowFrames;
NSUInteger initFrozenFrames;
SentryFramesTracker *_framesTracker;
#endif // SENTRY_HAS_UIKIT
}

- (instancetype)initWithContext:(SentrySpanContext *)context
#if SENTRY_HAS_UIKIT
framesTracker:(nullable SentryFramesTracker *)framesTracker;
#endif // SENTRY_HAS_UIKIT
{
if (self = [super init]) {
self.startTimestamp = [SentryDependencyContainer.sharedInstance.dateProvider date];
Expand All @@ -43,6 +57,17 @@ - (instancetype)initWithContext:(SentrySpanContext *)context

if ([NSThread isMainThread]) {
_data[SPAN_DATA_THREAD_NAME] = @"main";

#if SENTRY_HAS_UIKIT
// Only track frames if running on main thread.
_framesTracker = framesTracker;
if (_framesTracker.isRunning) {
SentryScreenFrames *currentFrames = _framesTracker.currentFrames;
initTotalFrames = currentFrames.total;
initSlowFrames = currentFrames.slow;
initFrozenFrames = currentFrames.frozen;
}
#endif // SENTRY_HAS_UIKIT
} else {
_data[SPAN_DATA_THREAD_NAME] = [SentryDependencyContainer.sharedInstance.threadInspector
getThreadName:currentThread];
Expand All @@ -64,9 +89,17 @@ - (instancetype)initWithContext:(SentrySpanContext *)context
return self;
}

- (instancetype)initWithTracer:(SentryTracer *)tracer context:(SentrySpanContext *)context
- (instancetype)initWithTracer:(SentryTracer *)tracer
context:(SentrySpanContext *)context
#if SENTRY_HAS_UIKIT
framesTracker:(nullable SentryFramesTracker *)framesTracker
{
if (self = [self initWithContext:context framesTracker:framesTracker]) {
#else
{
if (self = [self initWithContext:context]) {
#endif // SENTRY_HAS_UIKIT

_tracer = tracer;
}
return self;
Expand Down Expand Up @@ -171,6 +204,27 @@ - (void)finishWithStatus:(SentrySpanStatus)status
SENTRY_LOG_DEBUG(@"Setting span timestamp: %@ at system time %llu", self.timestamp,
(unsigned long long)SentryDependencyContainer.sharedInstance.dateProvider.systemTime);
}

#if SENTRY_HAS_UIKIT
if (_framesTracker.isRunning) {

SentryScreenFrames *currentFrames = _framesTracker.currentFrames;
NSInteger totalFrames = currentFrames.total - initTotalFrames;
NSInteger slowFrames = currentFrames.slow - initSlowFrames;
NSInteger frozenFrames = currentFrames.frozen - initFrozenFrames;

if (sentryShouldAddSlowFrozenFramesData(totalFrames, slowFrames, frozenFrames)) {
[self setDataValue:@(totalFrames) forKey:@"frames.total"];
[self setDataValue:@(slowFrames) forKey:@"frames.slow"];
[self setDataValue:@(frozenFrames) forKey:@"frames.frozen"];

SENTRY_LOG_DEBUG(@"Frames for span \"%@\" Total:%ld Slow:%ld Frozen:%ld",
self.operation, (long)totalFrames, (long)slowFrames, (long)frozenFrames);
}
}

#endif // SENTRY_HAS_UIKIT

if (self.tracer == nil) {
SENTRY_LOG_DEBUG(
@"No tracer associated with span with id %@", self.spanId.sentrySpanIdString);
Expand Down
19 changes: 13 additions & 6 deletions Sources/Sentry/SentryTracer.m
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,11 @@ - (instancetype)initWithTransactionContext:(SentryTransactionContext *)transacti
hub:(nullable SentryHub *)hub
configuration:(SentryTracerConfiguration *)configuration;
{
if (!(self = [super initWithContext:transactionContext])) {
if (!(self = [super initWithContext:transactionContext
#if SENTRY_HAS_UIKIT
framesTracker:SentryDependencyContainer.sharedInstance.framesTracker
#endif // SENTRY_HAS_UIKIT
])) {
return nil;
}

Expand Down Expand Up @@ -351,7 +355,13 @@ - (void)cancelDeadlineTimer
spanDescription:description
sampled:self.sampled];

SentrySpan *child = [[SentrySpan alloc] initWithTracer:self context:context];
SentrySpan *child =
[[SentrySpan alloc] initWithTracer:self
context:context
#if SENTRY_HAS_UIKIT
framesTracker:SentryDependencyContainer.sharedInstance.framesTracker
#endif // SENTRY_HAS_UIKIT
];
child.startTimestamp = [SentryDependencyContainer.sharedInstance.dateProvider date];
SENTRY_LOG_DEBUG(@"Started child span %@ under %@", child.spanId.sentrySpanIdString,
parentId.sentrySpanIdString);
Expand Down Expand Up @@ -741,10 +751,7 @@ - (void)addMeasurements:(SentryTransaction *)transaction
NSInteger slowFrames = currentFrames.slow - initSlowFrames;
NSInteger frozenFrames = currentFrames.frozen - initFrozenFrames;

BOOL allBiggerThanZero = totalFrames >= 0 && slowFrames >= 0 && frozenFrames >= 0;
BOOL oneBiggerThanZero = totalFrames > 0 || slowFrames > 0 || frozenFrames > 0;

if (allBiggerThanZero && oneBiggerThanZero) {
if (sentryShouldAddSlowFrozenFramesData(totalFrames, slowFrames, frozenFrames)) {
[self setMeasurement:@"frames_total" value:@(totalFrames)];
[self setMeasurement:@"frames_slow" value:@(slowFrames)];
[self setMeasurement:@"frames_frozen" value:@(frozenFrames)];
Expand Down
3 changes: 3 additions & 0 deletions Sources/Sentry/include/SentryFramesTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ NS_ASSUME_NONNULL_BEGIN

@end

BOOL sentryShouldAddSlowFrozenFramesData(
NSInteger totalFrames, NSInteger slowFrames, NSInteger frozenFrames);

NS_ASSUME_NONNULL_END

#endif // SENTRY_HAS_UIKIT
17 changes: 15 additions & 2 deletions Sources/Sentry/include/SentrySpan.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ NS_ASSUME_NONNULL_BEGIN
@class SentryTracer, SentryId, SentrySpanId, SentryFrame, SentrySpanContext;
@protocol SentrySerializable;

#if SENTRY_HAS_UIKIT
@class SentryFramesTracker;
#endif // SENTRY_HAS_UIKIT

@interface SentrySpan : NSObject <SentrySpan, SentrySerializable>
SENTRY_NO_INIT

Expand Down Expand Up @@ -85,13 +89,22 @@ SENTRY_NO_INIT
* @param transaction The @c SentryTracer managing the transaction this span is associated with.
* @param context This span context information.
*/
- (instancetype)initWithTracer:(SentryTracer *)transaction context:(SentrySpanContext *)context;
- (instancetype)initWithTracer:(SentryTracer *)transaction
context:(SentrySpanContext *)context
#if SENTRY_HAS_UIKIT
framesTracker:(nullable SentryFramesTracker *)framesTracker;
#endif // SENTRY_HAS_UIKIT
;

/**
* Init a @c SentrySpan with given context.
* @param context This span context information.
*/
- (instancetype)initWithContext:(SentrySpanContext *)context;
- (instancetype)initWithContext:(SentrySpanContext *)context
#if SENTRY_HAS_UIKIT
framesTracker:(nullable SentryFramesTracker *)framesTracker;
#endif // SENTRY_HAS_UIKIT
;

- (void)setExtraValue:(nullable id)value forKey:(NSString *)key DEPRECATED_ATTRIBUTE;
@end
Expand Down
2 changes: 1 addition & 1 deletion Tests/SentryTests/PrivateSentrySDKOnlyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ class PrivateSentrySDKOnlyTests: XCTestCase {
let slow = 2
let frozen = 1
let normal = 100
displayLink.givenFrames(slow, frozen, normal)
displayLink.renderFrames(slow, frozen, normal)

let currentFrames = PrivateSentrySDKOnly.currentScreenFrames
XCTAssertEqual(UInt(slow + frozen + normal), currentFrames.total)
Expand Down
2 changes: 1 addition & 1 deletion Tests/SentryTests/SentryClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ class SentryClientTest: XCTestCase {
func testCaptureTransactionWithoutScreen() {
SentryDependencyContainer.sharedInstance().application = TestSentryUIApplication()

let event = Transaction(trace: SentryTracer(context: SpanContext(operation: "test")), children: [])
let event = Transaction(trace: SentryTracer(context: SpanContext(operation: "test"), framesTracker: nil), children: [])
fixture.getSut().capture(event: event, scope: fixture.scope)

try? assertLastSentEventWithAttachment { event in
Expand Down
Loading
Loading