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


155

私はこのサイトでこれを何度か言われましたが、私はこれが本当にそうであることを確認したかったのです。

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

これは使用しないでください。もしそうなら、経験豊富なObjective-Cプログラマの間で最も一般的な代替手段は何ですか?


7
私はこの質問が非常に古いことを知っていますが、それでも可能であれば、マークシャルボノーの回答を承認済みとしてマークします。私は彼を指すように私の答えを変更しましたが、彼の答えは正しいものです。
e.James、2009年

5
頻繁なループの内側のNSLog()は、あなたのパフォーマンスを完全に殺します、と彼は難しい方法を見つけたと言いました。
willc2 2009

回答:


197

プリプロセッサマクロは確かにデバッグに最適です。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てください。アプリケーションのさまざまな場所で再利用できます。たとえば、私のアプリケーションでは、それを使用してライセンスキーチェックを無効にし、特定の日付より前の場合にのみアプリケーションを実行できるようにします。これにより、期間限定の完全に機能するベータ版コピーを、最小限の労力で配布できます。


8
優れた答えを得るには+1。私はあなたの#defineマクロが進むべき道であることを示すために私を変更しました、そして私はOPが受け入れられた答えを切り替えることを望みます(私は彼にコメントを残しました)。マクロで...引数を使用できることを知らなかったので、ダミー関数を使用していました。生きて学ぶ!
e.James、2009年

15
優れた回答ですが、「JPM_DEBUG」などのように、「DEBUG_MODE」定義に個人的なプレフィックスを使用することをお勧めします。DEBUGやDEBUG_MODEなどを使用するサードパーティのコードに遭遇することが多すぎ、そのコードがDEBUGモードで正しく機能しない場合があります。サードパーティライブラリのデバッグをオンにする場合は、意図的に行う必要があります。(もちろん、シンボルのプレフィックスを付ける必要があるのはライブラリライターですが、多くのCおよびC ++フレームワークは、特にこの定義ではプレフィックスを付けません)。
Rob Napier、

1
構成がデバッグに設定されている場合にのみこれをオンにするために使用できるXcode定義済みマクロはありますか?すべてのプロジェクトで、このプリプロセッサマクロを自分で手動で設定したくありません。疑似コード#if XCODE_CONFIGURATION == DEBUGのようなことはできますか?
frankodwyer 2009年

1
#include <TargetConditionals.h>
slf

2
この方法では、ロギングステートメントがログに記録する値を計算する目的でのみ中間変数を使用する場合、リリースモードのコンパイラから誤った「未使用の変数」警告が表示されます。あなたが私と同じくらいコンパイラの警告を嫌うなら、それを避ける最も賢い方法は何でしょうか?
Jean-Denis Muys

78

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

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

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


2
最高のソリューションです。あなたはXCodeの6からprefix.pch手動で追加する必要があり
テディ

それでも、リリース前にビルド設定を変更する必要があります。つまり、デバッグからリリースへ
UserDev

25

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

システムログを散らかすアプリケーションは煩わしく、専門家ではないように出くわします。


14
申し訳ありませんが、誰にとっても専門家ではない人に遭遇しましたか?リリースされたアプリでログを確認し、それに基づいてプロフェッショナリズムを判断する可能性があるのは誰ですか?(明確にするために、アプリケーションのリリースバージョンでは大量のNSLogを保持するべきではないことに完全に同意しますが、「プロフェッショナリズム」の議論には混乱しています。)
WendiKidd

4
他の開発者はあなたがしていることをしてイライラします。Androidにも同様の問題があり、一部の開発者は非常に悪いplus.google.com/110166527124367568225/posts/h4jK38n4XYR
Roger Binns

24

マークシャルボノーの回答にはコメントできないので、回答として投稿します。

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

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

リリース」のアクティブ構成をも定義は行われず、リリースビルドからギングは省略されDEBUG_MODEますNSLog

手順:

  • ターゲット>情報を取得
  • ビルドタブ
  • 「PreProcessor Macros」(または GCC_PREPROCESSOR_DEFINITIONS)を
  • 構成を選択: デバッグ
  • このレベルで定義を編集
  • 追加 DEBUG_MODE=1
  • 構成の選択:リリース
  • 確認DEBUG_MODEが設定されていませんGCC_PREPROCESSOR_DEFINITIONS

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

また、このコメント(下に表示)をマクロ定義の上に貼り付けて、DEBUG_MACRO定義がどこから来たかを通知します;)

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

1
これは、質問に対する貴重な追加回答です。コメント以上のものに値する。
モーニングスター

DEBUG_MODEそしてDEBUG_MACRO、型破りです。DEBUG_MACROアップルのサイト(opensource.apple.com/source/gm4/gm4-15/src/m4.h?txt)で参照しているのは1つだけです。おそらくより標準的でDEBUGNDEBUGより良い選択でしょうか?NDEBUGPosixによって指定されています。while DEBUGは慣例により使用されます。
jww

+1はい、これは古い投稿ですが、それがポイントです... Xcodeの私のバージョン(4年後)では、GCC_PREPROCESSOR_DEFINITIONSを検索すると、いくつかの異なる言語が返されます。明確にするために、この優れた回答の更新を検討してください。
David

11

EDIT:この方法は、によって投稿マルクCharbonneau、およびによって私の注意に持って来ら、はるかに優れたこの1を超えています。

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


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

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

...

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


7

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

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


4

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

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

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

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

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

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

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

詳細には触れませんが、ハイライト(パフォーマンスに関する)は次のとおりです。

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

リソースはここここにあります


テキストを編集しました。リソースはフッターにある必要があるだけです。
Johan Karlsson 2013年

2

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

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

コードでNSLogをDDLogVerboseやDDLogErrorなどで置き換え、マクロ定義などの#importを追加して、多くの場合applicationDidFinishLaunchingメソッドでロガーを設定します。

NSLogと同じ効果を持つために、構成コードは

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

2

セキュリティの観点からは、何がログに記録されているかによって異なります。もしNSLog、機密情報を書き込んでいる(または他のロガー)、そして本番コードでロガーを削除する必要があります。

監査の観点から、監査人は、 NSLog機密情報がログに記録されないことを確認するためにのを確認する必要はありません。彼/彼女はロガーを取り除くようにあなたに単に言うでしょう。

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

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

そして、開発者ではなく「機密」を定義することを忘れないでください;)

また、大量のロギングを実行するアプリを、内破可能なアプリとして認識しています。多くのロギングが実行/必要とされる理由があり、通常は安定性がありません。そのすぐ上に、ハングしたサービスを再開する「ウォッチドッグ」スレッドがあります。

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


1

リリースコードのprintfやNSLogを不必要に冗長にするべきではありません。アプリに何か問題が発生した場合にのみ、printfまたはNSLogを実行してみてください。IEは回復不可能なエラーです。


1

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


0

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


TestFlightがアプリケーションに追加するオーバーヘッドを考慮する必要があります。TestFlightのログ部分のみを追加することは可能ですか?
Johan Karlsson 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.