파일에 NSLog하는 방법
NSLog
콘솔뿐만 아니라 파일에도 모두 쓸 수 있습니까? NSLog
로 바꾸지 않고 준비하고 싶습니다 someExternalFunctionForLogging
.
모두 교체하는 것이 진짜 문제가 될 것 NSLog
입니다. 콘솔에서 데이터를 구문 분석하거나 메시지를 포착 할 가능성이 있습니까?
옵션 1 : ASL 사용
NSLog는 ASL (Apple의 syslog 버전) 및 콘솔에 로그를 출력합니다. 즉, iPhone 시뮬레이터를 사용할 때 이미 Mac의 파일에 쓰고 있음을 의미합니다. 읽으려면 애플리케이션 Console.app을 열고 필터 필드에 애플리케이션 이름을 입력합니다. iPhone 장치에서 동일한 작업을 수행하려면 ASL API를 사용하고 일부 코딩을 수행해야합니다.
옵션 2 : 파일에 쓰기
시뮬레이터에서 실행 중이고 Console.app을 사용하고 싶지 않다고 가정 해 보겠습니다. freopen을 사용하여 오류 스트림을 원하는 파일로 리디렉션 할 수 있습니다.
freopen([path cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
자세한 내용은이 설명과 샘플 프로젝트 를 참조하십시오.
또는 매크로를 사용하여 사용자 지정 함수로 NSLog를 재정의 할 수 있습니다. 예를 들어, 다음 클래스를 프로젝트에 추가하십시오.
// 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
프로젝트 전체에 다음을 추가하여 가져옵니다 <application>-Prefix.pch
.
#import "Log.h"
이제 NSLog에 대한 모든 호출이 기존 코드를 건드릴 필요없이 사용자 지정 함수로 대체됩니다. 그러나 위의 기능은 콘솔에만 인쇄됩니다. 파일 출력을 추가하려면 _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];
}
_Log 함수의 fprintf 아래에 다음 줄을 추가합니다.
append(msg);
파일 쓰기는 iPhone 장치에서도 작동하지만 파일은 내부 디렉토리에 생성되며 코드를 추가하여 Mac으로 다시 보내거나 내부의보기에 표시하지 않으면 액세스 할 수 없습니다. 앱을 사용하거나 iTunes를 사용하여 문서 디렉토리를 추가하십시오.
이 훨씬 더 쉽게 접근 방식은. 다음은 NSLog
출력을 애플리케이션 Documents
폴더 의 파일로 리디렉션하는 방법입니다 . 이는 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);
}
빠른:
func redirectLogToDocuments() {
let allPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let documentsDirectory = allPaths.first!
let pathForLog = documentsDirectory.stringByAppendingString("/yourFile.txt")
freopen(pathForLog.cStringUsingEncoding(NSASCIIStringEncoding)!, "a+", stderr)
}
이 메서드를 실행하면 NSLog
(ObjC) 또는 print
(Swift)에 의해 생성 된 모든 출력이 지정된 파일로 전달됩니다. 저장된 파일을 열려면 단순히 폴더 를 찾아 보는 것보다 Organizer
응용 프로그램의 파일을 찾아보고 Application Data
파일 시스템에 Documents
저장하십시오.
문제에 대한 가장 간단한 해결책을 찾았습니다 . iPhone의 파일에 로깅 . NSLog 코드를 변경하거나 로거 자체를 변경할 필요가 없습니다.이 4 줄을 didFinishLaunchingWithOptions에 추가하고 빌드 설정에서 라이브 릴리스가 활성화되지 않는지 확인하십시오 (이를 위해 LOG2FILE 플래그를 추가했습니다).
#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
JaakL의 답변을 Swift로 번역하여 다른 사람도 필요로하는 경우 여기에 게시했습니다.
이 코드를 앱 어딘가에서 실행하면 그 순간부터 모든 NSLog () 출력이 문서 디렉토리의 파일에 저장됩니다.
let docDirectory: NSString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as NSString
let logpath = docDirectory.stringByAppendingPathComponent("YourFileName.txt")
freopen(logpath.cStringUsingEncoding(NSASCIIStringEncoding)!, "a+", stderr)
추가 : Xcode로 로그 파일을 찾는 방법 : Xcode
에서 로그에 간단히 액세스 할 수 있습니다 : Windows> 장치> 앱 선택> InfoWheelButton> 다운로드 컨테이너. 파인더로 파일보기 : 파일에서 마우스 오른쪽 버튼 클릭> 패키지 내용보기> appdata> 문서> 파일이 있습니다.
확인! 먼저 Evan-Mulawski에게 감사드립니다. 내 해결책은 다음과 같습니다. 누군가에게 도움이 될 것입니다.
AppDelegate에서 함수를 추가합니다.
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);
}
그런 다음 "replace for all"NSLog-> logThis를 사용하십시오. 이 코드는 내 앱에 맞게 조정되었습니다. 다양한 요구에 맞게 확장 할 수 있습니다.
도움을 청합니다.
이것이 내가 사용하고 잘 작동하는 것입니다.
http://parmanoir.com/Redirecting_NSLog_to_a_file
도움이 되었기를 바랍니다.
내용을 위해 여기에 게시하겠습니다.
- (BOOL)redirectNSLog {
// 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 redirect stderr"), NO; return YES;
}
Swift 2.0 :
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
}
console.log 액세스 :
로그 경로가 Xcode 로그 영역에 인쇄되면 경로를 선택하고 마우스 오른쪽 버튼을 클릭 한 다음 Finder에서 Services-Reaveal을 선택하고 console.log 파일을 엽니 다.
Swift 4 버전
let docDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let logpathe = docDirectory.appendingPathComponent("Logerr.txt")
freopen(logpathe.path.cString(using: .ascii)!, "a+", stderr)
let logpatho = docDirectory.appendingPathComponent("Logout.txt")
freopen(logpatho.path.cString(using: .ascii)!, "a+", stdout)
스위프트의 출력이 print()
될 것이다stdout
나는 Alvin George의 대답으로 약간 일했습니다.
로그 파일 크기를 제어하기 위해 "10 세대 로그 파일"솔루션을 구현하고 (빠르고 더티) 나중에 삭제하는 기능을 추가했습니다.
앱이 시작될 때마다 색인이 "0"인 새 로그 파일이 생성됩니다. 기존 파일은 이전보다 높은 색인으로 이름이 변경됩니다. 인덱스 "10"이 삭제됩니다.
따라서 시작할 때마다 최대 10 세대의 새 로그 파일이 제공됩니다.
이 작업을 수행하는 가장 우아한 방법은 아니지만 지난 몇 주 동안은 아주 잘 작동합니다. "Mac에서"오랫동안 로그를 기록해야하기 때문입니다.
// -----------------------------------------------------------------------------------------------------------
// redirectConsoleToFile()
//
// does two things
// 1) redirects "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 redirectConsoleToFile() {
// 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 redirect
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 redirected to \"\(logFilePath)\"")
} else {
displayDebugString(DEBUG_Others, StringToAdd: "stderr, stdin, stdout NOT redirected, 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)")
}
}
}
}
참고URL : https://stackoverflow.com/questions/7271528/how-to-nslog-into-a-file
'Development Tip' 카테고리의 다른 글
vue-cli 프로젝트에서 포트 번호를 변경하는 방법 (0) | 2020.12.13 |
---|---|
Android 장치에서 ARM 프로세서 버전을 찾는 방법은 무엇입니까? (0) | 2020.12.13 |
OnClickListener에 매개 변수를 전달하는 방법은 무엇입니까? (0) | 2020.12.13 |
CentOS 6에 php-mcrypt 설치 (0) | 2020.12.13 |
Bootstrap 3에서 navbar 높이를 어떻게 줄입니까? (0) | 2020.12.13 |