From eea38c3c8a773d4866cc971e7b86f41ee220dd51 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 6 Dec 2012 17:56:35 +0100 Subject: [PATCH 01/12] Add installationIDs to crash reports, so the amount of affected users of a crash can be determined Uses iOS 6 ASIdentifierManager class or identifierForVendor if the class is not available. Fallback on iOS 5 is to use app path UUID which is generated by iOS when installing the app Conflicts: Classes/BITCrashManager.m Classes/BITHockeyHelper.h Classes/BITHockeyHelper.m --- Classes/BITCrashManager.m | 10 +++++----- Classes/BITHockeyHelper.h | 3 +++ Classes/BITHockeyHelper.m | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 38c614242c..f84f8d402d 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -33,6 +33,7 @@ #import #import "HockeySDK.h" #import "HockeySDKPrivate.h" +#import "BITHockeyHelper.h" #import "BITCrashManagerPrivate.h" #import "BITCrashReportTextFormatter.h" @@ -64,7 +65,6 @@ @synthesize fileManager = _fileManager; - - (id)initWithAppIdentifier:(NSString *)appIdentifier { if ((self = [super init])) { _updateURL = BITHOCKEYSDK_URL; @@ -398,9 +398,7 @@ [self.delegate crashManagerWillShowSubmitCrashReportAlert:self]; } - NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; - if (!appName) - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyAppNamePlaceholder"); + NSString *appName = bit_appName(BITHockeyLocalizedString(@"HockeyAppNamePlaceholder")); NSString *alertDescription = [NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundAnonymousDescription"), appName]; // the crash report is not anynomous any more if username or useremail are not nil @@ -546,6 +544,7 @@ NSString *useremail = @""; NSString *applicationLog = @""; NSString *description = @""; + NSString *installString = bit_appAnonID() ?: @""; NSString *errorString = nil; NSPropertyListFormat format; @@ -569,7 +568,7 @@ description = [NSString stringWithFormat:@"%@", applicationLog]; } - [crashes appendFormat:@"%s%@%@%@%@%@%@%@%@%@", + [crashes appendFormat:@"%s%@%@%@%@%@%@%@%@%@%@", [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String], [self extractAppUUIDs:report], report.applicationInfo.applicationIdentifier, @@ -581,6 +580,7 @@ [crashLogString stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]>" options:NSLiteralSearch range:NSMakeRange(0,crashLogString.length)], username, useremail, + installString, [description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]>" options:NSLiteralSearch range:NSMakeRange(0,description.length)]]; diff --git a/Classes/BITHockeyHelper.h b/Classes/BITHockeyHelper.h index a7b48cc399..5143e7a1b7 100644 --- a/Classes/BITHockeyHelper.h +++ b/Classes/BITHockeyHelper.h @@ -33,6 +33,9 @@ NSString *bit_URLEncodedString(NSString *inputString); NSString *bit_URLDecodedString(NSString *inputString); NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB); +NSString *bit_encodeAppIdentifier(NSString *inputString); +NSString *bit_appName(NSString *placeHolderString); +NSString *bit_appAnonID(void); /* UIImage helpers */ UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize); diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index 7f5c875f29..33982ec68a 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -74,6 +74,44 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { return result; } +NSString *bit_encodeAppIdentifier(NSString *inputString) { + return (inputString ? bit_URLEncodedString(inputString) : bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"])); +} + +NSString *bit_appName(NSString *placeHolderString) { + NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; + if (!appName) + appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: placeHolderString; + + return appName; +} + +NSString *bit_appAnonID(void) { + // try to new iOS6 identifierForAdvertising + Class advertisingClass = NSClassFromString(@"ASIdentifierManager"); + if (advertisingClass) { + id adInstance = [advertisingClass performSelector:NSSelectorFromString(@"sharedManager")]; + + SEL adidSelector = NSSelectorFromString(@"advertisingIdentifier"); + return [[adInstance performSelector:adidSelector] performSelector:NSSelectorFromString(@"UUIDString")]; + } + + // try to new iOS6 identifierForVendor, in case ASIdentifierManager is not linked + SEL vendoridSelector = NSSelectorFromString(@"identifierForVendor"); + if ([[UIDevice currentDevice] respondsToSelector:vendoridSelector]) { + return [[[UIDevice currentDevice] performSelector:vendoridSelector] performSelector:NSSelectorFromString(@"UUIDString")]; + } + + // use app bundle path + NSArray *pathComponents = [[[NSBundle mainBundle] bundlePath] pathComponents]; + + if ([pathComponents count] > 1) { + return [pathComponents objectAtIndex:(pathComponents.count - 2)]; + } + + return nil; +} + #pragma mark UIImage private helpers From 417c82965c5ea1d6bea14bf0cc80b5ba8f229ee0 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 7 Nov 2012 16:25:22 +0100 Subject: [PATCH 02/12] Fix compiler warnings Conflicts: Classes/HockeySDK.h --- Classes/BITCrashManager.h | 2 +- Classes/BITCrashManager.m | 2 ++ Classes/HockeySDK.h | 5 ++--- Classes/HockeySDKPrivate.m | 4 +++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Classes/BITCrashManager.h b/Classes/BITCrashManager.h index 9417bdcffd..b998d3b689 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -36,7 +36,7 @@ typedef enum { BITCrashManagerStatusAlwaysAsk = 1, BITCrashManagerStatusAutoSend = 2 } BITCrashManagerStatus; -static NSString *kBITCrashManagerStatus = @"BITCrashManagerStatus"; +extern NSString *const kBITCrashManagerStatus; @protocol BITCrashManagerDelegate; diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index f84f8d402d..b80fb531a3 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -48,6 +48,8 @@ #define kBITCrashMetaUserEmail @"BITCrashMetaUserEmail" #define kBITCrashMetaApplicationLog @"BITCrashMetaApplicationLog" +NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; + @interface BITCrashManager () diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index c2a78f7fba..22896555b7 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -52,8 +52,7 @@ typedef enum { BITCrashAPIReceivedEmptyResponse, BITCrashAPIErrorWithStatusCode } BITCrashErrorReason; -static NSString *kBITCrashErrorDomain = @"BITCrashReporterErrorDomain"; - +extern NSString *const kBITCrashErrorDomain; // Update App Versions @@ -66,7 +65,7 @@ typedef enum { BITUpdateAPIClientAuthorizationMissingSecret, BITUpdateAPIClientCannotCreateConnection } BITUpdateErrorReason; -static NSString *kBITUpdateErrorDomain = @"BITUpdaterErrorDomain"; +extern NSString *const kBITUpdateErrorDomain; #endif diff --git a/Classes/HockeySDKPrivate.m b/Classes/HockeySDKPrivate.m index e223438ee2..bc534af71b 100644 --- a/Classes/HockeySDKPrivate.m +++ b/Classes/HockeySDKPrivate.m @@ -30,6 +30,8 @@ #import "HockeySDKPrivate.h" #include +NSString *const kBITCrashErrorDomain = @"BITCrashReporterErrorDomain"; +NSString *const kBITUpdateErrorDomain = @"BITUpdaterErrorDomain"; // Load the framework bundle. NSBundle *BITHockeyBundle(void) { @@ -66,4 +68,4 @@ NSString *BITHockeyMD5(NSString *str) { result[12], result[13], result[14], result[15] ]; -} \ No newline at end of file +} From 5ebafab1943995189c601c5ebfcea67317639887 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 9 Nov 2012 13:36:23 +0100 Subject: [PATCH 03/12] Format date and timestamp of crash reports to be always identical no matter what locale is set --- Classes/BITCrashReportTextFormatter.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Classes/BITCrashReportTextFormatter.m b/Classes/BITCrashReportTextFormatter.m index 703ffcbf90..65402de52d 100644 --- a/Classes/BITCrashReportTextFormatter.m +++ b/Classes/BITCrashReportTextFormatter.m @@ -240,8 +240,14 @@ static NSInteger binaryImageSort(id binary1, id binary2, void *context) { NSString *osBuild = @"???"; if (report.systemInfo.operatingSystemBuild != nil) osBuild = report.systemInfo.operatingSystemBuild; - - [text appendFormat: @"Date/Time: %@\n", report.systemInfo.timestamp]; + + NSLocale *enUSPOSIXLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; + NSDateFormatter *rfc3339Formatter = [[[NSDateFormatter alloc] init] autorelease]; + [rfc3339Formatter setLocale:enUSPOSIXLocale]; + [rfc3339Formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"]; + [rfc3339Formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + + [text appendFormat: @"Date/Time: %@\n", [rfc3339Formatter stringFromDate:report.systemInfo.timestamp]]; [text appendFormat: @"OS Version: %@ %@ (%@)\n", osName, report.systemInfo.operatingSystemVersion, osBuild]; [text appendFormat: @"Report Version: 104\n"]; } From 9ffae558df84da36251a8f3bd41bfc68602bf6b7 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 6 Dec 2012 18:05:38 +0100 Subject: [PATCH 04/12] Fix a problem showing the update UI animated if there TTNavigator class is present even though not being used Conflicts: Classes/BITHockeyBaseManager.m --- Classes/BITUpdateManager.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index ee046e0f36..9741ca0d24 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -483,7 +483,10 @@ if (NSClassFromString(@"TTNavigator")) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" - parentViewController = [[NSClassFromString(@"TTNavigator") performSelector:(NSSelectorFromString(@"navigator"))] visibleViewController]; + UIViewController *ttParentViewController = nil; + ttParentViewController = [[NSClassFromString(@"TTNavigator") performSelector:(NSSelectorFromString(@"navigator"))] visibleViewController]; + if (ttParentViewController) + parentViewController = ttParentViewController; #pragma clang diagnostic pop } From 109976422226e2a8aa7140a396f2dde70e4689b7 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 26 Nov 2012 19:45:21 +0100 Subject: [PATCH 05/12] Call delegate also if a crash was detected but could not be read If PLCrashReporter wrote a crash report, that could not be read, no delegate was fired. That could make the app stay in the start up maintenance screen, if it handles crashes on startup. Though there was no report this ever happened, there is the theoretical chance this could. --- Classes/BITCrashManager.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index b80fb531a3..bc81f07501 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -367,8 +367,17 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; if ([_crashFiles count] > 0) { BITHockeyLog(@"INFO: %i pending crash reports found.", [_crashFiles count]); return YES; - } else + } else { + if (_didCrashInLastSession) { + if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashManagerWillCancelSendingCrashReport:)]) { + [self.delegate crashManagerWillCancelSendingCrashReport:self]; + } + + _didCrashInLastSession = NO; + } + return NO; + } } From 2701bd3df5be1dffd9156cffb975984a9d11395b Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 27 Nov 2012 02:37:37 +0100 Subject: [PATCH 06/12] Add anonID to crash reports CrashReporter Key is actually an anonymous ID for each device/installation where the crash occurred --- Classes/BITCrashManager.m | 4 ++-- Classes/BITCrashReportTextFormatter.h | 2 +- Classes/BITCrashReportTextFormatter.m | 10 +++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index bc81f07501..625ff357c1 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -541,7 +541,8 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; if ([report respondsToSelector:@selector(reportInfo)]) { crashUUID = report.reportInfo.reportGUID ?: @""; } - NSString *crashLogString = [BITCrashReportTextFormatter stringValueForCrashReport:report]; + NSString *installString = bit_appAnonID() ?: @""; + NSString *crashLogString = [BITCrashReportTextFormatter stringValueForCrashReport:report crashReporterKey:installString]; if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedSame) { _crashIdenticalCurrentVersion = YES; @@ -555,7 +556,6 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; NSString *useremail = @""; NSString *applicationLog = @""; NSString *description = @""; - NSString *installString = bit_appAnonID() ?: @""; NSString *errorString = nil; NSPropertyListFormat format; diff --git a/Classes/BITCrashReportTextFormatter.h b/Classes/BITCrashReportTextFormatter.h index ebaf38bb47..4ff2743cd8 100644 --- a/Classes/BITCrashReportTextFormatter.h +++ b/Classes/BITCrashReportTextFormatter.h @@ -47,7 +47,7 @@ @interface BITCrashReportTextFormatter : NSObject { } -+ (NSString *)stringValueForCrashReport:(PLCrashReport *)report; ++ (NSString *)stringValueForCrashReport:(PLCrashReport *)report crashReporterKey:(NSString *)crashReporterKey; + (NSArray *)arrayOfAppUUIDsForCrashReport:(PLCrashReport *)report; @end diff --git a/Classes/BITCrashReportTextFormatter.m b/Classes/BITCrashReportTextFormatter.m index 65402de52d..db6754e2d4 100644 --- a/Classes/BITCrashReportTextFormatter.m +++ b/Classes/BITCrashReportTextFormatter.m @@ -76,7 +76,7 @@ static NSInteger binaryImageSort(id binary1, id binary2, void *context) { * * @return Returns the formatted result on success, or nil if an error occurs. */ -+ (NSString *)stringValueForCrashReport:(PLCrashReport *)report { ++ (NSString *)stringValueForCrashReport:(PLCrashReport *)report crashReporterKey:(NSString *)crashReporterKey { NSMutableString* text = [NSMutableString string]; boolean_t lp64 = true; // quiesce GCC uninitialized value warning @@ -178,13 +178,17 @@ static NSInteger binaryImageSort(id binary1, id binary2, void *context) { if (report.hasReportInfo && report.reportInfo.reportGUID != nil) reportGUID = report.reportInfo.reportGUID; } - + + NSString *reporterKey = @"[TODO]"; + if (crashReporterKey) + reporterKey = crashReporterKey; + NSString *hardwareModel = @"???"; if (report.hasMachineInfo && report.machineInfo.modelName != nil) hardwareModel = report.machineInfo.modelName; [text appendFormat: @"Incident Identifier: %@\n", reportGUID]; - [text appendFormat: @"CrashReporter Key: [TODO]\n"]; + [text appendFormat: @"CrashReporter Key: %@\n", reporterKey]; [text appendFormat: @"Hardware Model: %@\n", hardwareModel]; } From dca243527d555ceda501375c90f70a144734fd31 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 27 Nov 2012 20:43:25 +0100 Subject: [PATCH 07/12] Move calculation of time interval between startup and crash further up in the code This allows the delegate, e.g. applicationLog, to know about the interval and e.g. include it in the log file Conflicts: Classes/BITCrashManager.m --- Classes/BITCrashManager.m | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 625ff357c1..b048aab70e 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -277,6 +277,15 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; if (crashData == nil) { BITHockeyLog(@"ERROR: Could not load crash report: %@", error); } else { + // get the startup timestamp from the crash report, and the file timestamp to calculate the timeinterval when the crash happened after startup + PLCrashReport *report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease]; + + if ([report.applicationInfo respondsToSelector:@selector(applicationStartupTimestamp)]) { + if (report.systemInfo.timestamp && report.applicationInfo.applicationStartupTimestamp) { + _timeintervalCrashInLastSessionOccured = [report.systemInfo.timestamp timeIntervalSinceDate:report.applicationInfo.applicationStartupTimestamp]; + } + } + [crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES]; // write the meta file @@ -309,15 +318,6 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; } else { BITHockeyLog(@"ERROR: Writing crash meta data failed. %@", error); } - - // get the startup timestamp from the crash report, and the file timestamp to calculate the timeinterval when the crash happened after startup - PLCrashReport *report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease]; - - if ([report.applicationInfo respondsToSelector:@selector(applicationStartupTimestamp)]) { - if (report.systemInfo.timestamp && report.applicationInfo.applicationStartupTimestamp) { - _timeintervalCrashInLastSessionOccured = [report.systemInfo.timestamp timeIntervalSinceDate:report.applicationInfo.applicationStartupTimestamp]; - } - } } } From 7cc267797d13d3bcfe01623108386a570677b525 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 28 Nov 2012 23:21:20 +0100 Subject: [PATCH 08/12] Clean this up! Thanks @tewha :) --- Classes/BITHockeyManager.m | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index 9baf72c0b8..422d7cc879 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -98,14 +98,10 @@ _startManagerIsInvoked = NO; // check if we are really not in an app store environment - if ([[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) { - _appStoreEnvironment = NO; - } else { +#if !TARGET_IPHONE_SIMULATOR + if (![[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) { _appStoreEnvironment = YES; } - -#if TARGET_IPHONE_SIMULATOR - _appStoreEnvironment = NO; #endif [self performSelector:@selector(validateStartManagerIsInvoked) withObject:nil afterDelay:0.0f]; From 610a441e8548d0d3b5a35962d4923cda9e6514f6 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 28 Nov 2012 23:26:08 +0100 Subject: [PATCH 09/12] Oh documentation *doh* --- Classes/BITHockeyManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index 422d7cc879..ce44393b31 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -97,8 +97,8 @@ _appStoreEnvironment = NO; _startManagerIsInvoked = NO; - // check if we are really not in an app store environment #if !TARGET_IPHONE_SIMULATOR + // check if we are really in an app store environment if (![[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) { _appStoreEnvironment = YES; } From c2250f3b8093b8b9cf83a5f84ec1b0edef5734ff Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 6 Dec 2012 18:12:27 +0100 Subject: [PATCH 10/12] Make sure crash reports incident identifier and key don't have special [] chars and some value The previously shows [] as part of [TODO], since PLCrashReporter didn't fill them out. Having the incident identifier showing a [ or ] char made it impossible to drag it into the Organizer to get it symbolicated in there --- Classes/BITCrashReportTextFormatter.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/BITCrashReportTextFormatter.m b/Classes/BITCrashReportTextFormatter.m index db6754e2d4..e1abddeeb0 100644 --- a/Classes/BITCrashReportTextFormatter.m +++ b/Classes/BITCrashReportTextFormatter.m @@ -173,14 +173,14 @@ static NSInteger binaryImageSort(id binary1, id binary2, void *context) { } { - NSString *reportGUID = @"[TODO]"; + NSString *reportGUID = @"TODO"; if ([report respondsToSelector:@selector(reportInfo)]) { if (report.hasReportInfo && report.reportInfo.reportGUID != nil) reportGUID = report.reportInfo.reportGUID; } - NSString *reporterKey = @"[TODO]"; - if (crashReporterKey) + NSString *reporterKey = @"TODO"; + if (crashReporterKey && [crashReporterKey length] > 0) reporterKey = crashReporterKey; NSString *hardwareModel = @"???"; From 752edca28c1fa2370e06818f1db0822beb9785a4 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 17 Nov 2012 17:01:57 +0100 Subject: [PATCH 11/12] Update documentation on how to add Lumberjack log data --- docs/HowTo-Add-Application-Log-template.md | 99 +++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/docs/HowTo-Add-Application-Log-template.md b/docs/HowTo-Add-Application-Log-template.md index e091ccd6e7..dc426be0d2 100644 --- a/docs/HowTo-Add-Application-Log-template.md +++ b/docs/HowTo-Add-Application-Log-template.md @@ -58,7 +58,7 @@ This example code is based on CocoaLumberjack logging into log files: - (NSString *) getLogFilesContentWithMaxSize:(NSInteger)maxSize { NSMutableString *description = [NSMutableString string]; - NSArray *sortedLogFileInfos = [[[Logging fileLogger] logFileManager] sortedLogFileInfos]; + NSArray *sortedLogFileInfos = [[_fileLogger logFileManager] sortedLogFileInfos]; NSUInteger count = [sortedLogFileInfos count]; // we start from the last one @@ -96,3 +96,100 @@ This example code is based on CocoaLumberjack logging into log files: @end + +## Advanced HowTo + +If you want to restrict the log files to contain only the data from the last application run (from app start until it crashed, ignoring all suspend and resume actions), you follow these steps. (Thanks to Michael Tyson for this hint!) + +4. Adjust CocoaLumberjack to initialize a new log file per application start + + [_fileLogger performSelector:@selector(currentLogFileHandle)]; // init log file prior to rolling + [_fileLogger rollLogFile]; + [_fileLogger performSelector:@selector(currentLogFileHandle)]; // re-init log file to apply roll + +5. And when loading the prior (crashed) application run log file, stop the iteration over the log files before the most current one (which is the new session, the one after the crash): + + // we start from the last (oldest) one, and stop just before the newest (which is the log for the session after the crash) + for (int index = count - 1; index > 0; index--) { + + +## Example + + @interface BITAppDelegate () {} + @property (nonatomic) DDFileLogger *fileLogger; + @end + + + @implementation BITAppDelegate + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [self.window makeKeyAndVisible]; + + // initialize before HockeySDK, so the delegate can access the file logger! + _fileLogger = [[DDFileLogger alloc] init]; + _fileLogger.maximumFileSize = (1024 * 64); // 64 KByte + _fileLogger.logFileManager.maximumNumberOfLogFiles = 1; + [_fileLogger performSelector:@selector(currentLogFileHandle)]; // init log file prior to rolling + [_fileLogger rollLogFile]; + [_fileLogger performSelector:@selector(currentLogFileHandle)]; // re-init log file to apply roll + [DDLog addLogger:_fileLogger]; + + [[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"<>" + delegate:nil]; + + [[BITHockeyManager sharedHockeyManager] startManager]; + + // add Xcode console logger if not running in the App Store + if (![[BITHockeyManager sharedHockeyManager] isAppStoreEnvironment]) { + PSDDFormatter *psLogger = [[[PSDDFormatter alloc] init] autorelease]; + [[DDTTYLogger sharedInstance] setLogFormatter:psLogger]; + + [DDLog addLogger:[DDTTYLogger sharedInstance]]; + + [DDLog addLogger:[DDNSLoggerLogger sharedInstance]]; + } + + return YES; + } + + // get the log content with a maximum byte size + - (NSString *) getLogFilesContentWithMaxSize:(NSInteger)maxSize { + NSMutableString *description = [NSMutableString string]; + + NSArray *sortedLogFileInfos = [[_fileLogger logFileManager] sortedLogFileInfos]; + NSUInteger count = [sortedLogFileInfos count]; + + // we start from the last (oldest) one, and stop just before the newest (which is the log for the session after the crash) + for (int index = count - 1; index > 0; index--) { + DDLogFileInfo *logFileInfo = [sortedLogFileInfos objectAtIndex:index]; + + NSData *logData = [[NSFileManager defaultManager] contentsAtPath:[logFileInfo filePath]]; + if ([logData length] > 0) { + NSString *result = [[NSString alloc] initWithBytes:[logData bytes] + length:[logData length] + encoding: NSUTF8StringEncoding]; + + [description appendString:result]; + [result release]; + } + } + + if ([description length] > maxSize) { + description = (NSMutableString *)[description substringWithRange:NSMakeRange([description length]-maxSize-1, maxSize)]; + } + + return description; + } + + #pragma mark - BITCrashManagerDelegate + + - (NSString *)applicationLogForCrashManager:(BITCrashManager *)crashManager { + NSString *description = [self getLogFilesContentWithMaxSize:5000]; // 5000 bytes should be enough! + if ([description length] == 0) { + return nil; + } else { + return description; + } + } + + @end \ No newline at end of file From cf32aa4c08594cf099cd4e2c953c95a19b58a461 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 6 Dec 2012 18:21:06 +0100 Subject: [PATCH 12/12] Bump version to 2.5.5 build 10 Also update podspec and changelog --- HockeySDK.podspec | 4 ++-- Support/buildnumber.xcconfig | 6 +++--- docs/Changelog-template.md | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/HockeySDK.podspec b/HockeySDK.podspec index 5c9ea3df8e..b9600f43c7 100644 --- a/HockeySDK.podspec +++ b/HockeySDK.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |s| s.name = 'HockeySDK' - s.version = '2.5.3' + s.version = '2.5.5' s.license = 'MIT' s.platform = :ios, '4.0' s.summary = 'Distribute beta apps and collect crash reports with HockeyApp.' s.homepage = 'http://hockeyapp.net/' s.author = { 'Andreas Linde' => 'mail@andreaslinde.de', 'Thomas Dohmke' => "thomas@dohmke.de" } - s.source = { :git => 'https://github.com/bitstadium/HockeySDK-iOS.git', :tag => '2.5.3' } + s.source = { :git => 'https://github.com/bitstadium/HockeySDK-iOS.git', :tag => '2.5.5' } s.description = 'HockeyApp is a server to distribute beta apps and collect crash reports. ' \ 'It improves the testing process dramatically and can be used for both beta ' \ diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index a660c7ec30..47857f8eb2 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,3 +1,3 @@ -BUILD_NUMBER = 9 -VERSION_STRING = 2.5.4 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"2.5.4\"" +BUILD_NUMBER = 10 +VERSION_STRING = 2.5.5 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"2.5.5\"" diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index 708004c0a0..54ab56743b 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,3 +1,21 @@ +### Version 2.5.5 + +- General: + + - [BUGFIX] Fix some new compiler warnings + +- Crash Reporting: + + - [NEW] Add anonymous device ID to crash reports + - [BUGFIX] Move calculation of time interval between startup and crash further up in the code, so delegates can use this information e.g. to add it into a log file + - [BUGFIX] Call delegate also if a crash was detected but could not be read (if handling crashes on startup is implemented) + - [BUGFIX] Format timestamp in crash report to be always UTC in en_US locale + - [BUGFIX] Make sure crash reports incident identifier and key don't have special [] chars and some value + +- Updating: + + - [BUGFIX] Fix a problem showing the update UI animated if there TTNavigator class is present even though not being used + ### Version 2.5.4 - General: