Merge branch 'hotfix/2.5.5'

This commit is contained in:
Andreas Linde 2012-12-06 18:48:01 +01:00
commit 90b2bfe61d
14 changed files with 219 additions and 42 deletions

View File

@ -36,7 +36,7 @@ typedef enum {
BITCrashManagerStatusAlwaysAsk = 1, BITCrashManagerStatusAlwaysAsk = 1,
BITCrashManagerStatusAutoSend = 2 BITCrashManagerStatusAutoSend = 2
} BITCrashManagerStatus; } BITCrashManagerStatus;
static NSString *kBITCrashManagerStatus = @"BITCrashManagerStatus"; extern NSString *const kBITCrashManagerStatus;
@protocol BITCrashManagerDelegate; @protocol BITCrashManagerDelegate;

View File

@ -33,6 +33,7 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "HockeySDK.h" #import "HockeySDK.h"
#import "HockeySDKPrivate.h" #import "HockeySDKPrivate.h"
#import "BITHockeyHelper.h"
#import "BITCrashManagerPrivate.h" #import "BITCrashManagerPrivate.h"
#import "BITCrashReportTextFormatter.h" #import "BITCrashReportTextFormatter.h"
@ -47,6 +48,8 @@
#define kBITCrashMetaUserEmail @"BITCrashMetaUserEmail" #define kBITCrashMetaUserEmail @"BITCrashMetaUserEmail"
#define kBITCrashMetaApplicationLog @"BITCrashMetaApplicationLog" #define kBITCrashMetaApplicationLog @"BITCrashMetaApplicationLog"
NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
@interface BITCrashManager () @interface BITCrashManager ()
@ -64,7 +67,6 @@
@synthesize fileManager = _fileManager; @synthesize fileManager = _fileManager;
- (id)initWithAppIdentifier:(NSString *)appIdentifier { - (id)initWithAppIdentifier:(NSString *)appIdentifier {
if ((self = [super init])) { if ((self = [super init])) {
_updateURL = BITHOCKEYSDK_URL; _updateURL = BITHOCKEYSDK_URL;
@ -275,6 +277,15 @@
if (crashData == nil) { if (crashData == nil) {
BITHockeyLog(@"ERROR: Could not load crash report: %@", error); BITHockeyLog(@"ERROR: Could not load crash report: %@", error);
} else { } 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]; [crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES];
// write the meta file // write the meta file
@ -307,15 +318,6 @@
} else { } else {
BITHockeyLog(@"ERROR: Writing crash meta data failed. %@", error); 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];
}
}
} }
} }
@ -365,8 +367,17 @@
if ([_crashFiles count] > 0) { if ([_crashFiles count] > 0) {
BITHockeyLog(@"INFO: %i pending crash reports found.", [_crashFiles count]); BITHockeyLog(@"INFO: %i pending crash reports found.", [_crashFiles count]);
return YES; return YES;
} else } else {
if (_didCrashInLastSession) {
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashManagerWillCancelSendingCrashReport:)]) {
[self.delegate crashManagerWillCancelSendingCrashReport:self];
}
_didCrashInLastSession = NO;
}
return NO; return NO;
}
} }
@ -398,9 +409,7 @@
[self.delegate crashManagerWillShowSubmitCrashReportAlert:self]; [self.delegate crashManagerWillShowSubmitCrashReportAlert:self];
} }
NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; NSString *appName = bit_appName(BITHockeyLocalizedString(@"HockeyAppNamePlaceholder"));
if (!appName)
appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyAppNamePlaceholder");
NSString *alertDescription = [NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundAnonymousDescription"), appName]; NSString *alertDescription = [NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundAnonymousDescription"), appName];
// the crash report is not anynomous any more if username or useremail are not nil // the crash report is not anynomous any more if username or useremail are not nil
@ -532,7 +541,8 @@
if ([report respondsToSelector:@selector(reportInfo)]) { if ([report respondsToSelector:@selector(reportInfo)]) {
crashUUID = report.reportInfo.reportGUID ?: @""; 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) { if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedSame) {
_crashIdenticalCurrentVersion = YES; _crashIdenticalCurrentVersion = YES;
@ -569,7 +579,7 @@
description = [NSString stringWithFormat:@"%@", applicationLog]; description = [NSString stringWithFormat:@"%@", applicationLog];
} }
[crashes appendFormat:@"<crash><applicationname>%s</applicationname><uuids>%@</uuids><bundleidentifier>%@</bundleidentifier><systemversion>%@</systemversion><platform>%@</platform><senderversion>%@</senderversion><version>%@</version><uuid>%@</uuid><log><![CDATA[%@]]></log><userid>%@</userid><contact>%@</contact><description><![CDATA[%@]]></description></crash>", [crashes appendFormat:@"<crash><applicationname>%s</applicationname><uuids>%@</uuids><bundleidentifier>%@</bundleidentifier><systemversion>%@</systemversion><platform>%@</platform><senderversion>%@</senderversion><version>%@</version><uuid>%@</uuid><log><![CDATA[%@]]></log><username>%@</username><contact>%@</contact><installstring>%@</installstring><description><![CDATA[%@]]></description></crash>",
[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String], [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String],
[self extractAppUUIDs:report], [self extractAppUUIDs:report],
report.applicationInfo.applicationIdentifier, report.applicationInfo.applicationIdentifier,
@ -581,6 +591,7 @@
[crashLogString stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,crashLogString.length)], [crashLogString stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,crashLogString.length)],
username, username,
useremail, useremail,
installString,
[description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,description.length)]]; [description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,description.length)]];

View File

@ -47,7 +47,7 @@
@interface BITCrashReportTextFormatter : NSObject { @interface BITCrashReportTextFormatter : NSObject {
} }
+ (NSString *)stringValueForCrashReport:(PLCrashReport *)report; + (NSString *)stringValueForCrashReport:(PLCrashReport *)report crashReporterKey:(NSString *)crashReporterKey;
+ (NSArray *)arrayOfAppUUIDsForCrashReport:(PLCrashReport *)report; + (NSArray *)arrayOfAppUUIDsForCrashReport:(PLCrashReport *)report;
@end @end

View File

@ -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. * @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]; NSMutableString* text = [NSMutableString string];
boolean_t lp64 = true; // quiesce GCC uninitialized value warning boolean_t lp64 = true; // quiesce GCC uninitialized value warning
@ -173,18 +173,22 @@ static NSInteger binaryImageSort(id binary1, id binary2, void *context) {
} }
{ {
NSString *reportGUID = @"[TODO]"; NSString *reportGUID = @"TODO";
if ([report respondsToSelector:@selector(reportInfo)]) { if ([report respondsToSelector:@selector(reportInfo)]) {
if (report.hasReportInfo && report.reportInfo.reportGUID != nil) if (report.hasReportInfo && report.reportInfo.reportGUID != nil)
reportGUID = report.reportInfo.reportGUID; reportGUID = report.reportInfo.reportGUID;
} }
NSString *reporterKey = @"TODO";
if (crashReporterKey && [crashReporterKey length] > 0)
reporterKey = crashReporterKey;
NSString *hardwareModel = @"???"; NSString *hardwareModel = @"???";
if (report.hasMachineInfo && report.machineInfo.modelName != nil) if (report.hasMachineInfo && report.machineInfo.modelName != nil)
hardwareModel = report.machineInfo.modelName; hardwareModel = report.machineInfo.modelName;
[text appendFormat: @"Incident Identifier: %@\n", reportGUID]; [text appendFormat: @"Incident Identifier: %@\n", reportGUID];
[text appendFormat: @"CrashReporter Key: [TODO]\n"]; [text appendFormat: @"CrashReporter Key: %@\n", reporterKey];
[text appendFormat: @"Hardware Model: %@\n", hardwareModel]; [text appendFormat: @"Hardware Model: %@\n", hardwareModel];
} }
@ -241,7 +245,13 @@ static NSInteger binaryImageSort(id binary1, id binary2, void *context) {
if (report.systemInfo.operatingSystemBuild != nil) if (report.systemInfo.operatingSystemBuild != nil)
osBuild = report.systemInfo.operatingSystemBuild; 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: @"OS Version: %@ %@ (%@)\n", osName, report.systemInfo.operatingSystemVersion, osBuild];
[text appendFormat: @"Report Version: 104\n"]; [text appendFormat: @"Report Version: 104\n"];
} }

View File

@ -33,6 +33,9 @@
NSString *bit_URLEncodedString(NSString *inputString); NSString *bit_URLEncodedString(NSString *inputString);
NSString *bit_URLDecodedString(NSString *inputString); NSString *bit_URLDecodedString(NSString *inputString);
NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB); NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB);
NSString *bit_encodeAppIdentifier(NSString *inputString);
NSString *bit_appName(NSString *placeHolderString);
NSString *bit_appAnonID(void);
/* UIImage helpers */ /* UIImage helpers */
UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize); UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize);

View File

@ -74,6 +74,44 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) {
return result; 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 #pragma mark UIImage private helpers

View File

@ -97,15 +97,11 @@
_appStoreEnvironment = NO; _appStoreEnvironment = NO;
_startManagerIsInvoked = NO; _startManagerIsInvoked = NO;
// check if we are really not in an app store environment #if !TARGET_IPHONE_SIMULATOR
if ([[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) { // check if we are really in an app store environment
_appStoreEnvironment = NO; if (![[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) {
} else {
_appStoreEnvironment = YES; _appStoreEnvironment = YES;
} }
#if TARGET_IPHONE_SIMULATOR
_appStoreEnvironment = NO;
#endif #endif
[self performSelector:@selector(validateStartManagerIsInvoked) withObject:nil afterDelay:0.0f]; [self performSelector:@selector(validateStartManagerIsInvoked) withObject:nil afterDelay:0.0f];

View File

@ -483,7 +483,10 @@
if (NSClassFromString(@"TTNavigator")) { if (NSClassFromString(@"TTNavigator")) {
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks" #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 #pragma clang diagnostic pop
} }

View File

@ -52,8 +52,7 @@ typedef enum {
BITCrashAPIReceivedEmptyResponse, BITCrashAPIReceivedEmptyResponse,
BITCrashAPIErrorWithStatusCode BITCrashAPIErrorWithStatusCode
} BITCrashErrorReason; } BITCrashErrorReason;
static NSString *kBITCrashErrorDomain = @"BITCrashReporterErrorDomain"; extern NSString *const kBITCrashErrorDomain;
// Update App Versions // Update App Versions
@ -66,7 +65,7 @@ typedef enum {
BITUpdateAPIClientAuthorizationMissingSecret, BITUpdateAPIClientAuthorizationMissingSecret,
BITUpdateAPIClientCannotCreateConnection BITUpdateAPIClientCannotCreateConnection
} BITUpdateErrorReason; } BITUpdateErrorReason;
static NSString *kBITUpdateErrorDomain = @"BITUpdaterErrorDomain"; extern NSString *const kBITUpdateErrorDomain;
#endif #endif

View File

@ -30,6 +30,8 @@
#import "HockeySDKPrivate.h" #import "HockeySDKPrivate.h"
#include <CommonCrypto/CommonDigest.h> #include <CommonCrypto/CommonDigest.h>
NSString *const kBITCrashErrorDomain = @"BITCrashReporterErrorDomain";
NSString *const kBITUpdateErrorDomain = @"BITUpdaterErrorDomain";
// Load the framework bundle. // Load the framework bundle.
NSBundle *BITHockeyBundle(void) { NSBundle *BITHockeyBundle(void) {

View File

@ -1,12 +1,12 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'HockeySDK' s.name = 'HockeySDK'
s.version = '2.5.3' s.version = '2.5.5'
s.license = 'MIT' s.license = 'MIT'
s.platform = :ios, '4.0' s.platform = :ios, '4.0'
s.summary = 'Distribute beta apps and collect crash reports with HockeyApp.' s.summary = 'Distribute beta apps and collect crash reports with HockeyApp.'
s.homepage = 'http://hockeyapp.net/' s.homepage = 'http://hockeyapp.net/'
s.author = { 'Andreas Linde' => 'mail@andreaslinde.de', 'Thomas Dohmke' => "thomas@dohmke.de" } 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. ' \ 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 ' \ 'It improves the testing process dramatically and can be used for both beta ' \

View File

@ -1,3 +1,3 @@
BUILD_NUMBER = 9 BUILD_NUMBER = 10
VERSION_STRING = 2.5.4 VERSION_STRING = 2.5.5
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"2.5.4\"" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"2.5.5\""

View File

@ -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 ### Version 2.5.4
- General: - General:

View File

@ -58,7 +58,7 @@ This example code is based on CocoaLumberjack logging into log files:
- (NSString *) getLogFilesContentWithMaxSize:(NSInteger)maxSize { - (NSString *) getLogFilesContentWithMaxSize:(NSInteger)maxSize {
NSMutableString *description = [NSMutableString string]; NSMutableString *description = [NSMutableString string];
NSArray *sortedLogFileInfos = [[[Logging fileLogger] logFileManager] sortedLogFileInfos]; NSArray *sortedLogFileInfos = [[_fileLogger logFileManager] sortedLogFileInfos];
NSUInteger count = [sortedLogFileInfos count]; NSUInteger count = [sortedLogFileInfos count];
// we start from the last one // we start from the last one
@ -96,3 +96,100 @@ This example code is based on CocoaLumberjack logging into log files:
@end @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 () <BITCrashManagerDelegate> {}
@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