Skip to content

Commit

Permalink
Feature: Replaced Crashlytics with Sentry
Browse files Browse the repository at this point in the history
Crash logging is now handled by the Sentry service.

Signed-off-by: Christopher Snowhill <[email protected]>
  • Loading branch information
kode54 committed Feb 26, 2025
1 parent 30d9eee commit 4a0cca2
Show file tree
Hide file tree
Showing 20 changed files with 224 additions and 296 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ xcuserdata

# User-specific xcconfig files
Xcode-config/DEVELOPMENT_TEAM.xcconfig
Xcode-config/SENTRY_SETTINGS.xcconfig

# Plist derived from template at build time
/Info.plist
Expand Down
64 changes: 48 additions & 16 deletions Application/AppController.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@

#import "PreferencesController.h"

@import Firebase;
#import "FeedbackController.h"

@import Sentry;

void *kAppControllerContext = &kAppControllerContext;

Expand Down Expand Up @@ -166,19 +168,14 @@ - (BOOL)application:(NSApplication *)sender delegateHandlesKey:(NSString *)key {
return [key isEqualToString:@"currentEntry"];
}

static BOOL consentLastEnabled = NO;

- (void)awakeFromNib {
#if DEBUG
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @(NO) }];
#else
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions": @(YES) }];
#endif
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"crashlyticsConsented": @(NO),
@"crashlyticsAskedConsent": @(NO) }];

[FIRApp configure];

[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.crashlyticsConsented" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kAppControllerContext];
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"sentryConsented": @(NO),
@"sentryAskedConsent": @(NO) }];

[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.sentryConsented" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:kAppControllerContext];

[[totalTimeField cell] setBackgroundStyle:NSBackgroundStyleRaised];

[self.infoButton setToolTip:NSLocalizedString(@"InfoButtonTooltip", @"")];
Expand Down Expand Up @@ -323,10 +320,45 @@ - (void)observeValueForKeyPath:(NSString *)keyPath
return;
}

if([keyPath isEqualToString:@"values.crashlyticsConsented"]) {
BOOL enabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"crashlyticsConsented"];
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:enabled];
[FIRAnalytics setAnalyticsCollectionEnabled:enabled];
if([keyPath isEqualToString:@"values.sentryConsented"]) {
BOOL enabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"sentryConsented"];
if(enabled != consentLastEnabled) {
if(enabled) {
[SentrySDK startWithConfigureOptions:^(SentryOptions *options) {
options.dsn = @"https://[email protected]/3";
options.debug = YES; // Enabled debug when first installing is always helpful

// Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
// We recommend adjusting this value in production.
options.tracesSampleRate = @1.0;

// Adds IP for users.
// For more information, visit: https://docs.sentry.io/platforms/apple/data-management/data-collected/
options.sendDefaultPii = YES;

// And now to set up user feedback prompting
options.onCrashedLastRun = ^void(SentryEvent * _Nonnull event) {
// capture user feedback
FeedbackController *fbcon = [[FeedbackController alloc] init];
[fbcon performSelectorOnMainThread:@selector(showWindow:) withObject:nil waitUntilDone:YES];
if([fbcon waitForCompletion]) {
SentryUserFeedback *userFeedback = [[SentryUserFeedback alloc] initWithEventId:[event eventId]];

userFeedback.comments = [fbcon comments];
userFeedback.email = [fbcon email];
userFeedback.name = [fbcon name];

[SentrySDK captureUserFeedback:userFeedback];
}
};
}];
} else {
if([SentrySDK isEnabled]) {
[SentrySDK close];
}
}
consentLastEnabled = enabled;
}
} else if([keyPath isEqualToString:@"playlistController.currentEntry"]) {
PlaylistEntry *entry = playlistController.currentEntry;
NSString *appTitle = NSLocalizedString(@"CogTitle", @"");
Expand Down
24 changes: 12 additions & 12 deletions Application/PlaybackController.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

#import "Logging.h"

@import Firebase;
//@import Sentry;

extern BOOL kAppControllerShuttingDown;

Expand Down Expand Up @@ -284,11 +284,11 @@ - (void)playEntry:(PlaylistEntry *)pe startPaused:(BOOL)paused andSeekTo:(id)off
if(!pe.url) {
pe.error = YES;
pe.errorMessage = NSLocalizedStringFromTableInBundle(@"ErrorMessageBadFile", nil, [NSBundle bundleForClass:[self class]], @"");
[[FIRCrashlytics crashlytics] log:@"Attempting to play bad file."];
//[[FIRCrashlytics crashlytics] log:@"Attempting to play bad file."];
return;
}

[[FIRCrashlytics crashlytics] logWithFormat:@"Playing track: %@", pe.url];
//[[FIRCrashlytics crashlytics] logWithFormat:@"Playing track: %@", pe.url];

DLog(@"PLAYLIST CONTROLLER: %@", [playlistController class]);
[playlistController setCurrentEntry:pe];
Expand Down Expand Up @@ -767,15 +767,15 @@ - (void)audioPlayer:(AudioPlayer *)player willEndStream:(id)userInfo {
}

if(pe && pe.url) {
[[FIRCrashlytics crashlytics] logWithFormat:@"Beginning decoding track: %@", pe.url];
//[[FIRCrashlytics crashlytics] logWithFormat:@"Beginning decoding track: %@", pe.url];
[player setNextStream:pe.url withUserInfo:pe withRGInfo:makeRGInfo(pe)];
} else if(pe) {
[[FIRCrashlytics crashlytics] log:@"Invalid playlist entry reached."];
//[[FIRCrashlytics crashlytics] log:@"Invalid playlist entry reached."];
[player setNextStream:nil];
pe.error = YES;
pe.errorMessage = NSLocalizedStringFromTableInBundle(@"ErrorMessageBadFile", nil, [NSBundle bundleForClass:[self class]], @"");
} else {
[[FIRCrashlytics crashlytics] log:@"End of playlist reached."];
//[[FIRCrashlytics crashlytics] log:@"End of playlist reached."];
[player setNextStream:nil];
}
}
Expand All @@ -786,7 +786,7 @@ - (void)audioPlayer:(AudioPlayer *)player didBeginStream:(id)userInfo {
// Delay the action until this function has returned to the audio thread
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
if(pe) {
[[FIRCrashlytics crashlytics] logWithFormat:@"Updating UI with track: %@", pe.url];
//[[FIRCrashlytics crashlytics] logWithFormat:@"Updating UI with track: %@", pe.url];
}

[self->playlistController setCurrentEntry:pe];
Expand Down Expand Up @@ -817,19 +817,19 @@ - (void)audioPlayer:(AudioPlayer *)player didChangeStatus:(NSNumber *)s userInfo
}

if(status == CogStatusStopped) {
[[FIRCrashlytics crashlytics] log:@"Stopped."];
//[[FIRCrashlytics crashlytics] log:@"Stopped."];

[self setPosition:0];
[self setSeekable:NO]; // the player stopped, disable the slider

[[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidStopNotificiation object:nil];
} else // paused
{
[[FIRCrashlytics crashlytics] log:@"Paused."];
//[[FIRCrashlytics crashlytics] log:@"Paused."];
[[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidPauseNotificiation object:nil];
}
} else if(status == CogStatusPlaying) {
[[FIRCrashlytics crashlytics] log:@"Started playing."];
//[[FIRCrashlytics crashlytics] log:@"Started playing."];

if(!positionTimer) {
positionTimer = [NSTimer timerWithTimeInterval:0.2 target:self selector:@selector(updatePosition:) userInfo:nil repeats:YES];
Expand Down Expand Up @@ -865,7 +865,7 @@ - (void)audioPlayer:(AudioPlayer *)player didChangeStatus:(NSNumber *)s userInfo

- (void)audioPlayer:(AudioPlayer *)player didStopNaturally:(id)userInfo {
if([[NSUserDefaults standardUserDefaults] boolForKey:@"quitOnNaturalStop"]) {
[[FIRCrashlytics crashlytics] log:@"Terminating due to natural stop."];
//[[FIRCrashlytics crashlytics] log:@"Terminating due to natural stop."];
[NSApp terminate:nil];
}
}
Expand All @@ -880,7 +880,7 @@ - (void)audioPlayer:(AudioPlayer *)player sustainHDCD:(id)userInfo {
- (void)audioPlayer:(AudioPlayer *)player restartPlaybackAtCurrentPosition:(id)userInfo {
PlaylistEntry *pe = [playlistController currentEntry];
BOOL paused = playbackStatus == CogStatusPaused;
[[FIRCrashlytics crashlytics] logWithFormat:@"Restarting playback of track: %@", pe.url];
//[[FIRCrashlytics crashlytics] logWithFormat:@"Restarting playback of track: %@", pe.url];
[player performSelectorOnMainThread:@selector(playBG:withUserInfo:withRGInfo:startPaused:andSeekTo:) withObjects:pe.url, pe, makeRGInfo(pe), @(paused), @(pe.seekable ? pe.currentPosition : 0.0), nil];
}

Expand Down
2 changes: 0 additions & 2 deletions Audio/PluginController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,6 @@ - (void)printPluginInfo {
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\
<plist version=\"1.0\">\n\
<dict>\n\
\t<key>FirebaseCrashlyticsCollectionEnabled</key>\n\
\t<false/>\n\
\t<key>SUEnableInstallerLauncherService</key>\n\
\t<true/>\n\
\t<key>CFBundleDevelopmentRegion</key>\n\
Expand Down
Loading

0 comments on commit 4a0cca2

Please sign in to comment.