Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write stderr on iPhone to both file and console

Tags:

ios

stderr

iphone

I'm following the suggestion in the answer here for redirecting NSLog output on an iOS device to a file, which works great. The problem is that it no longer shows up in the console on the device. What I'd really like is a way to tee the stderr stream to both the console and the file. Does anyone have an idea how to do that?

like image 739
David Potter Avatar asked Sep 28 '11 01:09

David Potter


3 Answers

I found an acceptable answer on another thread (NSLog() to both console and file).

The solution provided there is to only redirect to a file if a debugger is not detected, like this:

if (!isatty(STDERR_FILENO))
{
    // Redirection code
}

Thanks to Sailesh for that answer.

like image 74
David Potter Avatar answered Oct 26 '22 17:10

David Potter


Once you freopen() the file descriptor, you can read from it and do as you please with the data. Some ideas from this will be useful to you.

You could either write it back out to stdout, or try to write directly to /dev/console. I've never tried to open /dev/console on an iPhone, but I'm guessing it's possible despite being outside of the sandbox. I'm not sure how the app review process will treat it.

like image 26
QED Avatar answered Oct 26 '22 18:10

QED


Or you can redirect to a TCP socket and view on a remote telnet client. No need for XCode this way!

Basically:

  1. Create a standard C function which calls an Obj-C static method:

    void tcpLogg_log(NSString* fmt, ...)
    {
        va_list args;
        va_start(args, fmt);
        [TCPLogger tcpLog:fmt :args];
        va_end(args);
    }
    
  2. The static Obj-C method:

    (void)tcpLog:(NSString*)fmt :(va_list)args
    {
        NSLogv(fmt, args);
    
    
    if(sharedSingleton != nil && sharedSingleton.socket  != nil)
    {
      NSString *time = [sharedSingleton.dateFormat stringFromDate:[NSDate date]];
      NSString *msg = [[NSString alloc] initWithFormat:fmt arguments:args];
      mach_port_t tid = pthread_mach_thread_np(pthread_self());
    
      NSString *str = [NSString stringWithFormat:@"%@[%X]: %@\r\n", time, tid, msg];
      NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
      [sharedSingleton.socket writeData:data 
                              withTimeout:NETWORK_CLIENT_TIMEOUT_PERIOD 
                              tag:0];                                                
    }
    
    }
  3. Then in your .pch file, add the following lines to override NSLog()

    define NSLog(...) tcpLogg_log(__VA_ARGS__); 
    void tcpLogg_log(NSString* fmt, ...);
    

Of course more details are required to handle the TCP Socket. Working source code is available here: https://github.com/driedler/iOS-TCP-Logger/wiki/About

like image 35
driedler Avatar answered Oct 26 '22 16:10

driedler