programing

파일에 NS 로그인하는 방법

minimums 2023. 9. 15. 20:51
반응형

파일에 NS 로그인하는 방법

모든 것을 쓰는 것이 가능합니까?NSLog콘솔뿐만 아니라 파일로도?이것을 교체하지 않고 준비하고 싶습니다.NSLog안으로someExternalFunctionForLogging.

모두 교체하는 것은 정말 문제가 될 것입니다.NSLog할 수 이 있습니까? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

옵션 1: ASL 사용

NSLog는 로그를 ASL(Apple 버전의 syslog) 및 콘솔로 출력합니다. 이는 아이폰 시뮬레이터를 사용할 때 이미 Mac의 파일에 쓰고 있음을 의미합니다.읽으려면 Console.app 응용프로그램을 열고 필터 필드에 응용프로그램의 이름을 입력합니다.아이폰 기기에서도 똑같이 하려면 ASL API를 사용하고 코딩을 해야 합니다.

옵션 2: 파일에 쓰기

시뮬레이터에서 실행 중인데 Console.app을 사용하지 않겠다고 가정해 보겠습니다.freopen: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를 사용하여 문서 디렉토리를 추가하지 않으면 액세스할 수 없습니다.

훨씬쉬운 접근법이 있습니다.출력을 응용프로그램의 파일로 리디렉션하는 방법은 다음과 같습니다.Documents 를 뽑아 할 수 있습니다.이것은 개발 스튜디오 밖에서 맥에서 플러그를 뽑아 앱을 테스트하고 싶을 때 유용할 수 있습니다.

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

스위프트:

// 1. Window > Devices and Simulators
// 2. Select the device
// 3. Select your app and click gear icon
// 4. Download container
// 5. Right click and "view contents"
// 6. Find "yourfile.log" under Downloads
//
// redirectLogToDocuments()

func redirectLogToDocuments() {
  let allPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
  let documentsDirectory = allPaths.first!
  let pathForLog = "\(documentsDirectory)/yourfile.log"
  freopen(pathForLog.cString(using: String.Encoding.ascii)!, "a+", stdout)
}

한 후 한 된 은 를 은 에 의해 생성된 모든 출력NSLog( (ObjC)는print(Swift)는 지정된 파일로 전달됩니다.한을는법법는oOrganizer프로그램의 및 저장, 의 Application Data파일 시스템의 어딘가에, 단순히 찾아보기만 하는 것이 아니라Documents폴더.

이 문제에 대한 가장 간단한 해결책을 찾았습니다.아이폰의 파일에 로그인합니다. NSLog 코드를 변경하거나 로거 자체를 변경할 필요가 없습니다. 이 4줄을 완료된 FinishLaunchingWithOptions에 추가하고 빌드 설정에서 라이브 릴리스가 활성화되지 않도록 하십시오(를 위해 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의 답변을 스위프트에게 번역하여 다른 사람도 필요로 하는 경우에는 여기에 올렸습니다.

이 코드를 앱의 어딘가에서 실행하면, 그 순간부터 파일에 출력된 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 > Devices > 앱 선택 > InfoWheelButton > 다운로드 컨테이너finder로 파일 보기 : file에서 마우스 오른쪽 버튼 클릭 > package content > appdata > documents > 파일은

스위프트 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

좋아요! 먼저 에반 뮬라우스키에게 감사를 표합니다.여기 제 해결책이 있습니다. 아마도 누군가에게 도움이 될 것입니다.

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 -> log This를 사용합니다.이 코드는 제 앱에 맞게 수정되었습니다.다양한 요구에 맞게 확장할 수 있습니다.


도와주셔서 감사합니다.

이것이 제가 사용하는 것이고 잘 작동합니다.

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

스위프트 2.0:

Appelegate did가 옵션을 사용하여 시작을 마쳤습니다.

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 Log Area에 로그 경로가 인쇄되면 경로를 선택하고 마우스 오른쪽 버튼을 누른 후 Finder에서 Services - Reaveal을 선택하고 file console.log를 엽니다.

Alvin George의 답변을 조금 참고했습니다.

로그 파일 크기를 제어하기 위해 "10세대 로그 파일" 솔루션을 구현하고 나중에 삭제하는 기능을 추가했습니다.

앱이 시작될 때마다 인덱스가 "0"인 새 로그 파일이 생성됩니다.나가는 파일의 이름이 이전보다 높은 인덱스로 바뀝니다.인덱스 "10"이 삭제됩니다.

시작할 때마다 최대 10세대에 이르는 새로운 로그 파일이 제공됩니다.

가장 우아한 방법은 아닐 수도 있지만 지난 몇 주 동안은 매우 효과적이었습니다. "맥을 끊는" 오랜 로깅이 필요했기 때문입니다.

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

반응형