Created
March 24, 2014 03:04
-
-
Save 0x8badf00d/9733463 to your computer and use it in GitHub Desktop.
Generate live crash report using PLCrashReporter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @interface CrashManager:NSObject | |
| /** | |
| * Generates live crash report, without triggering an actual crash condition. | |
| * | |
| * Works only if the vendor SDK is built using PLCrashReporter v 1.1 atleast. | |
| * We are using runtime magic to call generateLiveReportAndReturnError: method on PLCrashReporter instance without changing vendor sdk (QuincyKit, HockeyApp, others) | |
| */ | |
| - (void)generateLiveReport; | |
| @end | |
| @implementation CrashManager | |
| - (void)generateLiveReport | |
| { | |
| Class plCrashReporter = [NSClassFromString(@"PLCrashReporter") class]; | |
| SEL sharedReporterSel = @selector(sharedReporter); | |
| SEL generateLiveReportSel = @selector(generateLiveReportAndReturnError:); | |
| if([plCrashReporter respondsToSelector:sharedReporterSel]) | |
| { | |
| id plIn = objc_msgSend(plCrashReporter, @selector(sharedReporter)); | |
| if([plIn respondsToSelector:generateLiveReportSel]) | |
| { | |
| NSError *err = nil; | |
| NSData *data = objc_msgSend(plIn, @selector(generateLiveReportAndReturnError:),&err); | |
| saveLiveReportForData(data); | |
| //printLiveReportForData(data); | |
| } | |
| } | |
| } | |
| @end | |
| /* Helper method to write data to file .plcrash that we can use to symbolicate on local mac */ | |
| static NSString *WATCHDOG_REPORT_DIR = @"WatchdogLogs"; | |
| static NSUInteger MAX_FILES = 10; | |
| static void saveLiveReportForData (NSData *data) | |
| { | |
| NSFileManager *fileManager = [NSFileManager defaultManager]; | |
| /*Setup directory attributes 755*/ | |
| NSDictionary *attributes = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:0755] forKey:NSFilePosixPermissions]; | |
| NSError *error = nil; | |
| NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); | |
| NSString *documentsDirectory = [paths objectAtIndex:0]; | |
| if(![fileManager createDirectoryAtPath: documentsDirectory withIntermediateDirectories:YES attributes:attributes error:&error]) | |
| { | |
| NSLog(@"Could not create documents directory: %@", error); | |
| return; | |
| } | |
| /* Create Watchdog logs directory that we will use to save the watchdog reports */ | |
| NSString *watchdogLogsDirectory = [documentsDirectory stringByAppendingPathComponent:WATCHDOG_REPORT_DIR]; | |
| if (![fileManager fileExistsAtPath:watchdogLogsDirectory]) | |
| { | |
| [fileManager createDirectoryAtPath:watchdogLogsDirectory withIntermediateDirectories:NO attributes:attributes error:&error]; | |
| } | |
| NSArray *watchdogDirectoryContent = [fileManager contentsOfDirectoryAtURL:[NSURL fileURLWithPath:watchdogLogsDirectory isDirectory:YES] | |
| includingPropertiesForKeys:@[NSURLContentModificationDateKey] | |
| options:NSDirectoryEnumerationSkipsHiddenFiles | |
| error:nil]; | |
| NSArray *sortedDirectoryContent = [watchdogDirectoryContent sortedArrayUsingComparator:^(NSURL *file1, NSURL *file2){ | |
| // compare | |
| NSDate *file1Date; | |
| [file1 getResourceValue:&file1Date forKey:NSURLContentModificationDateKey error:nil]; | |
| NSDate *file2Date; | |
| [file2 getResourceValue:&file2Date forKey:NSURLContentModificationDateKey error:nil]; | |
| return [file1Date compare:file2Date]; | |
| }]; | |
| /* Remove the first untouched file from the directory contents if the cached reports count reaches max_count*/ | |
| if([sortedDirectoryContent count] >= MAX_FILES) | |
| { | |
| [fileManager removeItemAtPath:[sortedDirectoryContent objectAtIndex:0] error:nil]; | |
| } | |
| /* Get current date/timestamp that we are going to append to file name as suffix before extension*/ | |
| NSDate *today = [NSDate date]; | |
| NSDateFormatter *dateFormatter = [NSDateFormatter new]; | |
| [dateFormatter setDateFormat:@"dd-MM-yyyy-hh-mm-ss"]; | |
| NSString *timeString = [dateFormatter stringFromDate:today]; | |
| NSString *fileName = [NSString stringWithFormat:@"watchdog_report_%@.plcrash",timeString]; | |
| NSString *outputPath = [watchdogLogsDirectory stringByAppendingPathComponent:fileName]; | |
| if(![data writeToFile:outputPath atomically:YES]) | |
| { | |
| NSLog(@"Failed to write crash report"); | |
| } | |
| NSLog(@"Saved crash report to: %@", outputPath); | |
| } | |
| /* Prints human readable crash report. Use this for debugging purpose only*/ | |
| static void printLiveReportForData (NSData *data) | |
| { | |
| Class plCrashReport = [NSClassFromString(@"PLCrashReport") class]; | |
| Class plCrashReportTextFormatter = [NSClassFromString(@"PLCrashReportTextFormatter") class]; | |
| SEL initWithDataSelector = @selector(initWithData:error:); | |
| SEL stringValueForCrashReportSelector = @selector(stringValueForCrashReport:withTextFormat:); | |
| if([plCrashReport respondsToSelector:initWithDataSelector]) | |
| { | |
| id classReport = objc_msgSend([plCrashReport alloc], initWithDataSelector,data,nil); | |
| if([plCrashReportTextFormatter respondsToSelector:stringValueForCrashReportSelector]) | |
| { | |
| NSString * crashReportText = objc_msgSend(plCrashReportTextFormatter, stringValueForCrashReportSelector,classReport,0); | |
| NSLog(@"%@",crashReportText); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment