[Tech] Custom log lines (aliasing NSLog) #iOS #Objective-C
Written by Mathieu Poli on
Any developer knows the importance of logging while debugging. The more you log, the faster and easier it will be to find anomalies in the source code. It allows for instance to look at the data received from the network, in our case, the responses of the requests sent to our architecture.
Anyway, two problems can appear around this problematic :
- These logs, essentials in DEV, slow the app in PROD, and significantly degrade the user experience
- The proliferation of logs makes the console unreadable very quickly, which requires rigor in writing their labels
To solve these problems we have chosen to implement a logging system tailored to our needs. The idea is obviously not to reinvent the wheel - the standard system proposed by the iOS SDK is very effective - but to provide a simple to use tool, that ensures readability and performance.
// MFLog
The first step was to create an alias for the NSLog method, the MFLog. This way, it is very fast to disable logging when in PROD through the removal of a precompilation statement.
As we were free to redefine the alias as we wanted, we've created a single log format: [OBJECT - FUNCTIONS] LABEL, powered automatically by the SDK, which allows us to make the console much more readable.
Here is the definition of this alias:
#define MFDEBUG
#ifdef MFDEBUG
#define MFLog(x,...) NSLog(@"%s - %@", __FUNCTION__, [NSString stringWithFormat:(x), ##__VA_ARGS__])
#else
#define MFLog(x,...)
#endif
Here is a call to this log method (just like a classic NSLog call):
[...]
MFLog(@"Hello GoodBarbers :) %d", i);
[...]
And the console output:
Our development team always prefixes the class names and other methods with "GB" (for GoodBarber of course). But in this case, I used my custom log method far before the start of the project and had prefixed it with my initials. And it stayed like that ... :)
// MFImportantLog
In the same logic, we also needed a log that is not deactivated, so we created the variant MFImportantLog, following exactly the same model. This log is never disabled in PROD and is very useful to look for bugs that can't occur in DEV.
// MEMLog
In our iOS project, we choosed not to use ARC. As we manage our memory "by hand", this log allows us at any time to know the "retainCount" of an object and thus makes the memory debugging much easier.
The implementation of this log is a bit more complex than the previous ones. We had to subclass certain native objects (NSObject, UIView, UIViewController, ...) to redefine their memory management functions (retain, release, init, dealloc). So, everytime one of these methods is called, a log with the "retainCount" of the object is displayed.
These logs are of course activated / deactivated in each object via a simple boolean.
Here is the definition of the MEMLog alias, to get a pretty output:
Here is the definition of the MEMLog alias, to get a pretty output:
#define MEMLog(x, ...) NSLog(@"-[%@ %@] - %@", [[[[NSString stringWithFormat:@"%@", self] componentsSeparatedByString:@":"] objectAtIndex:0] stringByReplacingOccurrencesOfString:@"<" withString:@""], [[[[NSString stringWithFormat:@"%s", __FUNCTION__] componentsSeparatedByString:@" "] objectAtIndex:1] stringByReplacingOccurrencesOfString:@"]" withString:@""], [NSString stringWithFormat:(x), ##__VA_ARGS__])
The implementation of the MEMLog is quite long if you need it ponctually. But, at the scale of a project like GoodBarber, it helps us to save a lot of time when debugging!