[ANN] UKCrashReporter 0.1

  • Hi guys,

      I just posted UKCrashReporter to my web site. The URL is:

    http://www.zathras.de/angelweb/sourcecode.htm#UKCrashReporter

    The general implementation is based on the suggestion for a crash
    reporter that John Gruber wanted to suggest to the developers of
    PathFinder before they implemented it themselves:

    http://daringfireball.net/2006/01/smart_crash_reports

    So, what's it do?

    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.

    Cheers,
    -- M. Uli Kusterer
    http://www.zathras.de
  • folks, just an update

    Apparently ULI is having some connectivity issues and his server is
    down.

    I'll post an alternative link for him later today.

    stay tuned.

    On Feb 6, 2006, at 3:46 PM, Uli Kusterer wrote:

    > Hi guys,
    >
    > I just posted UKCrashReporter to my web site. The URL is:
    >
    > http://www.zathras.de/angelweb/sourcecode.htm#UKCrashReporter
    >
    > The general implementation is based on the suggestion for a crash
    > reporter that John Gruber wanted to suggest to the developers of
    > PathFinder before they implemented it themselves:
    >
    > http://daringfireball.net/2006/01/smart_crash_reports
    >
    > So, what's it do?
    >
    > 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.
    >
    > Cheers,
    > -- M. Uli Kusterer
    > http://www.zathras.de
    >
    >
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<scott...>
    >
    > This email sent to <scott...>
  • 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

      I just posted UKCrashReporter to my web site. The URL is:

    http://www.zathras.de/angelweb/sourcecode.htm#UKCrashReporter

    (temporarily available here http://www.stepwise.com/temp/
    UKCrashReporter_21-35-21.zip)

    The general implementation is based on the suggestion for a crash
    reporter that John Gruber wanted to suggest to the developers of
    PathFinder before they implemented it themselves:

    http://daringfireball.net/2006/01/smart_crash_reports

    So, what's it do?

    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.

    ---

    note that I have no affiliation with this software. Uli just needed a
    temporary home for it, and I was able to hook him up.
  • 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
  • from cocoadev

    Alan

    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      (<Cocoa-dev...>)
    Help/Unsubscribe/Update your Subscription:
    http://lists.apple.com/mailman/options/cocoa-dev/<alan...>

    This email sent to <alan...>
  • Perhaps you do so elsewhere, but I think it is important to note that
    the user should be prompted before any "personal" information is sent
    around the world. Even if one trusts the endpoints to be trustworthy,
    there are less than savory eavesdropping practices occurring as we
    speak.

    -M

    On Feb 9, 2006, at 6:27 AM, Nicko van Someren wrote:
    > 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.
    <snip code>

    |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-
    AgentM
    <agentm...>
    |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-
  • On 9 Feb 2006, at 15:11, AgentM wrote:

    > On Feb 9, 2006, at 6:27 AM, Nicko van Someren wrote:
    >> 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.
    > <snip code>

    > Perhaps you do so elsewhere, but I think it is important to note
    > that the user should be prompted before any "personal" information
    > is sent around the world. Even if one trusts the endpoints to be
    > trustworthy, there are less than savory eavesdropping practices
    > occurring as we speak.

    Indeed.  In this model it is the helper application that must prompt
    the user since if the main app is sick to the point of crashing there
    is no way it can prompt the user.  With regards the transport of the
    users' information, the standard way to deal with this would be to
    send the data over SSL.  Uli's code for transmitting the data (using
    an NSMutableURLRequest) should be able to handle this fine.

    Nicko
  • On 06/02/06, Uli Kusterer <kusterer...> wrote:
    >
    > I just posted UKCrashReporter to my web site. The URL is:
    >
    > http://www.zathras.de/angelweb/sourcecode.htm#UKCrashReporter
    >

    Folks,

    just wanted to mention that my server seems to be up again (*knocks on wood
    and hugs rabbit's foot*), now that all those visitors of the Taiwanese
    hotlinker that caused the breakdown are gone (1.7 GB of traffic in a single
    day! Jolly!). Keep your fingers crossed that this won't happen again...

    And thanks again to Scott Anguish, who kept UKCrashReporter available on
    his site in the meantime. You ROCK!

    And I have oodles of blogging ideas to remember and write...

    Cheers,
    M. Uli Kusterer
    ------------------------------------------------------------
          "The Witnesses of TeachText are everywhere..."
                      http://www.zathras.de
previous month february 2006 next month
MTWTFSS
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28          
Go to today