概要
ログを表示するアプリを作成しました。
右側にあるOperationボタンの操作を行うと、ボタンの文字に合わせたログが表示されます。
(実際はプログラム処理の結果をログで表示するために使用します。)
押下したOperationボタンに応じてUI上にログを表示します。
※[DEBUG]``[TRACE]
に関してはログファイルにのみ表示します。(ユーザに知らせる必要のない情報のため)
また同時にappと同じ場所にログファイルを書き出しています。
GitHub
実装-UI部分
ペタペタと部品を貼り付けます。
今回ログの表示には以下の「Text View」(NSScrollView)を使用します。
ログの見た目を揃えるため、フォントは等幅フォントを使用します。
今回はFamily名をOsakaに設定、Styleを等幅とします。
また右側のOperationの文字の下に並んでいるのは、NSButton
のMatrixです。
以下の通りIBAction
を使って押下されたボタンを取得します。
// 画面右のOperationボタンが押下された場合
- (IBAction)operationButtonPush:(NSMatrix *)sender {
int selectedRow = (int)sender.selectedRow;
...
}
実装-プログラム部分
コードの先頭で必要な変数をローカル変数として定義しています。
ログレベルに関しては、以下の記事を参考にしました。
ログ設計指針
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 *** アプリケーションを終了します… ***