Skip to content

Instantly share code, notes, and snippets.

@0x8badf00d
Created March 24, 2014 03:04
Show Gist options
  • Select an option

  • Save 0x8badf00d/9733463 to your computer and use it in GitHub Desktop.

Select an option

Save 0x8badf00d/9733463 to your computer and use it in GitHub Desktop.
Generate live crash report using PLCrashReporter
@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