Cómo ingresar a un file

¿Es posible escribir cada NSLog no solo en la console sino también en un file? Quiero preparar esto sin replace NSLog en someExternalFunctionForLogging .

Será un problema real replace todos los NSLog . ¿Tal vez existe la posibilidad de analizar datos desde la console o capturar posts?

Opción 1: usar ASL

NSLog registra el logging en ASL (versión de Apple de syslog) y la console, lo que significa que ya está escribiendo en un file en su Mac cuando utiliza el simulador de iPhone. Si desea leerlo, abra la aplicación Console.app y escriba el nombre de su aplicación en el campo del filter. Para hacer lo mismo en su dispositivo iPhone, necesitará utilizar la API de ASL y realizar alguna encoding.

Opción 2: escribir en un file

Digamos que se está ejecutando en el simulador y no desea usar Console.app. Puede networkingirigir el flujo de error a un file de su agrado utilizando freopen:
freopen([path cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
Vea esta explicación y muestre el proyecto para más detalles.

O puede anular NSLog con una function personalizada utilizando una macro. Ejemplo, agregue esta class a su proyecto:

 // 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 

E impórtelo de proyecto, agregando lo siguiente a su <application>-Prefix.pch :

 #import "Log.h" 

Ahora todas las llamadas a NSLog serán reemplazadas con su function personalizada sin la necesidad de tocar su código existente. Sin embargo, la function anterior solo está imprimiendo a la console. Para agregar salida de file, agregue esta function arriba _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]; } 

y agregue esta línea debajo de fprintf en la function _Log:

 append(msg); 

La escritura de files también funciona en su dispositivo iPhone, pero el file se creará en un directory dentro de él y no podrá acceder a less que agregue código para enviarlo de vuelta a su mac o mostrarlo en una vista dentro de su aplicación o use iTunes para agregar el directory de documentos.

Hay un enfoque mucho más fácil . Aquí está el método que networkingirige la salida NSLog a un file en Documents carpeta Documents la aplicación. Esto puede ser útil cuando desee probar su aplicación fuera de su estudio de desarrollo, desenchufada de su Mac.

ObjC:

 - (void)networkingirectLogToDocuments { NSArray *allPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [allPaths objectAtIndex:0]; NSString *pathForLog = [documentsDirectory stringByAppendingPathComponent:@"yourFile.txt"]; freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr); } 

Rápido:

 func networkingirectLogToDocuments() { let allPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) let documentsDirectory = allPaths.first! let pathForLog = documentsDirectory.stringByAppendingString("/yourFile.txt") freopen(pathForLog.cStringUsingEncoding(NSASCIIStringEncoding)!, "a+", stderr) } 

Después de ejecutar este método, toda la salida generada por NSLog (ObjC) o print (Swift) se reenviará al file especificado. Para que el file guardado esté abierto en el Organizer , navegue por los files de la aplicación y guarde los Application Data en algún lugar de su sistema de files, solo busque Documents carpeta Documents .

Encontré la solución más simple al problema: iniciar session en un file en el iPhone . No es necesario cambiar ningún código NSLog o cambiar el registrador por sí mismo, simplemente agregue estas 4 líneas a su didFinishLaunchingWithOptions y asegúrese de que en su configuration de compilation, la versión en vivo no tenga esta activada (agregué el distintivo LOG2FILE para esto).

 #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 

Traducido la respuesta de JaakL a Swift , publicándolo aquí, en cualquier caso, alguien más lo necesita también.

Ejecute este código en algún lugar de su aplicación, desde ese momento almacena todos los resultados de NSLog () en un file, en el directory de documentos.

 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: Cómo encontrar el file de logging con Xcode:
Simplemente puede acceder al logging desde Xcode: Windows> Dispositivos> Elija su aplicación> InfoWheelButton> download contenedor. Ver el file con buscador: haga clic con el button derecho del mouse en el file> mostrar el contenido del package> appdata> documentos> y allí los files están

¡De acuerdo! En primer lugar, quiero agradecer a Evan-Mulawski. Aquí está mi solución, tal vez sea útil para alguien:

En AppDelegate agrego Función:

 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); } 

y, luego, use "replace para todos" NSLog -> logThis. Este código está adaptado para mi aplicación. Se puede expandir para diferentes necesidades.


Busca ayuda.

Esto es lo que uso y funciona bien:

http://parmanoir.com/Redirecting_NSLog_to_a_file

Espero eso ayude.

Lo publicaré aquí por el contenido.

 - (BOOL)networkingirectNSLog { // Create log file [@"" writeToFile:@"/NSLog.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil]; id fileHandle = [NSFileHandle fileHandleForWritingAtPath:@"/NSLog.txt"]; 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 networkingirect stderr"), NO; return YES; } 

Swift 2.0:

Agregue estos a Appdelegate didFinishLaunchWithOptions.

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { var paths: Array = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) let documentsDirectory: String = paths[0] let logPath: String = documentsDirectory.stringByAppendingString("/console.log") if (isatty(STDERR_FILENO) == 0) { freopen(logPath, "a+", stderr) freopen(logPath, "a+", stdin) freopen(logPath, "a+", stdout) } print(logPath) return true } 

Acceso a console.log:

Cuando se imprima la ruta del logging en el área de logging de Xcode, select la ruta, haga clic derecho, elija Servicios Reaveal en el Finder y abra el file console.log

Trabajé un poco con la respuesta de Alvin George.

Para mantener bajo control los tamaños de los files de logging implementé (rápido y sucio) una solución de "10 generaciones de files de logging" y agregué una function para eliminarlos más tarde

Cada vez que se inicia la aplicación, generará un nuevo file de logging con un índice "0". Los files que salen serán renombrados con un índice mayor que antes. El índice "10" se eliminará.

Entonces, cada inicio te da un nuevo file de logging, máximo 10 generaciones.

Puede que no sea la manera más elegante de hacerlo, pero me funciona muy bien en las últimas semanas, ya que necesito un logging de larga duración "fuera de la Mac"

  // ----------------------------------------------------------------------------------------------------------- // networkingirectConsoleToFile() // // does two things // 1) networkingirects "stderr", "stdin" and "stdout" to a logfile // 2) deals with old/existing files to keep up to 10 generations of the logfiles // tested with IOS 9.4 and Swift 2.2 func networkingirectConsoleToFile() { // Instance of a private filemanager let myFileManger = NSFileManager.defaultManager() // the path of the documnts directory of the app let documentDirectory: String = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first! // maximum number of logfiles let maxNumberOfLogFiles: Int = 10 // look if the max number of files already exist var logFilePath : String = documentDirectory.stringByAppendingString("/Console\(maxNumberOfLogFiles).log") var FlagOldFileNoProblem: Bool = true if myFileManger.fileExistsAtPath(logFilePath) == true { // yes, max number of files reached, so delete the oldest one do { try myFileManger.removeItemAtPath(logFilePath) } catch let error as NSError { // something went wrong print("ERROR deleting old logFile \(maxNumberOfLogFiles): \(error.description)") FlagOldFileNoProblem = false } } // test, if there was a problem with the old file if FlagOldFileNoProblem == true { // loop over all possible filenames for i in 0 ..< maxNumberOfLogFiles { // look, if an old file exists, if so, rename it with an index higher than before logFilePath = documentDirectory.stringByAppendingString("/Console\((maxNumberOfLogFiles - 1) - i).log") if myFileManger.fileExistsAtPath(logFilePath) == true { // there is an old file let logFilePathNew = documentDirectory.stringByAppendingString("/WayAndSeeConsole\(maxNumberOfLogFiles - i).log") do { // rename it try myFileManger.moveItemAtPath(logFilePath, toPath: logFilePathNew) } catch let error as NSError { // something went wrong print("ERROR renaming logFile: (i = \(i)), \(error.description)") FlagOldFileNoProblem = false } } } } // test, if there was a problem with the old files if FlagOldFileNoProblem == true { // No problem so far, so try to delete the old file logFilePath = documentDirectory.stringByAppendingString("/Console0.log") if myFileManger.fileExistsAtPath(logFilePath) == true { // yes, it exists, so delete it do { try myFileManger.removeItemAtPath(logFilePath) } catch let error as NSError { // something went wrong print("ERROR deleting old logFile 0: \(error.description)") } } } // even if there was a problem with the files so far, we networkingirect logFilePath = documentDirectory.stringByAppendingString("/Console0.log") if (isatty(STDIN_FILENO) == 0) { freopen(logFilePath, "a+", stderr) freopen(logFilePath, "a+", stdin) freopen(logFilePath, "a+", stdout) displayDebugString(DEBUG_Others, StringToAdd: "stderr, stdin, stdout networkingirected to \"\(logFilePath)\"") } else { displayDebugString(DEBUG_Others, StringToAdd: "stderr, stdin, stdout NOT networkingirected, STDIN_FILENO = \(STDIN_FILENO)") } } // ----------------------------------------------------------------------------------------------------------- // cleanupOldConsoleFiles() // // delete all old consolfiles func cleanupOldConsoleFiles() { // Instance of a private filemanager let myFileManger = NSFileManager.defaultManager() // the path of the documnts directory of the app let documentDirectory: String = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first! // maximum number of logfiles let maxNumberOfLogFiles: Int = 10 // working string var logFilePath: String = "" // loop over all possible filenames for i in 0 ... maxNumberOfLogFiles { // look, if an old file exists, if so, rename it with an index higher than before logFilePath = documentDirectory.stringByAppendingString("/Console\(i).log") if myFileManger.fileExistsAtPath(logFilePath) == true { // Yes, file exist, so delete it do { try myFileManger.removeItemAtPath(logFilePath) } catch let error as NSError { // something went wrong print("ERROR deleting old logFile \"\(i)\": \(error.description)") } } } }