로그를 표시하는 NSTextView 만들기

개요



로그를 표시하는 앱을 만들었습니다.
오른쪽에 있는 Operation 버튼을 조작하면 버튼의 문자에 맞는 로그가 표시됩니다.
(실제로는 프로그램 처리 결과를 로그로 표시하는 데 사용합니다.)

누른 Operation 버튼에 따라 UI에 로그를 표시합니다.

[DEBUG] [TRACE] 에 관해서는 로그 파일에만 표시합니다. (사용자에게 알릴 필요가 없는 정보를 위해)

또한 동시에 app과 같은 위치에 로그 파일을 내보내고 있습니다.



GitHub



코드에 대한 자세한 내용은 GitHub를 참조하십시오.

구현-UI 부분



페타 페타와 부품을 붙여 넣습니다.



이번 로그의 표시에는 이하의 「Text View」(NSScrollView)를 사용합니다.



로그의 모양을 정렬하기 위해 글꼴은 등폭 글꼴을 사용합니다.
이번에는 Family명을 Osaka로 설정, Style을 등폭으로 합니다.



또한 오른쪽의 Operation 문자 아래에 늘어선 것은 NSButton의 Matrix입니다.
아래와 같이 IBAction 를 사용해 눌려진 버튼을 취득합니다.

NSButton의 Matrix 누를 때의 동작
// 画面右のOperationボタンが押下された場合
- (IBAction)operationButtonPush:(NSMatrix *)sender {
    int selectedRow = (int)sender.selectedRow;
    ...
}

구현 - 프로그램 부분



코드의 시작 부분에서 필요한 변수를 로컬 변수로 정의합니다.

로그 레벨에 관해서는, 이하의 기사를 참고로 했습니다.
로그 설계 지침

AppDelegate.m
static NSString *const kLogFileName = @"sample.log"; // 出力ログ名

// ログ表示の調節用
static NSString *const kWhiteSpaceAdjustment = @"                              ";
static NSString *const kSeparateLine = @"---------------------------------------";

// ログのレベル
// コンソール・ファイルの両方に出力
static NSString *const kLogLevel_Fatal = @"[FATAL]"; // プログラムの異常終了を伴うようなもの。
static NSString *const kLogLevel_Error = @"[ERROR]"; // 予期しないその他の実行時エラー
static NSString *const kLogLevel_Warn  = @"[WARN] "; // 廃要素となったAPIの使用、APIの不適切な使用、エラーに近い事象など。異常とは言い切れないが正常ではない予期しない問題
static NSString *const kLogLevel_Info  = @"[INFO] "; // 実行時の何らかの注目すべき事象(開始や終了など)。メッセージ内容は簡潔に止めるべき
// コンソールのみに出力
static NSString *const kLogLevel_Debug = @"[DEBUG]"; // システムの動作状況に関する詳細な情報
static NSString *const kLogLevel_Trace = @"[TRACE]"; // デバッグ情報よりも、更に詳細な情報

또 바인드 하는 오브젝트는 NSScrollView 는 아니고, NSTextView 인 것에 주의합니다.
@property (unsafe_unretained) IBOutlet NSTextView *logTextView;

로그의 TextView에 쓰는 부분



TextView에의 말미에의 캐릭터 라인 추가에 관해서는, 이하를 참고로 했습니다.
NSTextView의 끝에 문자를 추가하는 방법

날짜 부분의 세부 사항은 다음과 같습니다.
iPhone SDK 본체의 현지화 형식에 맞게 날짜 시간을 얻는 방법
/**
 @brief コメントをログビューに追加する(その際にログファイルの更新も併せて行う)
 @param message ログに表示する内容 level ログのレベル
 */
- (void)appendLogMessage:(NSString *)message logLevel:(NSString *)level {
    // ログ記録時刻
    NSDate          *logDate          = [NSDate date];
    NSDateFormatter *logDateFormatter = [[NSDateFormatter alloc] init];
    logDateFormatter.dateStyle        = NSDateFormatterMediumStyle;
    logDateFormatter.timeStyle        = NSDateFormatterMediumStyle;
    NSString        *logDateStr       = [logDateFormatter stringFromDate:logDate];
    NSMutableString *logMessage       = [NSMutableString stringWithFormat:@"%@ %@ %@\r\n", level, logDateStr, message];

    // アプリ画面のログ表示(ログレベルがDEBUG, TRACEならばUI上のログには表示しない)
    if ([level isEqualToString:kLogLevel_Fatal] ||
        [level isEqualToString:kLogLevel_Error] ||
        [level isEqualToString:kLogLevel_Warn]  ||
        [level isEqualToString:kLogLevel_Info] ) {
        [_logTextView setEditable:YES];
        [_logTextView setSelectedRange: NSMakeRange(-1, 0)]; // 文末を選択
        [_logTextView insertText:logMessage replacementRange:NSMakeRange(-1, 0)];    // 末尾にログを追加
        [_logTextView setEditable:NO];
    }

    // ログファイルの更新
    if (![self updateLogFileWithMessage:logMessage]) {
        NSString *message = @"ログの出力時にエラーが発生しました。";
        NSMutableString *logMessage = [NSMutableString stringWithFormat:@"%@ %@ %@\r\n", kLogLevel_Error, logDateStr, message];
        [_logTextView setEditable:YES];
        [_logTextView setSelectedRange: NSMakeRange(-1, 0)]; // 文末を選択
        [_logTextView insertText:logMessage replacementRange:NSMakeRange(-1, 0)];    // 末尾にログを追加
        [_logTextView setEditable:NO];
    }
}

로그 파일 업데이트



기존 로그 파일의 내용을 읽고 텍스트를 추가하여 덮어쓰기 저장을 수행합니다.
/**
 @brief ログファイルの更新を行う
 @param addedMessage ログに追加する文字列
 */
- (BOOL)updateLogFileWithMessage:(NSString *)addedMessage {
    // appと同じ場所にログファイルを書き出す
    NSURL   *bundleURL  = [NSURL fileURLWithPath:[NSBundle.mainBundle.bundlePath stringByDeletingLastPathComponent]];
    NSURL   *logFileURL = [bundleURL URLByAppendingPathComponent:kLogFileName];
    NSError *error      = nil;

    NSString *newLogMessage = [NSString string];   // 更新後のログメッセージ

    // 既存のログファイル読み込み
    NSString *oldLogMessage = [[NSString alloc] initWithContentsOfURL:logFileURL
                                                             encoding:NSUTF8StringEncoding
                                                                error:&error];
    if (oldLogMessage.length == 0) {
        newLogMessage = [NSString stringWithString:addedMessage];
    } else {
        newLogMessage = [oldLogMessage stringByAppendingString:addedMessage];
    }
    // 外部ログファイルに出力
    if (![newLogMessage writeToURL:logFileURL
                         atomically:YES
                           encoding:NSUTF8StringEncoding
                              error:&error]) {
        NSLog(@"%@", error.localizedDescription);
        return NO;
    }
    return YES;
}

출력되는 로그
[INFO]  Mar 20, 2019 20:14:14 ---------------------------------------
[INFO]  Mar 20, 2019 20:14:14 *** アプリケーションが起動しました ***
[FATAL] Mar 20, 2019 20:14:18 Operationが実行されました。
[ERROR] Mar 20, 2019 20:14:19 Operationが実行されました。
[WARN]  Mar 20, 2019 20:14:20 Operationが実行されました。
[INFO]  Mar 20, 2019 20:14:21 Operationが実行されました。
[DEBUG] Mar 20, 2019 20:14:22 Operationが実行されました。
[TRACE] Mar 20, 2019 20:14:23 Operationが実行されました。
[ERROR] Mar 20, 2019 20:14:23 Operationを実行します。
                              長いログが出力されています…
                              長いログが出力されています…
                              長いログが出力されています…
                              Operationが終了しました。
[INFO]  Mar 20, 2019 20:14:25 *** アプリケーションを終了します… ***

좋은 웹페이지 즐겨찾기