56

Recently we came across a situation where we wanted to see the debug info from the app which a user has on his device. So, what I am looking for is a way to find the log on the device, paste it as inline text on a mail and allow the user to send it..

Any ideas? Here are the questions again.. 1)Find a debug log on the device 2)open the file and attach the contents of the file as inline text in to the mail. 3)Allow the user to email it the next time app launches..

Thanks,

Mobilewits
  • 1,743
  • 4
  • 21
  • 34
  • 1
    iTunes actually does that for you automagically. Check your iTunes-Connect account. – Till Nov 22 '11 at 20:40

9 Answers9

67

Thanks for all the inputs guys.. I clubbed your solutions into one that would solve my problem.. Here is what I made it to be.. Surely I did not compile the code, it is a half baked code.. but I will iron it soon once as I implement it in my code..

NSLog into file How to NSLog into a file LOG2FILE

#if TARGET_IPHONE_SIMULATOR == 0    
    NSArray *paths =  
    NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);        
    NSString *documentsDirectory = [paths objectAtIndex:0];    
    NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.log"];    
    freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
#endif

Catch the Crash and Log them too into a File

First, create a function that will handle the error and output it to the console (as well as whatever else you want to do with it):

void uncaughtExceptionHandler(NSException *exception) {    
    NSLog(@"CRASH: %@", exception);      
    NSLog(@"Stack Trace: %@", [exception callStackSymbols]);    
    // Internal error reporting
}

Next, add the exception handler to your app delegate:

-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:  
(NSDictionary*)launchOptions
{   
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);    // Normal launch stuff
}

Set a variable in the info.plist called Crashed and then read/write it this way

- (void)readPlist
 {
      NSString *localizedPath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"plist"];        
      NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:localizedPath];

    NSString *crashed;
    crashed = [plistDict objectForKey:@"Crashed"];
}


- (void)writeToPlist
{
    NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];

    [plistDict setValue:@"YES" forKey:@"Crashed"];
    [plistDict writeToFile:filePath atomically: YES];
}

Once the app launches read the info.plist and prompt the user to submit the crash logs..

{
    MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
    mailComposer.mailComposeDelegate = self;[mailComposer setSubject:@"Crash Log"];
    // Set up recipients
    NSArray *toRecipients = [NSArray arrayWithObject:@"first@example.com"]; 
    [mailComposer setToRecipients:toRecipients];
    // Attach the Crash Log..
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.log"];
    NSData *myData = [NSData dataWithContentsOfFile:logPath];
    [mailComposer addAttachmentData:myData mimeType:@"Text/XML" fileName:@"Console.log"];
    // Fill out the email body text
    NSString *emailBody = @"Crash Log";
    [mailComposer setMessageBody:emailBody isHTML:NO];
    [self presentModalViewController:mailComposer animated:YES];
}
grebulon
  • 7,697
  • 5
  • 42
  • 66
Mobilewits
  • 1,743
  • 4
  • 21
  • 34
  • Works great, thanks. I added the Mail function code in a separate method and call it from a button that lets the user email the debug log. You have to add the didFinishWithResult in mail controller to dismiss the modal view and return to the app. – anuragbh Jul 17 '12 at 15:31
  • NSString *localizedPath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"plist"]; - actually you CAN NOT save data to plist in mainBundle. so use documents folder – Dmitriy Kalachniuk Sep 20 '12 at 09:04
  • 1
    Interesting solution. Why trying to write to plist, when you could use `NSUserDefaults`? – Houman Nov 26 '13 at 22:17
  • 3
    Unfortunately, this method does not catch all kind of crashes. Crashes that are due to deallocated objects being called will not be caught. I know because it happened to me :) – Duck Jan 30 '14 at 19:53
  • @AppvolutionTech or any body can please translate this code into Swift :) – Qadir Hussain Mar 05 '15 at 07:32
  • Don't forget about [`+ canSendMail`](https://developer.apple.com/library/ios/documentation/MessageUI/Reference/MFMailComposeViewController_class/#//apple_ref/occ/clm/MFMailComposeViewController/canSendMail) method – DanSkeel Jun 15 '15 at 13:03
  • How to do this mail in Swift ?? I am struking in "A C Function pointer cannot be formed from a local function captures context" http://stackoverflow.com/questions/32952611/how-to-use-nssetuncaughtexceptionhandler-to-show-exception-message-on-uiview-in The same error... Kindly guide me. – McDonal_11 Sep 01 '16 at 11:28
51
  1. For logging your own data, use Cocoalumberjack. It is much faster than NSLog and can be turned on/off dynamically. It also provides options to save the data into a file. NSLog will slow down your app and fills the console log. Also you don't want to log too much in general. You cannot safely do logging when the crash happens. So rather once you figured out where the problem area is, add some more logging there and try to reproduce it, e.g. by using automated testing frameworks like KIF.

  2. For catching crash report you should nothing else than a solution based on the open source framework PLCrashReporter, which can safely catch crashes, also when you app is already in the app store! Exception catching as suggested by others is not recommended, check this article to see why!

    iTunes Connect offers you to view some crash reports too, but it takes up to 2 weeks to see some, but by far not all as e.g. pointed out by the Camera+ developers. So you better use your own solution.

    PLCrashReporter will send you standard apple formatted crash reports, ready for symbolication, so you know where the crash happens in your code, including line numbers.

    Some solutions based on PLCrashReporter are:

    • QuincyKit: Open Source client + php server, basic crash grouping, symbolication can be automated from your mac (I am the developer of this)
    • HockeyApp: Paid service, uses QuincyKit client, advanced crash grouping, symbolication fully done on the server (I am on of the developers of this)
    • Bugsense: Free service, no symbolication
    • AppBlade: FREE service if used with 25 devices or less, no symbolication
    • Crashlytics: Private beta, unknown features, their solution seems to be based on PLCrashReporter
  3. The proposed solutions either allow sending the data automatically on the next startup or by asking the user if he/she agrees to send.

rb413
  • 171
  • 1
  • 5
Kerni
  • 15,241
  • 5
  • 36
  • 57
  • BugSense currently offers symbolication on the device. – Nick Toumpelis Dec 15 '11 at 18:10
  • @Kerni how do you do automated symbolication on your machine (does it have to be a Mac) with QuincyKit? – Roberto Jan 22 '12 at 07:38
  • @Roberto Yes it has to be a mac. QuincyKit has a modified symbolization script, launch agent etc. bundled. Check the read me on how to set it up: https://github.com/TheRealKerni/QuincyKit/blob/develop/README.markdown – Kerni Jan 22 '12 at 10:11
5

For logging & analytics under Swift you can use SwiftyBeaver, it is a full-featured logging platform including open-source Swift 2 & Objective-C Framework, encrypted cloud storage and Mac App.

Website: https://swiftybeaver.com

Framework (supporting): https://github.com/SwiftyBeaver/SwiftyBeaver

Disclaimer: I am a founder.

Sebastian
  • 8,952
  • 3
  • 32
  • 30
  • can this be used to push the logs to the server? or integrate with google docs.? – Ccr May 10 '16 at 08:15
  • Yes, it can be used to push logs to the server. It even has its own, end-to-end encrypted logging platform. – Sebastian May 10 '16 at 08:40
  • @sebastian, It's a really cool framework. Can you pls confirm like how many user's(devices) log can this, sync up to cloud. If any store app is using this framework means, the app has to get the user consent before collecting the log data..right? Finally, how can we ensure that syncing up the logs to cloud doesn't slow down the app..? – Anand May 10 '17 at 17:09
5

This is a solution that catches crashes as they happen, it will give more human readable code info than a crash log. It will lack some of the crash log, but as Till says, you should be able to access those anyway.

From another SO question about the Xcode 4.2 always returning to main upon crashing. The answer there uses this method and you can extend it to keep track of crashes.

implement your own exception handler in the AppDelegate

// on load
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

void uncaughtExceptionHandler(NSException *exception) {
    NSLog(@"CRASH: %@", exception);
    NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    // Internal error reporting
}

UPDATE I did some backtracking and this solution was offered by Zane Claes to the question Xcode 4.2 debug doesn't symbolicate stack call

He offers a general solution in his second comment. "I find it to be useful to write the crash log to a file and prompt the user to submit it on the next launch (in release mode only, to not get in the way of debugging). This lets me get great bug reports... and the users know that their problem is being addressed" I understand not everybody would like to ask this of the user, but there are super users out there that would be glad to help out.

You could of course include a never show me this prompt again button so that people are not frustrated by reporting mechanism.

Alternatively, You could reach out to a server with the info (not sure if it will work as it is crashing, but save it and occasionally try to POST to a server with the details)

Community
  • 1
  • 1
Jesse Black
  • 7,966
  • 3
  • 34
  • 45
3

I've been using Crittercism to automate this for me. Works for testing and in production too.

Jeff
  • 31
  • 1
1

BugSense provides crash reporting services for iOS. Apart from providing a fully symbolicated stack trace, BugSense provides analytics for your crashes, across all your applications.

I think it's better than email, because when your app becomes popular you will need to manage all these emails manually, while BugSense does this automatically. However, BugSense is also open-source, so you can modify its internals any way you want and add any additional functionality.

In addition to that, you get us to work for you for free: If you have an idea about a cool new feature that you want us to have, we'll do it -provided we think it's cool, too.

Disclaimer: I write the code for BugSense-iOS.framework.

Nick Toumpelis
  • 2,717
  • 22
  • 38
0

See Ryan's answer in How to view NSLog statement from iphone .app file for a free utility provided by Apple.

But this is still no convenient solution. If you can afford a new build, you should change your logging within the app. Jano has some very good ideas on this in How to NSLog into a file. Especially option 2 should do without too much effort.

In general I would recommend hiding native logging facilities behind a facade or similar design just at the beginning of the project regardless what programming language is used.

Community
  • 1
  • 1
Kay
  • 12,918
  • 4
  • 55
  • 77
-1

I have used below code to catch debug logs - Swift 4.1

var paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let fileName = "Logfile.txt"
let logFilePath = (documentsDirectory as NSString).appendingPathComponent(fileName)
freopen(logFilePath.cString(using: String.Encoding.ascii)!, "a+", stderr)
Prashant Gaikwad
  • 3,493
  • 1
  • 24
  • 26
-1

If you use the TestFlight with their SDK this is automated. It's a really nice system. For test builds only, however.

https://testflightapp.com/sdk/

TomSwift
  • 39,369
  • 12
  • 121
  • 149