How to NSLog into a file

Is it possible to write every NSLog not only into console, but into a file too? I want to prepare this without replacing NSLog into someExternalFunctionForLogging.

It will be real problem to replace all NSLog. Maybe there is possibility for parsing data from console or catching messages?

Option 1: Use ASL

NSLog outputs log to ASL (Apple's version of syslog) and console, meaning it is already writing to a file in your Mac when you use the iPhone simulator. If you want to read it open the application Console.app, and type the name of your application in the filter field. To do the same in your iPhone device, you would need to use the ASL API and do some coding.

Option 2: write to a file

Let's say you are running on the simulator and you don't want to use the Console.app. You can redirect the error stream to a file of your liking using freopen: freopen([path cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr); See this explanation and sample project for details.

Or you can override NSLog with a custom function using a macro. Example, add this class to your project:

// file Log.h
#define NSLog(args...) _Log(@"DEBUG ", __FILE__,__LINE__,__PRETTY_FUNCTION__,args);
@interface Log : NSObject
void _Log(NSString *prefix, const char *file, int lineNumber, const char *funcName, NSString *format,...);
@end

// file Log.m
#import "Log.h"
@implementation Log
void _Log(NSString *prefix, const char *file, int lineNumber, const char *funcName, NSString *format,...) {
    va_list ap;
    va_start (ap, format);
    format = [format stringByAppendingString:@"\n"];
    NSString *msg = [[NSString alloc] initWithFormat:[NSString stringWithFormat:@"%@",format] arguments:ap];   
    va_end (ap);
    fprintf(stderr,"%s%50s:%3d - %s",[prefix UTF8String], funcName, lineNumber, [msg UTF8String]);
    [msg release];
}
@end

And import it project wide adding the following to your <application>-Prefix.pch:

#import "Log.h"

Now every call to NSLog will be replaced with your custom function without the need to touch your existing code. However, the function above is only printing to console. To add file output, add this function above _Log:

void append(NSString *msg){
    // get path to Documents/somefile.txt
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"logfile.txt"];
    // create if needed
    if (![[NSFileManager defaultManager] fileExistsAtPath:path]){
        fprintf(stderr,"Creating file at %s",[path UTF8String]);
        [[NSData data] writeToFile:path atomically:YES];
    } 
    // append
    NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:path];
    [handle truncateFileAtOffset:[handle seekToEndOfFile]];
    [handle writeData:[msg dataUsingEncoding:NSUTF8StringEncoding]];
    [handle closeFile];
}

and add this line below fprintf in the _Log function:

append(msg);

File writing also works in your iPhone device, but the file will be created in a directory inside it, and you won't be able to access unless you add code to send it back to your mac, or show it on a view inside your app, or use iTunes to add the documents directory.

Redirecting NSLog Output to a File on Demand for iPhone , NSLog can be a great tool for debugging when developing iPhone applications. It outputs a formatted message to StdErr, which is the console view in Xcode by  Thanks for the link ! As dup2 does redirect all stderr, it's really quite blunt. I like that NSLog prints both in Xcode and in the console — opening Console. app is a quick and easy way to see if/where your app failed, so I'm all in favor of NSLog, debug or release :)

There is a far easier approach. Here is the method that redirects NSLog output into a file in application’s Documents folder. This can be useful when you want to test your app outside your development studio, unplugged from your mac.

ObjC:

- (void)redirectLogToDocuments 
{
     NSArray *allPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
     NSString *documentsDirectory = [allPaths objectAtIndex:0];
     NSString *pathForLog = [documentsDirectory stringByAppendingPathComponent:@"yourFile.txt"];

     freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
}

Swift:

func redirectLogToDocuments() {

    let allPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let documentsDirectory = allPaths.first!
    let pathForLog = documentsDirectory.stringByAppendingString("/yourFile.txt")

    freopen(pathForLog.cStringUsingEncoding(NSASCIIStringEncoding)!, "a+", stderr)
}

After executing this method all output generated by NSLog (ObjC) or print (Swift) will be forwarded to specified file. To get your saved file open Organizer, browse application’s files and save Application Data somewhere in your file system, than simply browse to Documents folder.

Redirecting NSLog to a file, This will redirect to a root file /NSLog.txt . After that, launch your app and use tail in Terminal to see your log updates : > tail -f /NSLog.txt  To get the file path as a string, use path instead: let logPath = dir.appendingPathComponent(file).path Better, use the dedicated method to pass an URLs path to a system call: let logFileURL = dir.appendingPathComponent(file) logFileURL.withUnsafeFileSystemRepresentation { _ = freopen($0, "a+", stderr) }

I found the simplest solution to the problem: Logging to a file on the iPhone . No need to change any NSLog code or change logger itself, just add these 4 lines to your didFinishLaunchingWithOptions and make sure in your build settings that live release will not have this activated (I added LOG2FILE flag for this).

#ifdef LOG2FILE
 #if TARGET_IPHONE_SIMULATOR == 0
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.log"];
    freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
 #endif
#endif

Writing Log Files with NSLogger - Claus Höfele, Since this issue only happens when using the app in the field, I was looking into writing log files that I can analyze once I'm back at my desk to figure out how to  Teams. Q&A for Work. Stack Overflow for Teams is a private, secure spot for you and your coworkers to find and share information.

Translated the answer of JaakL to Swift, posting it here in any case someone else needs it as well

Run this code somewhere in your app, from that moment it stores all NSLog() output to a file, in the documents directory.

let docDirectory: NSString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as NSString
let logpath = docDirectory.stringByAppendingPathComponent("YourFileName.txt")
freopen(logpath.cStringUsingEncoding(NSASCIIStringEncoding)!, "a+", stderr)

Extra: How to find the log-file with Xcode: You can simply acces the log from Xcode: Windows > Devices > Choose your app > InfoWheelButton > download container. View the file with finder: click right mouse button on file > show package content > appdata > documents > And there the files are

Redirect the nslog output to file instead of console, Redirecting the nslog output to a file is useful in scenerios when device is not connected to system and we need the console logs to track down  Option 1: Use ASL. NSLog outputs log to ASL (Apple's version of syslog) and console, meaning it is already writing to a file in your Mac when you use the iPhone simulator. If you want to read it open the application Console.app, and type the name of your application in the filter field.

Ok! firstly, I want to thank Evan-Mulawski. Here is my solution, maybe it will be helpful for someone:

In AppDelegate I add Function:

void logThis(NSString* Msg, ...)
{   
    NSArray* findingMachine = [Msg componentsSeparatedByString:@"%"];
    NSString* outputString = [NSString stringWithString:[findingMachine objectAtIndex:0]];
    va_list argptr;
    va_start(argptr, Msg);

    for(int i = 1; i < [findingMachine count]; i++) {
        if ([[findingMachine objectAtIndex:i] hasPrefix:@"i"]||[[findingMachine objectAtIndex:i] hasPrefix:@"d"]) {
            int argument = va_arg(argptr, int); /* next Arg */
            outputString = [outputString stringByAppendingFormat:@"%i", argument];      
            NSRange range;
            range.location = 0;
            range.length = 1;
            NSString* tmpStr = [[findingMachine objectAtIndex:i] stringByReplacingCharactersInRange:range withString:@""];
            outputString = [outputString stringByAppendingString:tmpStr];
        }
        else if ([[findingMachine objectAtIndex:i] hasPrefix:@"@"]) {
            id argument = va_arg(argptr, id);
            // add argument and next patr of message    
            outputString = [outputString stringByAppendingFormat:@"%@", argument];
            NSRange range;
            range.location = 0;
            range.length = 1;
            NSString* tmpStr = [[findingMachine objectAtIndex:i] stringByReplacingCharactersInRange:range withString:@""];
            outputString = [outputString stringByAppendingString:tmpStr];
        }
        else if ([[findingMachine objectAtIndex:i] hasPrefix:@"."]) {
            double argument = va_arg(argptr, double);       
            // add argument and next patr of message    
            outputString = [outputString stringByAppendingFormat:@"%f", argument];
            NSRange range;
            range.location = 0;
            range.length = 3;
            NSString* tmpStr = [[findingMachine objectAtIndex:i] stringByReplacingCharactersInRange:range withString:@""];
            outputString = [outputString stringByAppendingString:tmpStr];
        }
        else if ([[findingMachine objectAtIndex:i] hasPrefix:@"f"]) {
            double argument = va_arg(argptr, double);       
            // add argument and next patr of message    
            outputString = [outputString stringByAppendingFormat:@"%f", argument];
            NSRange range;
            range.location = 0;
            range.length = 1;
            NSString* tmpStr = [[findingMachine objectAtIndex:i] stringByReplacingCharactersInRange:range withString:@""];
            outputString = [outputString stringByAppendingString:tmpStr];
        }
        else {
            outputString = [outputString stringByAppendingString:@"%"];
            outputString = [outputString stringByAppendingString:[findingMachine objectAtIndex:i]];
        }
    }
    va_end(argptr);
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
    NSString *  filePath = [[paths objectAtIndex:0]stringByAppendingPathComponent:@"logFile.txt"];
    NSError* theError = nil;
    NSString * fileString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&theError];
    if (theError != nil||[fileString length]==0) {
        fileString = [NSString stringWithString:@""];
    }
    fileString = [fileString stringByAppendingFormat:@"\n%@",outputString];
    if(![fileString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&theError])
    {
            NSLog(@"Loging problem");
    }

    NSLog(@"%@",outputString);
}

and, then use "replace for all" NSLog -> logThis. This code is adapted for my app. It can be expand for different needs.


Thnks for help.

Logging to your own file using NSLog, I'd recommend you have a look at CocoaLumberjack instead of using the code here in anything you're working on. Have you ever found yourself  There's a far more convenient way to trace with log messages in Xcode, and that's using Breakpoint Actions. On the line of code where you'd be tempted to add a printf or NSLog, set a breakpoint, then control-click it and choose "Edit Breakpoint".

Redirect NSLog to a file on the iPhone, The method below will create a file name “console.log” in the Documents folder of your application so you can later read it. Just call this method in  What would be the best way to write log statements to a file or database in an iPhone application? Ideally, NSLog() output could be redirected to a file using freopen(), but I've seen several reports that it doesn't work. Does anyone have this going already or have any ideas how this might best be done? Thanks!

Easy way to redirect NSLog to a physical file on your phone / ipad , Is it possible to write every NSLog not only into console, but into a file too? I want to prepare this without replacing NSLog into  The log files and various troubleshooting data can be obtained from NetScaler Configuration Utility too, To download specific files using GUI Navigate to System>Diagnostics>Maintenance>Delete/Download log files. You can download the specific files and can share the same with support.

NetScaler newnslog Files Not Compressed Which Results in /var , //the .mm file void saveNSLogToFile() { //Neat way to send NSLog output to a log file in the device. The file can then be sent to the developer. Learn how to use NSLog() for outputing logs to the Console.

Comments
  • You can replace NSLog with another function call using a #define.
  • I tried to follow the top answer below but this just messes with my project and throws a ton of parse issues in NSObjCRuntime.h and all over NSobject etc.
  • You can use the Organizer to get the text file: Select "Devices" - #Your Device# - "Applications". Select your application. You see your file (amongst others) in the "Data files in Sandbox" tree below. Click "Download". You now have the file on your mac, and can rightclick "Show Package Contents" to browse to your text file.
  • Can we create a category on NSLog?
  • How can i create a category on the class of NSLog ? If yes, can you please suggest what is the class name where NSLog function present? I tried to create category of NSObjCRuntime using "objective c category file creation template" and it is not allowing me go next. Please suggest me how i override NSLog ? Thanks.
  • @PrasadG NSLog is not part of any class. It is a C function. To override it you have to redefine it as I did with #define above.
  • When I try to Log an [object description] use this way, system get error. I don't know why.
  • when i use this after run the application i have got more than 1 log files , why it become ? can we not use it for only single file?
  • freopen(pathForLog.cStringUsingEncoding(NSASCIIStringEncoding)!, "a+", stderr) . Instead of stderr we need stdout for all logs to redirect to file. With stderr only error logs would go to file.
  • I think NSLog only writes to stderr.
  • Can somebody please guide, how to clear this file, once its copied into clipboard, so as to start over for next launch of app.
  • One thing I've seen is that if you use a mix of print and NSLog in Swift then they don't get logged into the file in the correct order (prints seem to come much later or not at all). My preference is usually to use NSLog to get the timestamp info anyway.