web-dev-qa-db-ja.com

本番コードでNSLog()を使用すべきではないのは本当ですか?

私はこのサイトでこれを数回言われましたが、実際にそうであることを確認したかったのです。

私はコード全体にNSLog関数呼び出しを振りかけることができ、Xcode/gccはリリース/配布ビルドを構築するときにそれらの呼び出しを自動的に削除することを期待していました。

これの使用を避けるべきですか?もしそうなら、経験豊富なObjective-Cプログラマーの間で最も一般的な選択肢は何ですか?

153
jpm

プリプロセッサマクロは、デバッグに最適です。 NSLog()には何の問題もありませんが、より優れた機能を備えた独自のロギング関数を定義するのは簡単です。私が使用しているものは次のとおりです。ログステートメントを追跡しやすくするために、ファイル名と行番号が含まれています。

#define DEBUG_MODE

#ifdef DEBUG_MODE
    #define DebugLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
    #define DebugLog( s, ... ) 
#endif

このステートメント全体を、独自のファイルよりもプレフィックスヘッダーに入れる方が簡単だとわかりました。必要に応じて、DebugLogを通常のObjective-Cオブジェクトと対話させることにより、より複雑なログシステムを構築できます。たとえば、独自のログファイル(またはデータベース)に書き込み、実行時に設定できる 'priority'引数を含むロギングクラスを作成できます。そのため、リリースバージョンではデバッグメッセージは表示されませんが、エラーメッセージは(これを行うと、DebugLog()、WarningLog()などを作成できます。

ああ、#define DEBUG_MODEはアプリケーションのさまざまな場所で再利用できることに注意してください。たとえば、私のアプリケーションでは、これを使用してライセンスキーのチェックを無効にし、特定の日付より前の場合にのみアプリケーションの実行を許可します。これにより、時間の制限があり、完全に機能するベータコピーを最小限の労力で配布できます。

196

この3行を-prefix.pchファイルの最後に追加します。

#ifndef DEBUG
  #define NSLog(...) /* suppress NSLog when in release mode */
#endif

DEBUGはプロジェクトの作成時にデフォルトでビルド設定で定義されるため、プロジェクトに何も定義する必要はありません。

77
roel

NSLog呼び出しは本番コードに残すことができますが、本当に例外的な場合、またはシステムログに記録されることが望ましい情報のためにのみ存在する必要があります。

システムログを散らかすアプリケーションは迷惑であり、専門家ではないものとして出くわします。

25

Marc Charbonneauの答え にコメントすることはできませんので、これを回答として投稿します。

マクロをプリコンパイル済みヘッダーに追加することに加えて、ターゲットビルド構成を使用して、DEBUG_MODEの定義(または定義の欠如)を制御できます。

Debug」アクティブ構成を選択すると、DEBUG_MODEが定義され、マクロは完全なNSLog定義に展開されます。

Release」アクティブ構成を選択しても、DEBUG_MODEは定義されず、NSLoggingはリリースビルドから省略されます。

手順:

  • ターゲット>情報を取得
  • ビルドタブ
  • 「プリプロセッサマクロ」を検索します(またはGCC_PREPROCESSOR_DEFINITIONS
  • 構成の選択:Debug
  • このレベルで定義を編集
  • 追加DEBUG_MODE=1
  • 構成の選択:Release
  • _DEBUG_MODEGCC_PREPROCESSOR_DEFINITIONSが設定されていないことを確認します

定義で「=」文字を省略すると、プリプロセッサからエラーが発生します

また、DEBUG_MACRO定義がどこから来たかを思い出させるために、このコメント(下に表示)をマクロ定義の上に貼り付けます。

// Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS
// Configuration = Release: <empty>
//               = Debug:   DEBUG_MODE=1
23
ohhorob

編集: メソッドMarc Charbonnea によって投稿し、 sho によって私の注意を引いたが、これよりもはるかに優れています。

デバッグモードが無効になっている場合に空の関数を使用してログを無効にすることを提案した回答の一部を削除しました。自動プリプロセッサマクロの設定を扱う部分は依然として関連しているため、そのまま残ります。また、プリプロセッサマクロの名前を編集して、Marc Charbonneauの答えに合うようにしました。


Xcodeで自動(および予想される)動作を実現するには:

プロジェクト設定で、「ビルド」タブに移動し、「デバッグ」構成を選択します。 「プリプロセッサマクロ」セクションを探し、DEBUG_MODEという名前のマクロを追加します。

...

編集: DEBUG_MODEマクロを使用してロギングを有効または無効にする適切な方法については、 Marc Charbonneauの答え を参照してください。

11
e.James

私はマシューに同意します。本番コードのNSLogには何の問題もありません。実際、ユーザーにとって有用な場合があります。ただし、NSLogを使用している唯一の理由がデバッグを支援することである場合は、はい、リリースする前に削除する必要があります。

さらに、これをiPhoneの質問としてタグ付けしたため、NSLogはリソースを使用しますが、これはiPhoneにはほとんどありません。 NSLogging anythingをiPhoneで使用している場合、アプリのプロセッサ時間がかかります。賢く使用してください。

7
August

簡単な真実は、NSLogが非常に遅いということです。

しかし、なぜ?その質問に答えるために、NSLogが何をするのか、そしてそれがどのようにそれを行うのかを見てみましょう。

NSLogは正確に何をしますか?

NSLogは2つのことを行います:

ログメッセージをApple System Logging(asl)機能に書き込みます。これにより、ログメッセージがConsole.appに表示されます。また、アプリケーションのstderrストリームが端末に送信されるかどうかを確認します。 (アプリケーションがXcode経由で実行されている場合など。)その場合、ログメッセージがstderrに書き込まれます(Xcodeコンソールに表示されるように)。

STDERRへの書き込みは難しくありません。これは、fprintfとstderrファイル記述子リファレンスを使用して実現できます。しかし、ASLはどうですか?

ASLについて私が見つけた最高のドキュメントは、Peter Hoseyの10部構成のブログ投稿です。 link

あまり詳しく説明しなくても、ハイライトは(パフォーマンスに関係するため)これです。

ASL機能にログメッセージを送信するには、基本的にASLデーモンへのクライアント接続を開き、メッセージを送信します。ただし、各スレッドは個別のクライアント接続を使用する必要があります。したがって、スレッドセーフにするために、NSLogが呼び出されるたびに、新しいaslクライアント接続を開き、メッセージを送信してから接続を閉じます。

リソースが見つかりました herehere

4
Andrew

セキュリティの観点からは、何が記録されているかに依存します。 NSLog(または他のロガー)が機密情報を書き込んでいる場合、プロダクションコードでロガーを削除する必要があります。

監査の観点から見ると、監査人はNSLogを使用するたびに、機密情報を記録しないことを確認したくありません。彼/彼女はロガーを削除するように単にあなたに言うでしょう。

私は両方のグループで働いています。コードを監査し、コーディングガイドを作成します。このガイドでは、プロダクションコードでロギングを無効にする必要があります。したがって、内部チームはそれを試さないことを知っています;)

また、機密情報が誤って漏洩することに関連するリスクを受け入れたくないため、実稼働環境でログインする外部アプリも拒否します。開発者が何を言っているかは気にしません。調査するだけの価値はありません。

そして、覚えておいてください、私たちは開発者ではなく「機密」を定義しています;)

また、大量のロギングを実行するアプリは、爆発する準備ができているアプリだと考えています。これほど多くのロギングが実行/必要とされる理由があり、通常は安定性がありません。ハングしたサービスを再起動する「ウォッチドッグ」スレッドがあります。

セキュリティアーキテクチャ(SecArch)のレビューを一度も行ったことがない場合、これらは私たちが見ているようなものです。

2
jww

他の回答で述べたように、#defineを使用して、コンパイル時にNSLogを使用するかどうかを変更できます。

ただし、より柔軟な方法は、 Cocoa Lumberjack などのロギングライブラリを使用することです。これにより、実行時に何かを記録するかどうかも変更できます。

コードでNSLogをDDLogVerboseまたはDDLogErrorなどに置き換え、マクロ定義などに#importを追加し、多くの場合applicationDidFinishLaunchingメソッドでロガーをセットアップします。

NSLogと同じ効果を得るには、構成コードは

[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];
2
Mark

NSLogsはUI /メインスレッドの速度を低下させる可能性があることに注意してください。どうしても必要な場合を除き、リリースビルドからそれらを削除するのが最善です。

1
psy

リリースコードでprintfまたはNSLogを不必要に冗長にしないでください。アプリに何か悪いことが起こった場合にのみprintfまたはNSLogを実行してみてください、I.E。回復不能なエラー。

1
MaddTheSane

ロギングにTestFlightを使用することを強くお勧めします(無料)。 NSLogのメソッドは(マクロを使用して)NSLogをオーバーライドし、NSLogへのすべての既存の呼び出しに対して、サーバー、Appleシステムログ、およびSTDERRログへのログのオン/オフを許可します。これの良いところは、テスターに​​デプロイされたアプリとApp Storeにデプロイされたアプリのログメッセージを、ユーザーのシステムログに表示せずに確認できることです。両方の長所。

0
Joel