目次

目次

【Swift】 OSLogを使ったログ出力

アバター画像
神山義仁
アバター画像
神山義仁
最終更新日2022/07/25 投稿日2022/07/25

はじめに

こんにちは。iOSアプリ開発グループの神山です。

開発時にログを出したい際に、 print()を使用したり、SwiftBeaverなどのライブラリを使用したり様々な方法があると思います。

今回はiOS14以降で使用できるLoggerも含めて、OSLogを使ってログを出力する方法をご紹介したいと思います。

OSLogでのログ出力

ログを出力する際には os_logを使いやすいように拡張して、以下のようなものを作成していました。

import OSLog

extension OSLog {
    static let ui = OSLog(subsystem: "com.sample", category: "UI")
    static let api = OSLog(subsystem: "com.sample", category: "API")
    static let other = OSLog(subsystem: "com.sample", category: "OTHER")
}

extension OSLogType: CustomStringConvertible {
    public var description: String {
        switch self {
        case .info:
            return "INFO"

        case .debug:
            return "DEBUG"

        case .error:
            return "ERROR"

        case .fault:
            return "FAULT"

        default:
            return "DEFAULT"
        }
    }
}

struct Logger {
    static func info(
        osLog: OSLog = .default,
        message: String,
        file: String = #file,
        function: String = #function,
        line: Int = #line
    ) {
        doLog(
            message: message,
            osLog: osLog,
            logType: .info,
            file: file,
            function: function,
            line: line
        )
    }

    static func debug(
        osLog: OSLog = .default,
        message: String,
        file: String = #file,
        function: String = #function,
        line: Int = #line
    ) {
        doLog(
            message: message,
            osLog: osLog,
            logType: .debug,
            file: file,
            function: function,
            line: line
        )
    }

    static func error(
        osLog: OSLog = .default,
        message: String,
        file: String = #file,
        function: String = #function,
        line: Int = #line
    ) {
        doLog(
            message: message,
            osLog: osLog,
            logType: .error,
            file: file,
            function: function,
            line: line
        )
    }

    static func fault(
        osLog: OSLog = .default,
        message: String,
        file: String = #file,
        function: String = #function,
        line: Int = #line
    ) {
        doLog(
            message: message,
            osLog: osLog,
            logType: .fault,
            file: file,
            function: function,
            line: line
        )
    }

    private static func doLog(
        message: String,
        osLog: OSLog,
        logType: OSLogType = .default,
        file: String,
        function: String,
        line: Int
    ) {
        #if DEBUG
            os_log(
                "✌️[%@] %@ %@ L:%d %@",
                log: osLog,
                type: logType,
                String(describing: logType),
                file.split(separator: "/").last! as CVarArg,
                function,
                line,
                message
            )
        #endif
    }
}

これらは以下のような形で呼び出して情報を出力することができます。

Logger.info(osLog: .ui, message: "INFOボタンを押しました") // 2022-06-16 18:57:19.370911+0900 SwiftDocument[66698:1068138] [UI] ✌️[INFO] LoggerViewController.swift tappedInfoButton() L:68 INFOボタンを押しました

Logger.debug(osLog: .api, message: "DEBUGボタンを押しました") // 2022-06-16 18:57:33.986027+0900 SwiftDocument[66698:1068138] [API] ✌️[DEBUG] LoggerViewController.swift tappedDebugButton() L:72 DEBUGボタンを押しました

Logger.error(osLog: .other, message: "ERRORボタンを押しました") // 2022-06-16 18:57:53.802459+0900 SwiftDocument[66698:1068138] [OTHER] ✌️[ERROR] LoggerViewController.swift tappedErrorButton() L:76 ERRORボタンを押しました

Logger.fault(message: "FAULTボタンを押しました") // 2022-06-16 18:58:10.936951+0900 SwiftDocument[66698:1068138] ✌️[FAULT] LoggerViewController.swift tappedFaultButton() L:80 FAULTボタンを押しました

拡張することで呼び出したファイル、関数、行数なども表示できました。

Loggerでのログ出力

iOS14以降で使用できるLoggerではより直感的に柔軟な出力をすることができます。

例えば、機密情報の場合はログに出力したくない場合もあるかと思います。デフォルトでは動的な値はprivateに設定されていますが、意図的に特定の値をコンソールに公開しないためにはコードで設定をする必要があります。

以下はLoggerとos_logのそれぞれで設定した場合の違いになります。

let privateUser = "Private User"

let log = OSLog(subsystem: "com.sample", category: "Sample")
os_log("User %{private}@ logged in", log: log, type: .info, privateUser)

let logger = Logger(subsystem: "com.sample", category: "Sample")
logger.info("User \(privateUser, privacy: .private) logged in")

このようにLoggerの方が直感的に記述できることがわかるかと思います。

ログの確認方法

Xcodeのコンソールにも出力されますが、 Console.appから確認することもできます。 上記のプライベートで設定したログがどのように表示されているか確認してみましょう。

まずコンソールアプリを開きます。

image-20220616120025602.png

使用する端末を選択し、開始ボタンを押します。

SettingConsole.png

Xcodeからアプリを起動して実際にログを送ってみます。 今回は以下のログを送ります。

let logger = Logger(subsystem: "com.sample", category: "Sample")
let privateUser = "Private User"
logger.info("User \(privateUser, privacy: .private) logged in")

コンソールを確認するとログが出力されました。

ただ、Xcodeからアプリを起動している際はログの設定をプライベートにしても情報は出力されます。

Log.png

では、Xcodeのアプリを終了してXcodeを経由せず、そのままアプリを起動してログを送ってみましょう。

LogPrivate.png

無事にプライベートの情報を表示させないようにすることができていますね。

※ Simulatorではなく実機でないとプライベートにならないのでご注意ください。

さいごに

OSLogは今回紹介したコンソールへの情報を可視させるか以外にも様々な機能が提供されています。

まだまだ調べ切れていないところが多いですが、ログはバグを発見する手がかりになったりと開発する上で非常に重要なものでもあるので今後も引き続き理解を深めていきたいと思います。

最後まで記事を読んで頂き、ありがとうございました。

参考文献

apple document(Logger)

OSLog and Unified logging as recommended by Apple

アバター画像

神山義仁

iOSエンジニアです。

目次