Home > OS >  Capturing NSLog Output with Firebase Crashlytics
Capturing NSLog Output with Firebase Crashlytics

Time:12-16

I used to use Crashlytics long ago and there was a simple macro that could be used to capture all output from NSLog() to send it along with the crash report to Crashlytics. Very very helpful so that if a user has a crash, I can see the related logging that led up to it. I even had this working after Google gobbled up Crashlytics for awhile.

But a few years (many?) later and I'm trying to use Crashlytics in a new project and none of these macros are working anymore. The best I've come up with is the following :

#define NSLog(...) [[FIRCrashlytics crashlytics] logWithFormat:(__VA_ARGS__)]

However this generates compile warnings for every NSLog call and it does not appear to be compatible with anything either than NSStrings as arguments to the format. For instance the following will not compile...

NSLog (@"My Float Value : %f", myFloat);

I realize this is Objective C so my apologies to the Swift folk out there. Also I'm not sure if switching over to OSLog would actually help either. I'm just looking to capture the logging output so I can get some more information past just the stack trace. Otherwise this is no better than what TestFlight gives me and is therefore useless to add in for my use case.

CodePudding user response:

Remove the parenthesis around the __VA_ARGS__ from the macro:

#define NSLog(...) [[FIRCrashlytics crashlytics] logWithFormat: __VA_ARGS__]

After doing that, I was able to call these NSLogs:

    NSLog (@"My Float Value %f", 1.0);
    NSLog (@"My Float string %s", "some string");
    NSLog (@"My decimal Value %d", 963);

And this is the result I got in the crash report:

enter image description here

CodePudding user response:

In order to resolve this for a call that has both a format string and values for that format string (NSLog (@"My Value %d", myValue);) and the case for just a single string (NSLog (@"Hello");) then the solution I found was this...

#define NSLog(__FORMAT__, ...) { NSString * str = [NSString stringWithFormat:__FORMAT__, ##__VA_ARGS__]; [[FIRCrashlytics crashlytics] log:str];}

However I ended up with this instead.

#define NSLog(__FORMAT__, ...) rrlog(__FORMAT__, ##__VA_ARGS__)

And this Class...

@interface RRLogger : NSObject

OBJC_EXTERN void rrlog(NSString* format, ...) NS_FORMAT_FUNCTION(1, 2);

@end

@implementation RRLogger

void rrlog(NSString* format, ...)
{
    if (!format) return;
    
    va_list args;
    va_start(args, format);
    
    NSString *msg = [[NSString alloc] initWithFormat:format arguments:args];
    
    NSLogv(format, args);
    
    va_end(args);
    
    [[FIRCrashlytics crashlytics] log:msg];
}

@end

The reason for this is because the Firebase -FIRDebugEnabled launch argument in my launch scheme wasn't outputting everything to the console. I'm not sure why but it was missing some of the log output. Hence the call to NSLogv in the above function.

  • Related