Reputation: 554
I've found a bunch of macro variations on how to use NSLog as a basis and adding PRETTY_FUNC and LINE but all the variations of those macros simply output the result to the console.
I'd like to have a macro that can take a format with a variable number of arguments, add the name of the method and line number where it was called and then return an NSString but so far, the compiler always complains where I call it. My latest version is as follow:
#define FileLog(format, ...) {\
return [NSString stringWithFormat:@"\n %s [Line %d] \n %@",
__PRETTY_FUNCTION__,
__LINE__,
[NSString stringWithFormat:(format), ##__VA_ARGS__]];\
}
Each time I call it from my code, the compiler generates one of those errors:
error: expected expression before '{' token
I don't want to write a log class or use a framework for that. There must be a way to do that with a macro? Anyone?
Thanks in advance!
Upvotes: 2
Views: 7574
Reputation: 8124
From Viraj Thenuwara, who was my iOS Senior developer who trained me :-)
This macro is much more simpler in its definition and also its usage, than the things mentioned above.
#define debug 1
#if debug
#define AppLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define AppLog(...)
#endif
And it's usage is as follows:
NSString *url = @"http://google.com";
AppLog(@"url %@ and id %d", url, 5);
This AppLog line will print out it's given content only if the debug constant is equal to 1. At the Production time or in anytime you don't want to print the log lines you can disable it by turning that 1 into 0.
And it's console out put will be seen as follows:
Hope this will be helpful to someone else! Cheers!
Upvotes: 0
Reputation: 4176
This is entirely possible with a macro, I think you just need a little more background on them.
First, macros are not functions, so the braces are unnecessary (and, in fact, are the cause of your error). A macro is really a fairly dumb "copy/paste" that is automated by the preprocessor, using syntax that it understands.
In order to define a macro that spans multiple lines and creates an NSString "in place", you have to escape the newlines with backslashes, like so:
#define FileLog(format, ...) \
[NSString stringWithFormat:@"\n %s [Line %d] \n %@", \
__PRETTY_FUNCTION__, \
__LINE__, \
[NSString stringWithFormat:format, ##__VA_ARGS__]]
Macros do not "return" like a function does, because, as I mentioned, they are merely a way to "copy/paste" text.
You can use it like so:
int num = 42;
NSLog(@"%@", FileLog(@"some number: %d", num));
If you were to look at the preprocessor output (the file that the preprocessor creates before compilation), the above example would expand to something like:
NSLog(@"%@", [NSString stringWithFormat:@"\n %s [Line %d] \n %@", __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:@"some number: %d", num]]);
Upvotes: 8
Reputation: 2371
Try this....
Create an include file
#define LOG_NOLOG_LEVEL 0
#define LOG_ERROR_LEVEL 1
#define LOG_WARN_LEVEL 2
#define LOG_INFO_LEVEL 3
#define LOG_DEBUG_LEVEL 4
#if LOG_HELPER_LEVEL >= LOG_DEBUG_LEVEL
#define LOGDEBUG(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGDEBUG(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_INFO_LEVEL
#define LOGINFO(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGINFO(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_WARN_LEVEL
#define LOGWARN(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGWARN(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_ERROR_LEVEL
#define LOGERROR(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGERROR(...)
#endif
Then create a simple class LogHelper with a single class method as follows....
+ (void) log:(NSString *)message
{
fputs([message cStringUsingEncoding:NSUTF8StringEncoding], stderr);
}
Then in your code, you can put calls like...
LOGDEBUG(@"%s - %d Redirect response received\n%@",__FILE__,
__LINE__,[redirectRequest dumpInfo]);
You can set the LOG_HELPER_LEVEL to the level of logging you want to produce. If you set the level at say LOG_WARN_LEVEL, then no code will be included in your app for INFO or DEBUG levels, so it's easy to package your app up for release.
Hope this helps...
Upvotes: 2