24 июня 2010 г.

Улучшаем NSLog()

Большим плюсом NSLog'а является возможность следить за состоянием программы без использования точек останова. Но не всегда информации предоставляемой этой функцией достаточно. Стандартный вывод NSLog() такой:

<дата> <время> <имя_приложения> [<pid>]  то, что выдаст NSLog

А хотелось бы чтобы в этой информации присутствовали как минимум имя исходного файла и номер строки. Кроме того было-бы желательно иметь возможность сохранять лог в файл.

Вариант для решения данной задачи и является нижеприведенный класс.

@interface Logger : NSObject {

   BOOL isWriteToFile;
}
@property (readonly) BOOL isWriteToFile;

+ (id) sharedLogger;
- (BOOL) setOutFile:(NSString *)outFile;
- (void) logOut:(char*)sourceFile lineNumber:(int)lineNumber
                format:(NSString*)format, ...;
@end

@implementation Logger

static Logger *_logger = nil;

@synthesize isWriteToFile;

+(void) initialize{
   if (self = [Logger class]) {
      _logger = [[Logger alloc] init];
   }
}

-(id)init{
   if ((self = [super init])) {
      isWriteToFile = NO;
   }
   return self;
}

+(id) sharedLogger {
   return _logger;
}

- (BOOL) setOutFile:(NSString *)outFile {
   [@"" writeToFile:outFile atomically:YES 
                    encoding:NSUTF8StringEncoding error:nil];
   id fileHandle = [NSFileHandle fileHandleForWritingAtPath:outFile];
   if (!fileHandle)
      return NSLog(@"Opening log failed"), NO;
   [fileHandle retain];
   // Redirect stderr
   int err = dup2([fileHandle fileDescriptor], STDERR_FILENO); 
   if (!err) return NSLog(@"Couldn't redirect stderr"), NO;
   isWriteToFile = YES;
   return YES;
}

- (void) logOut:(char*)sourceFile lineNumber:(int)lineNumber 
                format:(NSString*)format, ...{
   va_list ap;
   va_start(ap,format);
   NSString *print=[[NSString alloc] initWithFormat:format arguments:ap];
   va_end(ap);
   NSLog(@"%s:%d %@",[[[NSString stringWithUTF8String:sourceFile] 
                       lastPathComponent] UTF8String], lineNumber, print);
   [print release];
}

@end

Чтобы перенаправить вывод лога в файл используем:

   [[Logger sharedLogger] setOutFile:@"logout.txt"];

И несколько макросов:

#ifdef __DEBUG__ 

#define LoggerOut(s,...) \
[[Logger sharedLogger] logOut:__FILE__ lineNumber:__LINE__ \
format:(s),##__VA_ARGS__]

#else

#define LoggerOut(s,...) NSLog(s,##__VA_ARGS__)

#endif

С помощью которых можно использовать конструкцию вида

   LoggerOut(@"Тест");
   LoggerOut(@"Еще один %@", @"тест");

как в релиз так и в дебаг конфигурации, и на выходе будет:

2010-06-24 16:07:08.883 test-app[64895:a0f] test-app.m:13 Тест
2010-06-24 16:07:08.885 test-app[64895:a0f] test-app.m:14 Еще один тест

Комментариев нет:

Отправить комментарий