Hello guys I have found this code that is used to create a different NSLog (without data and timestamps) that displays the class where the log was made and the line number.
I have read that is possible to disable the logging only for certain classes with NO_LOG but there was not explained how to use it exactly, I am quite new to obj-c and I appreciate an explanation on how to disable logging for certain classes and how to activate and deactivate the debugging. thanks
#define MAKESTRING(__VA_ARGS__) #__VA_ARGS__
#define TOSTRING(...) MAKESTRING(__VA_ARGS__)
static inline void PxReportv(BOOL doLog, char const *file, int line, NSString *prefix, NSString *fmt, va_list argList) {
if (doLog) {
NSString *fileNameWithExtension = [[NSString stringWithFormat:#"%s", file] lastPathComponent];
#ifdef NO_LOG
NSString *fileName = [fileNameWithExtension stringByDeletingPathExtension];
char *f = TOSTRING(NO_LOG);
NSArray *comps = [[[NSString alloc] initWithFormat:#"%s", f] componentsSeparatedByString:#","];
for (NSString *except in comps) {
if ([except isEqualToString:fileName]) {
return;
}
}
#endif
vprintf([[[NSString alloc] initWithFormat:[[NSString alloc] initWithFormat:#"%# <%# [%d]> %#\n", prefix, fileNameWithExtension, line, fmt] arguments:argList] cStringUsingEncoding:NSUTF8StringEncoding], NULL);
}
}
static inline void PxReport(BOOL doLog, char const *file, int line, NSString *prefix, NSString *fmt, ...) {
va_list ap;
va_start(ap, fmt);
PxReportv(doLog, file, line, prefix, fmt, ap);
va_end(ap);
}
#define PxError(...) PxReport(YES, __FILE__, __LINE__, #"[ERROR]", __VA_ARGS__)
#ifdef DEBUG
#define PxDebug(...) PxReport(YES, __FILE__, __LINE__, #"[DEBUG]", __VA_ARGS__)
#define NSLog(...) PxReport(YES, __FILE__, __LINE__, #"", __VA_ARGS__)
#else
#define PxDebug(...)
#define NSLog(...)
#endif
Add this:
#define NO_LOG 1
before #importing the file you've shown above.
BTW a better implementation would define PxDebug() and NSLog() to nothing if NO_LOG was defined...
that is quite a verbose solution, i made one that is a lot neater than that
#ifndef DebugLog_h
#define DebugLog_h
#if DEBUG
#define DLog(...) do{\
printf("[%s:%d]", __FUNCTION__, __LINE__);\
NSString *_S_ = [NSString stringWithFormat:__VA_ARGS__];\
printf(" %s\n",[_S_ cStringUsingEncoding:NSUTF8StringEncoding]);\
}while(0);
#else
#define DLog(...)
#endif
#endif
that will print the line number, class and function it came from
eg:
Dlog(#"hello %d", 123);
[-[SomeViewController viewWillAppear:]:91] hello 123
edit: if you add the file to your projectname-Prefix.pch file, then you can use it without having to include it everywhere
and it will automatically be taken out of release builds, because DEBUG is defined as a project definition automatically when its in debug mode
Related
the code:
<UIKit/UIApplication.h> line 293-297
#if UIKIT_STRING_ENUMS
typedef NSString * UIApplicationLaunchOptionsKey NS_EXTENSIBLE_STRING_ENUM;
#else
typedef NSString * UIApplicationLaunchOptionsKey;
#endif
<UIKit/UIKitDefines.h>
#define UIKIT_STRING_ENUMS ((defined(SWIFT_SDK_OVERLAY_UIKIT_EPOCH) && SWIFT_SDK_OVERLAY_UIKIT_EPOCH >= 2))
What is #define UIKIT_STRING_ENUMS ?
UIKIT_STRING_ENUMS is a macro to control how Objective-C code is imported into Swift
I'm trying to solve a problem in an iOS program that was recently ported to 64 bits.
I discovered that stringWithUTF8String always returns nil, and I was able to narrow the problem to a very simple 12 liners. Here is my main.m file
#import <UIKit/UIKit.h>
#include <string>
int main(int argc, char* argv[])
{
std::string a("hello");
NSString * s1 = [NSString stringWithUTF8String: a.c_str()];
NSString * s2 = [[NSString alloc] initWithUTF8String: a.c_str()];
NSString * s3 = [NSString stringWithUTF8String: "hello"];
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, #"AppDelegate");
}
}
s1, s2, and s3 are nil when I debug the program on an iPad Air 2 !
I am inclined to think there might be either an obvious problem in the code, or there is a configuration error in the project settings since it was ported to 64 bits (this code used to work perfectly).
Does anyone have a clue?
Thanks in advance
EDIT :
I just tested the code in a new project under OSX (File|New Project|Command Line Tool), and it works.
So, it seems that my problem is due to the project settings. I do not know where to look although.
Argh, I'm going nuts.
I've got the following function which I am trying to log with a custom logger
CFWriteStreamWrite(CFWriteStreamRef stream, const UInt8 *buffer,
CFIndex bufferLength) {
NSData *data = [[NSData alloc] initWithBytes:buffer length: bufferLength];
NSString *errorDesc = nil;
NSPropertyListFormat format;
NSString * str = (NSString*)[NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc];
custom_log(CF, "CFURLCreateWithString: %s", str);
}
When I use my custom logger I get rubbish output
CFURLCreateWithString: < °3€
But when using NSLog, everything works fine,
Feb 10 00:36:39: {
bundleID = "com.test.testapp";
pid = 2852;
}
Custom Logger
EXPORT void custom_log(unsigned int facility, const char *msg, ...) {
if (minLogLevel <= INFO) {
char *msgBuffer;
va_list args;
va_start(args, msg);
vasprintf(&msgBuffer, msg, args);
va_end(args);
dispatch_async(logQueue, ^{
write(facility, INFO, msgBuffer);
});
}
}
Please tell me where I'm going wrong, I have spent the past 3 hours trying to convert to different data types. No luck.
Also, is it possible to get the output from NSLog into a string and then I'll just pass it to my logger instead?
One of the problems that you might be experiencing here is that NSString is not the same as the c_str that your vasprintf method is likely expecting to substitute for %s.
To compound this issue, I'm pretty sure you can't directly convert NSPropertyListSerialization to NSString, though I didn't test it myself. You might be looking for such an alternative instead:
NSString * str = [NSString stringWithFormat:#"%#", [NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc]];
custom_log(CF, "CFURLCreateWithString: %s", [str UTF8String]);
Of course, since you're already compositing a string, why not just do it all in the same place?
NSString * str = [NSString stringWithFormat:#"CFURLCreateWithString: %#", [NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc]];
custom_log(CF, [str UTF8String]);
As a fun side project, you might consider doing something like this in your main.mm. Replace stderr with stdout if you want more than just error stuff:
#if COPY_NSLOG_TO_CUSTOM
typedef int (*MyStdWriter)(void *, const char *, int);
static MyStdWriter _oldStdWrite;
int __customStderrWrite(void *inFD, const char *buffer, int size) {
if (minLogLevel <= INFO) {
// write to your custom stream here.
}
return _oldStdWrite(inFD, buffer, size);
}
void __copyNSLogToCustom(void) {
_oldStdWrite = stderr->_write;
stderr->_write = __customStderrWrite;
}
#endif
int main(int argc, char *argv[]) {
#if COPY_NSLOG_TO_CUSTOM
__copyNSLogToCustom();
#endif
// ...
}
I am passing a hard-coded NSString and converting to NSArray. Here I want to pass an NSString using command line and convert to an NSArray:
#import <Foundation/Foundation.h>
NSArray*sampleMethod(NSString*val){
NSString *newStr = [val substringFromIndex:1];
NSString *newStr1 = [newStr substringToIndex:[newStr length]-1];
NSString *trimmed = [newStr1 stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSArray *yourWords = [trimmed componentsSeparatedByString:#","];
return yourWords;
}
int main(int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *value =#"{1,2,3}";// hard code value
NSArray* ip1= sampleMethod(value);
/*
NSArray* ip1= sampleMethod(argv[1]);
here i want to read from command line and convert in to array
*/
printf("output: %# ",ip1);
[pool drain];
return 0;
}
I am trying to find a way for Cocoa Lumberjack to show me file and line number.
After looking through the docs and some Googling, I found no easy way to do this.
Is there any way to do this without adding custom formatter?
Well, like I said, there is no built-in way. So, I've implemented custom formatter:
#interface LineNumberLogFormatter : NSObject<DDLogFormatter>
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage;
#end
#implementation LineNumberLogFormatter
- (NSString *)formatLogMessage:(DDLogMessage *)logMessage
{
NSString *path = [NSString stringWithCString:logMessage->file encoding:NSASCIIStringEncoding];
NSString *fileName = [path lastPathComponent];
return [NSString stringWithFormat:#"%#:%d %#", fileName, logMessage->lineNumber, logMessage->logMsg];
}
#end
While a separate formatter class would work, it would make your logging code a bit more verbose. In my project I opted for adding some additional macros that make use of CocoaLumberjack like so:
// Prefix.pch file
// ...
#ifdef DEBUG
#define DLogError(fmt, ...) DDLogError((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DLogWarn(fmt, ...) DDLogWarn((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DLogInfo(fmt, ...) DDLogInfo((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DLogDebug(fmt, ...) DDLogDebug((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#define DLogVerbose(fmt, ...) DDLogVerbose((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define DLogError(fmt, ...)
#define DLogWarn(fmt, ...)
#define DLogInfo(fmt, ...)
#define DLogDebug(fmt, ...)
#define DLogVerbose(fmt, ...)
#endif
In your client code, you could then call:
DLogWarn(#"This is a warning");
As UrK suggested, there isn't any trivial way, but it's pretty simple if you define your own formatter (see doc)