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: track network connectivity changes with breadcrumbs #3232

Merged
merged 14 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.12.0

### Fixes
Expand Down
2 changes: 2 additions & 0 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,7 @@
84AF45A529A7FFA500FBB177 /* SentryProfiledTracerConcurrency.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryProfiledTracerConcurrency.mm; sourceTree = "<group>"; };
84B7FA3B29B2866200AD93B1 /* SentryTestUtils-ObjC-BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryTestUtils-ObjC-BridgingHeader.h"; sourceTree = "<group>"; };
84B7FA4729B2995A00AD93B1 /* DeploymentTargets.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DeploymentTargets.xcconfig; sourceTree = "<group>"; };
84C404B02ABA9F9C007F69C5 /* SentryReachability+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryReachability+Private.h"; sourceTree = "<group>"; };
84C47B2B2A09239100DAEB8A /* .codecov.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .codecov.yml; sourceTree = "<group>"; };
84E4F5692914F020004C7358 /* Brewfile */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = text; path = Brewfile; sourceTree = "<group>"; tabWidth = 2; };
84F993C32A62A74000EC0190 /* SentryCurrentDateProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryCurrentDateProvider.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1888,6 +1889,7 @@
84AC61D129F7541E009EEF61 /* SentryDispatchSourceWrapper.m */,
0AAE202028ED9BCC00D0CD80 /* SentryReachability.h */,
0AAE201D28ED9B9400D0CD80 /* SentryReachability.m */,
84C404B02ABA9F9C007F69C5 /* SentryReachability+Private.h */,
);
name = Networking;
sourceTree = "<group>";
Expand Down
55 changes: 40 additions & 15 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 @@ -24,23 +25,31 @@

@interface
SentryBreadcrumbTracker ()
#if !TARGET_OS_WATCH
<SentryReachabilityObserver>
#endif // !TARGET_OS_WATCH

@property (nonatomic, weak) id<SentryBreadcrumbDelegate> delegate;

@end

@implementation SentryBreadcrumbTracker

- (instancetype)init
#if !TARGET_OS_WATCH
- (void)dealloc
{
return [super init];
[SentryDependencyContainer.sharedInstance.reachability removeObserver:self];
}
#endif // !TARGET_OS_WATCH

- (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 +65,7 @@ - (void)stop
#if SENTRY_HAS_UIKIT
[SentryDependencyContainer.sharedInstance.swizzleWrapper
removeSwizzleSendActionForKey:SentryBreadcrumbTrackerSwizzleSendAction];
#endif
#endif // SENTRY_HAS_UIKIT
_delegate = nil;
}

Expand All @@ -70,10 +79,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 +99,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,9 +123,25 @@ - (void)trackApplicationUIKitNotifications
withDataKey:@"state"
withDataValue:@"foreground"];
}];
#endif
#endif // !TARGET_OS_WATCH
}

#if !TARGET_OS_WATCH
- (void)trackNetworkConnectivityChanges
{
[SentryDependencyContainer.sharedInstance.reachability
addObserver:self
withCallback:^(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
withLevel:(SentryLevel)level
Expand Down Expand Up @@ -155,7 +180,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 +208,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 +248,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 +312,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
47 changes: 22 additions & 25 deletions Sources/Sentry/SentryHttpTransport.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@

@interface
SentryHttpTransport ()
#if !TARGET_OS_WATCH
<SentryReachabilityObserver>
#endif // !TARGET_OS_WATCH

@property (nonatomic, strong) SentryFileManager *fileManager;
@property (nonatomic, strong) id<SentryRequestManager> requestManager;
Expand All @@ -37,9 +40,6 @@
@property (nonatomic, strong) SentryEnvelopeRateLimit *envelopeRateLimit;
@property (nonatomic, strong) SentryDispatchQueueWrapper *dispatchQueue;
@property (nonatomic, strong) dispatch_group_t dispatchGroup;
#if !TARGET_OS_WATCH
@property (nonatomic, strong) SentryReachability *reachability;
#endif // !TARGET_OS_WATCH

#if TEST || TESTCI
@property (nullable, nonatomic, strong) void (^startFlushCallback)(void);
Expand Down Expand Up @@ -73,9 +73,6 @@ - (id)initWithOptions:(SentryOptions *)options
rateLimits:(id<SentryRateLimits>)rateLimits
envelopeRateLimit:(SentryEnvelopeRateLimit *)envelopeRateLimit
dispatchQueueWrapper:(SentryDispatchQueueWrapper *)dispatchQueueWrapper
#if !TARGET_OS_WATCH
reachability:(SentryReachability *)reachability
#endif // !TARGET_OS_WATCH
{
if (self = [super init]) {
self.options = options;
Expand All @@ -95,33 +92,33 @@ - (id)initWithOptions:(SentryOptions *)options
[self sendAllCachedEnvelopes];

#if !TARGET_OS_WATCH
self.reachability = reachability;
__weak SentryHttpTransport *weakSelf = self;
[self.reachability monitorURL:[NSURL URLWithString:@"https://sentry.io"]
usingCallback:^(BOOL connected, NSString *_Nonnull typeDescription) {
if (weakSelf == nil) {
SENTRY_LOG_DEBUG(@"WeakSelf is nil. Not doing anything.");
return;
}

if (connected) {
SENTRY_LOG_DEBUG(@"Internet connection is back.");
[weakSelf sendAllCachedEnvelopes];
} else {
SENTRY_LOG_DEBUG(@"Lost internet connection.");
}
}];
#endif
[SentryDependencyContainer.sharedInstance.reachability
addObserver:self
withCallback:^(BOOL connected, NSString *_Nonnull typeDescription) {
if (weakSelf == nil) {
SENTRY_LOG_DEBUG(@"WeakSelf is nil. Not doing anything.");
return;
}

if (connected) {
SENTRY_LOG_DEBUG(@"Internet connection is back.");
[weakSelf sendAllCachedEnvelopes];
} else {
SENTRY_LOG_DEBUG(@"Lost internet connection.");
}
}];
#endif // !TARGET_OS_WATCH
}
return self;
}

#if !TARGET_OS_WATCH
- (void)dealloc
{
#if !TARGET_OS_WATCH
[self.reachability stopMonitoring];
#endif
[SentryDependencyContainer.sharedInstance.reachability removeObserver:self];
}
#endif // !TARGET_OS_WATCH

- (void)sendEnvelope:(SentryEnvelope *)envelope
{
Expand Down
15 changes: 15 additions & 0 deletions Sources/Sentry/SentryReachability+Private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#import "SentryReachability.h"

#if !TARGET_OS_WATCH

void SentryConnectivityCallback(__unused SCNetworkReachabilityRef target,
SCNetworkReachabilityFlags flags, __unused void *info);

@interface
SentryReachability ()

@property SCNetworkReachabilityRef sentry_reachability_ref;

@end

#endif // !TARGET_OS_WATCH
Loading