概要
以前、OSLogの記事を書きましたが、こちらの記事で記述した方法だとログ本体にログレベルが付与されないため、ログを分析する基盤に送付したとしても分析することが難しいという点に気付きました。
当記事では、
- OSLogを使用して取得したログにログレベルを自動で付与する
- OSLogStoreでそれらのログを取得するときにログレベルが付与されたログのみを抽出する
という内容について解説します。
詳細
OSLogを使用して取得したログにログレベルを自動で付与する
OSLogにはTrace,Debug,Info,Notice,Warning,Error,Critical,Fault
の8種類のログがあるので、それぞれのログに自動的にログレベルを付与するために、こちらの方の記事を参考にして、以下のようなextensionを作成しました。
extension Logger {
static var level = OSLogType.info
init(label: String) {
self.init(subsystem: "", category: label)
}
func trace(
_ message: String = "", function: String = #function, line: Int = #line,
file: String = #file
) {
self.log(level: .debug, "[TRACE][\(file):\(function):\(line)] \(message)")
}
func debug(
_ message: String = "", function: String = #function, line: Int = #line,
file: String = #file
) {
self.log(level: .debug, "[DEBUG][\(file):\(function):\(line)] \(message)")
}
func info(
_ message: String = "", function: String = #function, line: Int = #line,
file: String = #file
) {
self.log(level: .info, "[INFO][\(file):\(function):\(line)] \(message)")
}
func notice(
_ message: String = "", function: String = #function, line: Int = #line,
file: String = #file
) {
self.log(level: .debug, "[NOTICE][\(file):\(function):\(line)] \(message)")
}
func warning(
_ message: String = "", function: String = #function, line: Int = #line,
file: String = #file
) {
self.log(level: .error, "[WARNING][\(file):\(function):\(line)] \(message)")
}
func error(
_ message: String = "", function: String = #function, line: Int = #line,
file: String = #file
) {
self.log(level: .error, "[ERROR][\(file):\(function):\(line)] \(message)")
}
func critical(
_ message: String = "", function: String = #function, line: Int = #line,
file: String = #file
) {
self.log(level: .fault, "[CRITICAL][\(file):\(function):\(line)] \(message)")
}
func fault(
_ message: String = "", function: String = #function, line: Int = #line,
file: String = #file
) {
self.log(level: .fault, "[FAULT][\(file):\(function):\(line)] \(message)")
}
}
このextensionにより、自動的にログレベル
、呼び出し元の関数
、呼び出し元の関数のファイル内の行
が自動でログに付与されるようになります。
実例として、SwiftUIのボタンをタップしたときに全ての種類のログが実行されるようにしてみます。
Button("ログ出力") {
AppLogger.shared.logger.trace("trace:\(Date())")
AppLogger.shared.logger.debug("debug:\(Date())")
AppLogger.shared.logger.info("info:\(Date())")
AppLogger.shared.logger.notice("notice:\(Date())")
AppLogger.shared.logger.warning("warning:\(Date())")
AppLogger.shared.logger.error("error:\(Date())")
AppLogger.shared.logger.critical("critical:\(Date())")
AppLogger.shared.logger.fault("fault:\(Date())")
}
このボタンをタップすると、以下のような形式でログが出力されます。
[TRACE][...ContentView.swift:body:25] trace:2024-01-24 08:55:24 +0000
[DEBUG][...ContentView.swift:body:25] debug:2024-01-24 08:55:24 +0000
[INFO][...ContentView.swift:body:26] info:2024-01-24 08:55:24 +0000
[NOTICE][...ContentView.swift:body:27] notice:2024-01-24 08:55:24 +0000
[WARNING][...ContentView.swift:body:28] warning:2024-01-24 08:55:24 +0000
[ERROR][...ContentView.swift:body:29] error:2024-01-24 08:55:24 +0000
[CRITICAL][...ContentView.swift:body:30] critical:2024-01-24 08:55:24 +0000
[FAULT][...ContentView.swift:body:31] fault:2024-01-24 08:55:24 +0000
これで目的だったログレベルが自動で付与されるようになりました。
OSLogStoreでそれらのログを取得するときにログレベルが付与されたログのみを抽出する
次に、抽出処理です。
先述のログを外部のログ分析基盤(Cloudwatch Logsなど)に送付する場合、OSLogStoreを使用することになると思いますが、こちらの記事で解説している通り、OSLogStoreで蓄積されたログを取得すると、iPhone本体のログなどが混ざるため、送付するログとしては適切ではありません。
そこで、ログレベルが付与されているログだけを抽出するために以下のような関数を用意しました。
func exportLog(startDate: Date, userName: String) async {
do {
let store = try OSLogStore(scope: .currentProcessIdentifier)
let logLevels = [
"[INFO]", "[TRACE]", "[DEBUG]", "[WARNING]", "[ERROR]",
"[CRITICAL]", "[FAULT]",
]
let position = store.position(date: startDate)
let enumerator = try store.__entriesEnumerator(
options: [.reverse], position: position, predicate: nil)
enumerator.forEach { element in
if let logEntry = element as? OSLogEntry {
let message = logEntry.composedMessage
for logLevel in logLevels {
if message.starts(with: logLevel) {
logMessages += message + "\n"
}
}
}
}
// ここに送信処理を実装
} catch {
print("Error exporting logs: \(error)")
}
}
この関数を使用することによって、OSLogのログの内、ログレベルが埋め込まれているログのみを抽出することが可能です。
...
CF Read: domain = com.apple.Accessibility, preference = SpeechSettingsDisabledByManagedConfiguration, appID = (null) result = (null) (-1 - empty, 0 - false, 1 - true)
CF Read: domain = com.apple.Accessibility, preference = QuickSpeak, appID = (null) result = (null) (-1 - empty, 0 - false, 1 - true)
Evaluating dispatch of UIEvent: 0x600003914000; type: 0; subtype: 0; backing type: 11; shouldSend: 1; ignoreInteractionEvents: 0, systemGestureStateChange: 0
Sending UIEvent type: 0; subtype: 0; to windows: 1
Sending UIEvent type: 0; subtype: 0; to window: <UIWindow: 0x108214410>; contextId: 0xF00E590D
Evaluating dispatch of UIEvent: 0x600003914000; type: 0; subtype: 0; backing type: 11; shouldSend: 0; ignoreInteractionEvents: 0, systemGestureStateChange: 1
Evaluating dispatch of UIEvent: 0x600003914000; type: 0; subtype: 0; backing type: 11; shouldSend: 1; ignoreInteractionEvents: 0, systemGestureStateChange: 0
Sending UIEvent type: 0; subtype: 0; to windows: 1
Sending UIEvent type: 0; subtype: 0; to window: <UIWindow: 0x108214410>; contextId: 0xF00E590D
[TRACE][body:24] trace:2024-01-23 10:03:26 +0000
[DEBUG][body:25] debug:2024-01-23 10:03:26 +0000
[INFO][body:26] info:2024-01-23 10:03:26 +0000
[NOTICE][body:27] notice:2024-01-23 10:03:26 +0000
[WARNING][body:28] warning:2024-01-23 10:03:26 +0000
[ERROR][body:29] error:2024-01-23 10:03:26 +0000
[CRITICAL][body:30] critical:2024-01-23 10:03:26 +0000
[FAULT][body:31] fault:2024-01-23 10:03:26 +0000
....
[TRACE][...ContentView.swift:body:25] trace:2024-01-24 08:55:24 +0000
[DEBUG][...ContentView.swift:body:25] debug:2024-01-24 08:55:24 +0000
[INFO][...ContentView.swift:body:26] info:2024-01-24 08:55:24 +0000
[NOTICE][...ContentView.swift:body:27] notice:2024-01-24 08:55:24 +0000
[WARNING][...ContentView.swift:body:28] warning:2024-01-24 08:55:24 +0000
[ERROR][...ContentView.swift:body:29] error:2024-01-24 08:55:24 +0000
[CRITICAL][...ContentView.swift:body:30] critical:2024-01-24 08:55:24 +0000
[FAULT][...ContentView.swift:body:31] fault:2024-01-24 08:55:24 +0000
以上です。