iOSアプリ開発でログにログレベルを導入する方法

iOSアプリ開発でログを出力する場合「NSLog」を使用するが、Javaでログ出力に用いられるLog4Jのログレベルの様な考え方は存在しない。
今回はiOSアプリ開発でログにログレベルを導入する方法を紹介する。

<捕捉>
Log4Jのログレベルは、設定値によって出力するログを制御する方式である。
例えば、エラーより深刻なログを出力する設定にした場合、デバッグのために出力するログは出力されない仕組みである。
ログレベルの設定は、設定ファイルで簡単に変更することができ、単体テスト時は全てのログを出力し、結合テストの時は警告以上のログを出力し、サービスイン後はエラー以上のログを出力するといった制御が行える。

<方法概要>
1.PCHファイルにログレベルを定義する
2.PCHファイルに採用するログレベル定義する
3.PCHファイルにログレベル毎のログ出力を定義する

(注意)
PCHファイルはXcode6から自動で生成されなくなった。
手動で作成する方法は「Xcode6でPCHファイルを追加する方法」を参照のこと。

説明を簡単にするため、今回設定するログレベルは、下記の3レベルとする。


ログレベル説明
ログ無しログを出力しない
エラーエラー情報を出力する
デバッグデバッグ情報を出力する

<方法詳細>
1.PCHファイルにログレベルを定義する

<プロジェクト名>-Prefix.pchファイルにログレベルを定義する。
数値に意味は無く、他のログレベルと異なるのであれば、任意で良い。

//ログレベル定義
#define VAL_LOG_NONE    0       //ログ無し
#define VAL_LOG_ERROR   1       //エラー
#define VAL_LOG_DEBUG   2       //デバッグ


2.PCHファイルに採用するログレベル定義する

<プロジェクト名>-Prefix.pchファイルに採用するログレベル定義する。
「DEF_LOG_LEVEL」の右に手順1で定義したログレベルを記述することで、アプリが動作する時に採用するログレベルを定義する。
(下記の例はログレベル「エラー」を設定している)

//ログレベル設定
#define DEF_LOG_LEVEL VAL_LOG_ERROR


3.PCHファイルにログレベル毎のログ出力を定義する

<プロジェクト名>-Prefix.pchファイルにログレベル毎のログ出力を定義する。
マクロのif文で、手順2で設定した採用ログレベルにより、ログ出力の有無を定義する。
デバッグレベルで出力したいログ出力のために識別子「LogD」を定義し、エラーレベルで出力したいログ出力のために識別子「LogE」を定義する。

#if DEF_LOG_LEVEL == VAL_LOG_DEBUG      //↓↓↓ ログレベルが「デバッグ」の場合の定義

    #define LogD(format, ...) NSLog((@"<D>: "format), ##__VA_ARGS__)    //※1
    #define LogE(format, ...) NSLog((@"<E>: "format), ##__VA_ARGS__)    //※2

#elif DEF_LOG_LEVEL == VAL_LOG_ERROR   //↓↓↓ ログレベルが「エラー」の場合の定義

    #define LogD(format, ...)                                           //※3
    #define LogE(format, ...) NSLog((@"<E>: "format), ##__VA_ARGS__)    //※4

#elif DEF_LOG_LEVEL == VAL_LOG_NONE   //↓↓↓ ログレベルが「ログ無し」の場合の定義

    #define LogD(format, ...)                                           //※5
    #define LogE(format, ...)                                           //※6

#endif

※1:「LogD」という識別子を通常の「NSLog」出力に「」を付加して出力する
※2:「LogE」という識別子を通常の「NSLog」出力に「」を付加して出力する
※3:「LogD」という識別子は無視する
※4:「LogE」という識別子を通常の「NSLog」出力に「」を付加して出力する
※5:「LogD」という識別子は無視する
※6:「LogE」という識別子は無視する


自動生成されたPCHファイルか否かで、冒頭部分が異なる。
例は手動で生成したPCHファイルである。

#ifndef LogSample_LogSample_Prefix_pch
#define LogSample_LogSample_Prefix_pch

//ログレベル定義
#define VAL_LOG_NONE    0       //ログ無し
#define VAL_LOG_ERROR   1       //エラー
#define VAL_LOG_DEBUG   2       //デバッグ

//ログレベル設定
#define DEF_LOG_LEVEL VAL_LOG_ERROR

#if DEF_LOG_LEVEL == VAL_LOG_DEBUG      //↓↓↓ ログレベルが「デバッグ」の場合の定義

    #define LogD(format, ...) NSLog((@"<D>: "format), ##__VA_ARGS__)    //※1
    #define LogE(format, ...) NSLog((@"<E>: "format), ##__VA_ARGS__)    //※2

#elif DEF_LOG_LEVEL == VAL_LOG_ERROR   //↓↓↓ ログレベルが「エラー」の場合の定義

    #define LogD(format, ...)                                           //※3
    #define LogE(format, ...) NSLog((@"<E>: "format), ##__VA_ARGS__)    //※4

#elif DEF_LOG_LEVEL == VAL_LOG_NONE   //↓↓↓ ログレベルが「ログ無し」の場合の定義

    #define LogD(format, ...)                                           //※5
    #define LogE(format, ...)                                           //※6

#endif
#endif

<使用方法>
ログを出力する際は、「NSLog」ではなく、「LogD」および「LogE」を使用する。
サンプルコードを下記に示す。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    LogD(@"デバッグレベルのログ");
    
    LogE(@"エラーレベルのログ");
    
    NSLog(@"NSLogによる出力");
}

<出力結果>
「#define DEF_LOG_LEVEL VAL_LOG_DEBUG」と設定した場合

2014-12-01 20:48:28.543 LogSample[4775:32404] <D>: デバッグレベルのログ
2014-12-01 20:48:28.544 LogSample[4775:32404] <E>: エラーレベルのログ
2014-12-01 20:48:28.545 LogSample[4775:32404] NSLogによる出力

「#define DEF_LOG_LEVEL VAL_LOG_ERROR」と設定した場合

2014-12-01 20:49:35.280 LogSample[4861:32974] <E>: エラーレベルのログ
2014-12-01 20:49:35.281 LogSample[4861:32974] NSLogによる出力

ソースコードを変更せずに、PCHファイルの変更で、デバッグレベルのログが出力されなくなった。

「#define DEF_LOG_LEVEL VAL_LOG_NONE」と設定した場合

2014-12-01 20:51:42.142 LogSample[4991:33935] NSLogによる出力

ソースコードを変更せずに、PCHファイルの変更で、デバッグレベル・エラーレベルのログが出力されなくなった。

<考察>
実用レベルのiOSアプリを作成する場合、ログ出力のためのコードが大量になることが少なくない。
リリース時に全てログ出力用のコードを削除しても良いが、アプリにトラブルが発生した時に原因調査に再びログ出力用コードを記述することになる。
今回紹介した方法を使用すれば、簡単にログ出力量を制御することができる。

Enjoy Programing!!

<関連記事>
iOSアプリ開発でログにクラス名とメソッド名を出力する方法
iOSアプリ開発でログにログレベルを導入する方法(本記事)
iOSアプリ開発でNSErrorの情報を出力する拡張NSLogを定義する方法

<お勧め書籍>

詳解 Objective-C 2.0 第3版
iOSアプリ開発技術者として仕事をするのであれば、必ず読んでおくべき書籍である。
筆者も何度も繰り返し精読している。