Search code examples
iphonejailbreaknslog

NSLog limit exceeded how to workaround, expand or capture


I am writing a Mobilesubstrate tweak to capture the functions involved in performing a particular task on MobileSafari together with the timestamp where its called. I created this tweak and redirected the output to NSLog and saw many of the following message:

process 778 exceeded 500 log message per second limit  -  remaining messages this second discarded

When I used by own log file instead of NSLog, MobileSafari took too long to start and was killed. Is it possible to hook a function and log its function arguments (logify for c based functions) and time/data where its called using a low-overhead method? Is using a custom logging facility possible on iPhone (jailbroken) using and available methods like ASL libraries?

EDIT: I have tried to work around the problem by creating an NSOperationQueue, an NSOperation called LoggingOperation and embed the class right in the Tweak.xm file. I believe this can relief the main thread to update the UI and complete launching MobileSafari. The tweak can compile but when the function is hit, LoggingOperation did not write to the file, resulting in an empty log file:

//LoggingOperation.h
@interface LoggingOperation : NSOperation {
NSString *event;
}

@property(retain) NSString *Event;

- (id)initWithEvent:(NSString*)ev;

@end

Inside the NSOperation implementation:

//LoggingOperation.m
@implementation LoggingOperation

@synthesize Event;

- (id)initWithEvent:(NSString*)ev;
{
    if (![super init]) return nil;
    [self setEvent:ev];
    return self;
}

- (void)dealloc {
    [Event release], Event = nil;
    [super dealloc];
}

- (void)main {

    NSString *serverError = event;
    if (![[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/mylog.log"])
    {
            NSString *statusFileName = [NSString stringWithFormat:@"/var/mobile/mylog.log"];    
            NSFileManager *fileManager = [NSFileManager defaultManager];
            [fileManager createFileAtPath:statusFileName contents:nil attributes:nil];
    }
    serverError = [serverError stringByAppendingString:@"\n"];
    NSString *serverFile = [NSString stringWithFormat:@"/var/mobile/mylog.log"];
    NSData *serverText= [serverError dataUsingEncoding:NSUTF8StringEncoding];
    NSFileHandle *serverFileHandle = [NSFileHandle fileHandleForUpdatingAtPath:serverFile]; 
    if (serverFileHandle)
    {
        [serverFileHandle seekToEndOfFile];
            // this NSLog output appears in syslog but serverText is not written to mylog
        NSLog(@"WRITING TO THE LOG FILE!");
        [serverFileHandle writeData:serverText]; 
        [serverFileHandle closeFile];
    }
}

@end

I also created a convenience method for each hooked method to call to create a log:

void mylog(NSString* serverError)
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    LoggingOperation *op = [[LoggingOperation alloc] initWithEvent:serverError];
    [queue addOperation:op];
    [op release];
}

In the method hook itself:

CGRect replaced_CGRectIntegral (CGRect rect)
{
    mylog(@"CGRectIntegral(rect)");
    return o_CGRectIntegral(rect);
}

I wonder why am I writing to a file in an NSOperation and the file is empty?


Solution

  • I know it's not the answer you are looking for, but I would suggest rethinking your logging and reducing the amount of log statements generated. I would be asking the questions why are you logging these things? are they really telling you something important? and if you really need them for a debug session - how can you setup so that the task is only executed once for the test?

    Obviously in a release version you would not have this logging turned on.

    I've seen people write custom loggers in the Java world to hook onto method calls and log them and all their parameters. In every case it has been a waste of time because of the massive amount of data produced and the system slow downs generated. Logging is extremely useful when targeted well. It must be concise, contain information that is useful and only generated when there is something worth while to be said.