Re: Now available -- Re: [ANN] UKCrashReporter 0.1
Re: Now available -- Re: [ANN] UKCrashReporter 0.1
- Subject: Re: Now available -- Re: [ANN] UKCrashReporter 0.1
- From: Nicko van Someren <email@hidden>
- Date: Thu, 9 Feb 2006 12:27:53 +0000
On 8 Feb 2006, at 12:18, Scott Anguish wrote:
A copy of Uli Kusterer's UKCrashReporter v 0.1 is now available at
http://www.stepwise.com/temp/UKCrashReporter_21-35-21.zip
Uli's original announcement follows
...
UKCrashReporter is a simple function that you can call at
application startup to send crash reports for your application to a
CGI on your server. No patches, no daemons, no helper applications.
In case people are interested, I attach below some code I used in a
program of my own (built for household use, never released). Rather
than polling on start-up I used launchd to watch the crash log and
had it send the log back to my web server immediately when the
program crashed.
This method has both advantages and disadvantages over Uli's code.
There are two core advantages as I see it. Firstly, in the case of
programs like share-ware, it's not uncommon for people to never run
the program again if it crashes soon after it's first started. If
you only check for crashes on a subsequent run you may miss useful
information. Secondly, if the program is crashing early on in the
start-up process then the report might never get sent. (In the case
of my program, which was crashing on my mother at one point, the
problem was a corrupt preferences file and I think that that would
stop Uli's code looking up the last crash date and it would never
send the report).
The flip side of this is that my code requires a secondary helper
application to send the report. I used a simply command line utility
(which I'm not including because it's rubbish code I wrote years ago
and the guts of Uli's code would be a much better place to start from
than my thing). That said, the helper app can reside inside your
application and the code below copes with the user moving or renaming
your application and it is removed cleanly by deleting the application.
Anyway, the code is below. Enjoy!
Nicko
=====================
//
// NvSCrashReporter.m
//
// Created by Nicko van Someren on 08/02/2006.
// Copyright 2006 nicko.org. All rights reserved.
//
// This code is free for anyone to use for commercial or non-
commercial purposes.
// Caveat Machinator!
// No guarantee is expressed or implied. This code may or may not
do what you need.
// Read it, understand it and only then use it if you think it might
be useful.
// When the application's crash log is updated the reportProg
program is called with
// the program name, the URL to which to send the files, the crash
log file name and
// optionally a list of extra files (e.g. preferences or support
files).
#import "NvSCrashReporter.h"
static BOOL reporterStarted = NO;
static NSString *launchctlPath = @"/bin/launchctl";
@implementation NvSCrashReporter
+ (BOOL) registerCrashReporter: (NSString *) reportProg // Null
means HttpPoster in the main bundle
URLString: (NSString *) target // Must
be specified
applicationName: (NSString *) name // Null
means the main bundle name
crashLog: (NSString *) logFile // Log
file to watch, or NULL for the default
extraFiles: (NSArray *) extras { //
Optional extra files to be sent (e.g. preferences)
if (reporterStarted) {
NSLog(@"Reporter already started");
return NO;
}
NSFileManager *defMan = [NSFileManager defaultManager];
NSString *launchFile;
// Start by getting hold of various information about the bundle
of the calling application
NSBundle *b = [NSBundle mainBundle];
NSDictionary *info = [b infoDictionary];
// Can't post, won't post
if (!target)
return NO;
// Default name for the crash posting porgram
if (!reportProg)
reportProg = @"HttpPoster";
if (![reportProg hasPrefix: @"/"])
reportProg = [b pathForResource: reportProg ofType: Nil];
// Get the name of the program if we're not already given it
if (!name)
name = [[b infoDictionary] objectForKey: @"CFBundleName"];
if (!name)
name = [b bundleIdentifier];
if (!name)
return NO;
// Make sure that the log file exists (launchd needs this)
if (!logFile)
logFile = [[NSString stringWithFormat: @"~/Library/Logs/
CrashReporter/%@.crash.log", [info objectForKey:
@"CFBundleExecutable"] ] stringByExpandingTildeInPath];
if (![defMan fileExistsAtPath: logFile]) {
NSLog(@"Crash log does not exist; touching the file");
if (![@"" writeToFile: logFile atomically: YES]) {
NSLog(@"Cound not touch crash log file");
return NO;
}
}
NSLog(@"Parameters after defaulting:\ntarget=%@\nreportProg=%@
\nname=%@\nlogFile=%@", target, reportProg, name, logFile);
// Ensure the presence of the directory for the launch files
launchFile = [@"~/Library/Application Support/NvSCrashReporter"
stringByExpandingTildeInPath];
BOOL isDir;
if ([defMan fileExistsAtPath: launchFile isDirectory: &isDir]) {
if (!isDir)
return NO;
} else {
if (![defMan createDirectoryAtPath: launchFile attributes:
Nil])
return NO;
}
NSLog(@"Reporter directory looks OK");
// Construct the launch file path
launchFile = [launchFile stringByAppendingPathComponent:
[NSString stringWithFormat: @"%@.launch.plist", name]];
if ([defMan fileExistsAtPath: launchFile]) {
// There seems to be an existing launch file, so we ask
launchd to unload it
// since it my be an old version or the user moved the
application elsewhere.
NSLog(@"Unloading old launcher");
[[NSTask launchedTaskWithLaunchPath: launchctlPath
arguments: [NSArray arrayWithObjects: @"unload", launchFile, nil]]
waitUntilExit];
}
// Now we can build a new launchd plist
NSMutableDictionary *ld = [NSMutableDictionary
dictionaryWithCapacity: 6];
[ld setObject: [NSString stringWithFormat:
@"org.nicko.CrashReporter.%@.%@", [b bundleIdentifier], NSUserName
() ] forKey: @"Label"];
[ld setObject: [NSNumber numberWithBool: YES] forKey: @"OnDemand"];
NSMutableArray *progArgs = [NSMutableArray arrayWithCapacity: 8];
[progArgs addObject: reportProg];
[progArgs addObject: name];
[progArgs addObject: target];
[progArgs addObject: logFile];
if (extras)
[progArgs addObjectsFromArray: extras];
[ld setObject: progArgs forKey: @"ProgramArguments"];
[ld setObject: [NSArray arrayWithObject: logFile] forKey:
@"WatchPaths"];
NSLog(@"Created new launch file: %@", ld);
// Write the plist into the launch file
if (![ld writeToFile: launchFile atomically: YES])
return NO;
NSLog(@"Launch file saved; trying to load into launchd");
// Finally, ask launchd to load the file
NSTask *t = [NSTask launchedTaskWithLaunchPath: launchctlPath
arguments: [NSArray arrayWithObjects: @"load", launchFile, nil]];
[t waitUntilExit];
if ([t terminationStatus]) {
NSLog(@"Launchd failed to register crash reporter; returned %
d", [t terminationStatus]);
return NO;
}
NSLog(@"Success!");
reporterStarted = YES;
return YES;
}
@end
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden