UKCrashReporter
Language: Objective-C, Author: Uli Kusterer
License: MIT/X11
A simple function that you can call at application startup to send crash reports for your application to a CGI on your server.
UKCrashReporter source preview
// // UKCrashReporter.m // NiftyFeatures // // Created by Uli Kusterer on Sat Feb 04 2006. // Copyright (c) 2006 M. Uli Kusterer. All rights reserved. // // ----------------------------------------------------------------------------- // Headers: // ----------------------------------------------------------------------------- #import "UKCrashReporter.h" // ----------------------------------------------------------------------------- // UKCrashReporterCheckForCrash: // This submits the crash report to a CGI form as a POST request by // passing it as the request variable "crashlog". // // KNOWN LIMITATION: If the app crashes several times in a row, only the // last crash report will be sent because this doesn't // walk through the log files to try and determine the // dates of all reports. // // This is written so it works back to OS X 10.2, or at least cracefully // fails by just doing nothing on such older OSs. This also should never // throw exceptions or anything on failure. This is an additional service // for the developer and *mustn't* interfere with regular operation of the // application. // ----------------------------------------------------------------------------- void UKCrashReporterCheckForCrash() { NS_DURING // Try whether the classes we need to talk to the CGI are present: Class NSMutableURLRequestClass = NSClassFromString( @"NSMutableURLRequest" ); Class NSURLConnectionClass = NSClassFromString( @"NSURLConnection" ); if( NSMutableURLRequestClass == Nil || NSURLConnectionClass == Nil ) NS_VOIDRETURN; // Get the log file, it's last change date and last report date: NSString* appName = [[[NSBundle mainBundle] infoDictionary] objectForKey: @"CFBundleExecutable"]; NSString* crashLogsFolder = [@"~/Library/Logs/CrashReporter/" stringByExpandingTildeInPath]; NSString* crashLogName = [appName stringByAppendingString: @".crash.log"]; NSString* crashLogPath = [crashLogsFolder stringByAppendingPathComponent: crashLogName]; NSDictionary* fileAttrs = [[NSFileManager defaultManager] fileAttributesAtPath: crashLogPath traverseLink: YES]; NSDate* lastTimeCrashLogged = (fileAttrs == nil) ? nil : [fileAttrs fileModificationDate]; NSTimeInterval lastCrashReportInterval = [[NSUserDefaults standardUserDefaults] floatForKey: @"UKCrashReporterLastCrashReportDate"]; NSDate* lastTimeCrashReported = [NSDate dateWithTimeIntervalSince1970: lastCrashReportInterval]; if( lastTimeCrashLogged ) // We have a crash log file and its mod date? Means we crashed sometime in the past. { // If we never before reported a crash or the last report lies before the last crash: if( [lastTimeCrashReported compare: lastTimeCrashLogged] == NSOrderedAscending ) { if( NSRunAlertPanel( NSLocalizedStringFromTable( @"WANT_TO_SEND_CRASH_TITLE", @"UKCrashReporter", @"" ), NSLocalizedStringFromTable( @"WANT_TO_SEND_CRASH", @"UKCrashReporter", @"" ), NSLocalizedStringFromTable( @"WANT_TO_SEND_CRASH_SEND", @"UKCrashReporter", @"" ), NSLocalizedStringFromTable( @"WANT_TO_SEND_CRASH_DONT_SEND", @"UKCrashReporter", @"" ), @"", appName ) ) { // Fetch the newest report from the log: NSString* crashLog = [NSString stringWithContentsOfFile: crashLogPath]; NSArray* separateReports = [crashLog componentsSeparatedByString: @"\n\n**********\n\n"]; NSString* currentReport = [separateReports count] > 0 ? [separateReports objectAtIndex: [separateReports count] -1] : @"*** Couldn't read Report ***"; NSData* crashReport = [currentReport dataUsingEncoding: NSUTF8StringEncoding]; // 1 since report 0 is empty (file has a delimiter at the top). //NSLog(@"Report = \"%@\"", currentReport); // Prepare a request: NSMutableURLRequest *postRequest = [NSMutableURLRequestClass requestWithURL: [NSURL URLWithString: NSLocalizedStringFromTable( @"CRASH_REPORT_CGI_URL", @"UKCrashReporter", @"" )]]; NSString *boundary = @"0xKhTmLbOuNdArY"; NSURLResponse *response = nil; NSError *error = nil; NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary]; NSString *agent = @"UKCrashReporter"; // Add form trappings to crashReport: NSData* header = [[NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"crashlog\"\r\n\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]; NSMutableData* formData = [[header mutableCopy] autorelease]; [formData appendData: crashReport]; [formData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; // setting the headers: [postRequest setHTTPMethod: @"POST"]; [postRequest setValue: contentType forHTTPHeaderField: @"Content-Type"]; [postRequest setValue: agent forHTTPHeaderField: @"User-Agent"]; [postRequest setHTTPBody: formData]; (NSData*) [NSURLConnectionClass sendSynchronousRequest: postRequest returningResponse: &response error: &error]; } // Remember we just reported a crash, so we don't ask twice: [[NSUserDefaults standardUserDefaults] setFloat: [[NSDate date] timeIntervalSince1970] forKey: @"UKCrashReporterLastCrashReportDate"]; [[NSUserDefaults standardUserDefaults] synchronize]; } } NS_HANDLER NSLog(@"Exception during check for crash: %@",localException); NS_ENDHANDLER }
UKCrashReporter header preview
// // UKCrashReporter.h // NiftyFeatures // // Created by Uli Kusterer on Sat Feb 04 2006. // Copyright (c) 2006 M. Uli Kusterer. All rights reserved. // // ----------------------------------------------------------------------------- // Headers: // ----------------------------------------------------------------------------- #import <Foundation/Foundation.h> // ----------------------------------------------------------------------------- // Prototypes: // ----------------------------------------------------------------------------- /* Call this sometime during startup (e.g. in applicationDidLaunch) and it'll check for a new crash log and offer to the user to send it. The crash log is sent to a CGI script whose URL you specify in the UKUpdateChecker.strings file. If you want, you can even have different URLs for different locales that way, in case a crash is caused by an error in a localized file. */ void UKCrashReporterCheckForCrash();Download Archive
Compatible with:
- Mac OS X 10.2
- Mac OS X 10.3
- Mac OS X 10.4 PPC
- Mac OS X 10.4 Intel
- Mac OS X 10.5 PPC
- Mac OS X 10.5 Intel
Comments
Comment feed
