Skip to content

Commit

Permalink
Merge 7fa081e into 289c0b8
Browse files Browse the repository at this point in the history
  • Loading branch information
armcknight authored Sep 6, 2023
2 parents 289c0b8 + 7fa081e commit dc541cc
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 31 deletions.
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

- Record changes to network connectivity in breadcrumbs (#3232)

## 8.11.0

### Features
Expand Down
51 changes: 33 additions & 18 deletions Sources/Sentry/SentryBreadcrumbTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#import "SentryDependencyContainer.h"
#import "SentryHub.h"
#import "SentryLog.h"
#import "SentryReachability.h"
#import "SentryScope.h"
#import "SentrySwift.h"
#import "SentrySwizzle.h"
Expand All @@ -15,7 +16,7 @@
# import <UIKit/UIKit.h>
#elif TARGET_OS_OSX || TARGET_OS_MACCATALYST
# import <Cocoa/Cocoa.h>
#endif
#endif // !TARGET_OS_WATCH

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -31,16 +32,14 @@

@implementation SentryBreadcrumbTracker

- (instancetype)init
{
return [super init];
}

- (void)startWithDelegate:(id<SentryBreadcrumbDelegate>)delegate
{
_delegate = delegate;
[self addEnabledCrumb];
[self trackApplicationUIKitNotifications];
#if !TARGET_OS_WATCH
[self trackNetworkConnectivityChanges];
#endif // !TARGET_OS_WATCH
}

- (void)startSwizzle
Expand All @@ -56,7 +55,7 @@ - (void)stop
#if SENTRY_HAS_UIKIT
[SentryDependencyContainer.sharedInstance.swizzleWrapper
removeSwizzleSendActionForKey:SentryBreadcrumbTrackerSwizzleSendAction];
#endif
#endif // SENTRY_HAS_UIKIT
_delegate = nil;
}

Expand All @@ -70,10 +69,10 @@ - (void)trackApplicationUIKitNotifications
// Will resign Active notification is the nearest one to
// UIApplicationDidEnterBackgroundNotification
NSNotificationName backgroundNotificationName = NSApplicationWillResignActiveNotification;
#else
#else // TARGET_OS_WATCH
SENTRY_LOG_DEBUG(@"NO UIKit, OSX and Catalyst -> [SentryBreadcrumbTracker "
@"trackApplicationUIKitNotifications] does nothing.");
#endif
#endif // !TARGET_OS_WATCH

// not available for macOS
#if SENTRY_HAS_UIKIT
Expand All @@ -90,9 +89,9 @@ - (void)trackApplicationUIKitNotifications
crumb.message = @"Low memory";
[self.delegate addBreadcrumb:crumb];
}];
#endif
#endif // SENTRY_HAS_UIKIT

#if SENTRY_HAS_UIKIT || TARGET_OS_OSX || TARGET_OS_MACCATALYST
#if !TARGET_OS_WATCH
[NSNotificationCenter.defaultCenter addObserverForName:backgroundNotificationName
object:nil
queue:nil
Expand All @@ -114,8 +113,24 @@ - (void)trackApplicationUIKitNotifications
withDataKey:@"state"
withDataValue:@"foreground"];
}];
#endif
#endif // !TARGET_OS_WATCH
}

#if !TARGET_OS_WATCH
- (void)trackNetworkConnectivityChanges
{
[SentryDependencyContainer.sharedInstance.reachability
monitorURL:[NSURL URLWithString:@"https://sentry.io"]
usingCallback:^(BOOL connected, NSString *_Nonnull typeDescription) {
SentryBreadcrumb *crumb =
[[SentryBreadcrumb alloc] initWithLevel:kSentryLevelInfo
category:@"device.connectivity"];
crumb.type = @"connectivity";
crumb.data = [NSDictionary dictionaryWithObject:typeDescription forKey:@"connectivity"];
[self.delegate addBreadcrumb:crumb];
}];
}
#endif // !TARGET_OS_WATCH

- (void)addBreadcrumbWithType:(NSString *)type
withCategory:(NSString *)category
Expand Down Expand Up @@ -155,7 +170,7 @@ + (BOOL)avoidSender:(id)sender forTarget:(id)target action:(NSString *)action
}
return NO;
}
#endif
#endif // SENTRY_HAS_UIKIT

- (void)swizzleSendAction
{
Expand Down Expand Up @@ -183,9 +198,9 @@ - (void)swizzleSendAction
}
forKey:SentryBreadcrumbTrackerSwizzleSendAction];

#else
#else // !SENTRY_HAS_UIKIT
SENTRY_LOG_DEBUG(@"NO UIKit -> [SentryBreadcrumbTracker swizzleSendAction] does nothing.");
#endif
#endif // SENTRY_HAS_UIKIT
}

- (void)swizzleViewDidAppear
Expand Down Expand Up @@ -223,9 +238,9 @@ - (void)swizzleViewDidAppear
}),
mode, swizzleViewDidAppearKey);
# pragma clang diagnostic pop
#else
#else // !SENTRY_HAS_UIKIT
SENTRY_LOG_DEBUG(@"NO UIKit -> [SentryBreadcrumbTracker swizzleViewDidAppear] does nothing.");
#endif
#endif // SENTRY_HAS_UIKIT
}

#if SENTRY_HAS_UIKIT
Expand Down Expand Up @@ -287,7 +302,7 @@ + (NSDictionary *)fetchInfoAboutViewController:(UIViewController *)controller

return info;
}
#endif
#endif // SENTRY_HAS_UIKIT

@end

Expand Down
18 changes: 18 additions & 0 deletions Sources/Sentry/SentryDependencyContainer.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
# import "SentryUIDeviceWrapper.h"
#endif // TARGET_OS_IOS

#if !TARGET_OS_WATCH
# import "SentryReachability.h"
#endif // !TARGET_OS_WATCH

@implementation SentryDependencyContainer

static SentryDependencyContainer *instance;
Expand Down Expand Up @@ -368,4 +372,18 @@ - (SentryMXManager *)metricKitManager

#endif // SENTRY_HAS_METRIC_KIT

#if !TARGET_OS_WATCH
- (SentryReachability *)reachability
{
if (_reachability == nil) {
@synchronized(sentryDependencyContainerLock) {
if (_reachability == nil) {
_reachability = [[SentryReachability alloc] init];
}
}
}
return _reachability;
}
#endif // !TARGET_OS_WATCH

@end
6 changes: 3 additions & 3 deletions Sources/Sentry/SentryReachability.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
static SCNetworkReachabilityFlags sentry_current_reachability_state
= kSCNetworkReachabilityFlagsUninitialized;

static NSString *const SentryConnectivityCellular = @"cellular";
static NSString *const SentryConnectivityWiFi = @"wifi";
static NSString *const SentryConnectivityNone = @"none";
NSString *const SentryConnectivityCellular = @"cellular";
NSString *const SentryConnectivityWiFi = @"wifi";
NSString *const SentryConnectivityNone = @"none";

/**
* Check whether the connectivity change should be noted or ignored.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
@class SentryUIDeviceWrapper;
#endif // TARGET_OS_IOS

#if !TARGET_OS_WATCH
@class SentryReachability;
#endif // !TARGET_OS_WATCH

NS_ASSUME_NONNULL_BEGIN

@interface SentryDependencyContainer : NSObject
Expand Down Expand Up @@ -76,6 +80,10 @@ SENTRY_NO_INIT
@property (nonatomic, strong) SentryUIDeviceWrapper *uiDeviceWrapper;
#endif // TARGET_OS_IOS

#if !TARGET_OS_WATCH
@property (nonatomic, strong) SentryReachability *reachability;
#endif // !TARGET_OS_WATCH

- (SentryANRTracker *)getANRTracker:(NSTimeInterval)timeout;

#if SENTRY_HAS_METRIC_KIT
Expand Down
5 changes: 5 additions & 0 deletions Sources/Sentry/include/SentryReachability.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
// THE SOFTWARE.
//

#import "SentryDefines.h"
#import <Foundation/Foundation.h>

#if !TARGET_OS_WATCH
Expand All @@ -38,6 +39,10 @@ NSString *SentryConnectivityFlagRepresentation(SCNetworkReachabilityFlags flags)

BOOL SentryConnectivityShouldReportChange(SCNetworkReachabilityFlags flags);

SENTRY_EXTERN NSString *const SentryConnectivityCellular;
SENTRY_EXTERN NSString *const SentryConnectivityWiFi;
SENTRY_EXTERN NSString *const SentryConnectivityNone;

/**
* Function signature to connectivity monitoring callback of @c SentryReachability
* @param connected @c YES if the monitored URL is reachable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,31 @@ class SentryBreadcrumbTrackerTests: XCTestCase {
XCTAssertEqual(0, dict?.count)
}

func testNetworkConnectivityChangeBreadcrumbs() throws {
let testReachability = TestSentryReachability()
SentryDependencyContainer.sharedInstance().reachability = testReachability
let sut = SentryBreadcrumbTracker()
sut.start(with: delegate)
let states = [SentryConnectivityCellular,
SentryConnectivityWiFi,
SentryConnectivityNone,
SentryConnectivityWiFi,
SentryConnectivityCellular,
SentryConnectivityWiFi
]
states.forEach {
testReachability.setReachabilityState(state: $0)
}
sut.stop()
XCTAssertEqual(delegate.addCrumbInvocations.count, states.count + 1) // 1 breadcrumb for the tracker start
try states.enumerated().forEach {
let crumb = delegate.addCrumbInvocations.invocations[$0.offset + 1]
XCTAssertEqual(crumb.type, "connectivity")
XCTAssertEqual(crumb.category, "device.connectivity")
XCTAssertEqual(try XCTUnwrap(crumb.data?["connectivity"] as? String), $0.element)
}
}

func testSwizzlingStarted_ViewControllerAppears_AddsUILifeCycleBreadcrumb() {
let scope = Scope()
let client = TestClient(options: Options())
Expand Down
18 changes: 9 additions & 9 deletions Tests/SentryTests/Networking/SentryReachabilityTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ - (void)tearDown

- (void)testConnectivityRepresentations
{
XCTAssertEqualObjects(@"none", SentryConnectivityFlagRepresentation(0));
XCTAssertEqualObjects(
@"none", SentryConnectivityFlagRepresentation(kSCNetworkReachabilityFlagsIsDirect));
XCTAssertEqualObjects(SentryConnectivityNone, SentryConnectivityFlagRepresentation(0));
XCTAssertEqualObjects(SentryConnectivityNone,
SentryConnectivityFlagRepresentation(kSCNetworkReachabilityFlagsIsDirect));
# if SENTRY_HAS_UIKIT
// kSCNetworkReachabilityFlagsIsWWAN does not exist on macOS
XCTAssertEqualObjects(
@"none", SentryConnectivityFlagRepresentation(kSCNetworkReachabilityFlagsIsWWAN));
XCTAssertEqualObjects(@"cellular",
XCTAssertEqualObjects(SentryConnectivityNone,
SentryConnectivityFlagRepresentation(kSCNetworkReachabilityFlagsIsWWAN));
XCTAssertEqualObjects(SentryConnectivityCellular,
SentryConnectivityFlagRepresentation(
kSCNetworkReachabilityFlagsIsWWAN | kSCNetworkReachabilityFlagsReachable));
# endif // SENTRY_HAS_UIKIT
XCTAssertEqualObjects(
@"wifi", SentryConnectivityFlagRepresentation(kSCNetworkReachabilityFlagsReachable));
XCTAssertEqualObjects(@"wifi",
XCTAssertEqualObjects(SentryConnectivityWiFi,
SentryConnectivityFlagRepresentation(kSCNetworkReachabilityFlagsReachable));
XCTAssertEqualObjects(SentryConnectivityWiFi,
SentryConnectivityFlagRepresentation(
kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsIsDirect));
}
Expand Down
6 changes: 5 additions & 1 deletion Tests/SentryTests/Networking/TestSentryReachability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ class TestSentryReachability: SentryReachability {
self.block = block
}

func setReachabilityState(state: String) {
block?(state != SentryConnectivityNone, state)
}

func triggerNetworkReachable() {
block?(true, "wifi")
block?(true, SentryConnectivityWiFi)
}

var stopMonitoringInvocations = Invocations<Void>()
Expand Down

0 comments on commit dc541cc

Please sign in to comment.