メソッド名と行番号を出力し、NSLogを条件付きで無効にする方法は?


446

Xcodeでのデバッグに関するプレゼンテーションを行っています。NSLogを効率的に使用するための詳細情報を入手したいと考えています。

特に、2つの質問があります。

  • 現在のメソッドの名前/行番号を簡単にNSLogする方法はありますか?
  • リリースコード用にコンパイルする前に、すべてのNSLogを簡単に「無効にする」方法はありますか?

12
お気に入り(スター)の方が賛成票が多い最初の質問... +1 ..
Fahim Parkar 14

回答:


592

以下は、私が頻繁に使用するNSLogに関する便利なマクロです。

#ifdef DEBUG
#   define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#   define DLog(...)
#endif

// ALog always displays output regardless of the DEBUG setting
#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)

DLogマクロは、DEBUG変数が設定されている場合にのみ出力に使用されます(デバッグ構成用のプロジェクトのCフラグの-DDEBUG)。

ALogは常にテキストを出力します(通常のNSLogのように)。

出力(ALog(@ "Hello world")など)は次のようになります。

-[LibraryController awakeFromNib] [Line 364] Hello world

なぜ##があるのですか?議論を結びつけるためだと思いましたが、あなたは何にも固執していません。
Casebash、2010年

1
これにより、引数がマクロ展開される可能性が
なくなり

それは一般的にマクロで起こります。一部のマクロは複数の行を生成します。常に中括弧を使用するためのもう1つの引数;-)。
diederikh 2010年

greatとcocos2d apiにも同様のログステートメントがあります。
ユン・リー

どのようにそれはそれで(@"%s [Line %d] " fmt)引き起こしfmt制御文字列に追加するには?私はこのデバッグマクロ以外にこの構文を見たことはありません。
Robert Altman、

141

私は上から取ってDLog、それを上げることALogを追加しましULogUIAlertViewたメッセージを。

要約する:

  • DLogNSLogDEBUG変数が設定されている場合のみのように出力されます
  • ALog 常に次のように出力されます NSLog
  • ULogUIAlertViewDEBUG変数が設定されている場合にのみ表示されます
#ifdef DEBUG
#define DLog(fmt、...)NSLog((@ "%s [Line%d]" fmt)、__PRETTY_FUNCTION__、__LINE__、## __ VA_ARGS__);
#そうしないと
#DLog(...)を定義
#endif
#define ALog(fmt、...)NSLog((@ "%s [Line%d]" fmt)、__PRETTY_FUNCTION__、__LINE__、## __ VA_ARGS__);
#ifdef DEBUG
#define ULog(fmt、...){UIAlertView * alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@ "%s \ n [Line%d]"、__PRETTY_FUNCTION__、__LINE__] message:[NSString stringWithFormat:fmt 、## __ VA_ARGS__] delegate:nil cancelButtonTitle:@ "Ok" otherButtonTitles:nil]; [アラートショー]; }
#そうしないと
#ULog(...)を定義
#endif

これは次のようになります。

UIAlertViewのデバッグ

+1ディーデリク


ALog + DLogコードもULogで拡張します。非常に便利。
neoneye 2011

このコードは、DEBUGで実行されていない場合、Xcode 5.1で未使用の変数エラーを引き起こします:(
yonix

#defineディレクティブの一部がセミコロンで終わるのはなぜですか?
Monstieur 2015

@Locutusしたがって、DLogステートメントの後にセミコロンを付ける必要はありません。これを行うと、リリースビルドでDLog何もコンパイルされず、コード内にぶら下がっているセミコロンが残ってしまうので便利です。これはエラーではありませんが、別のセミコロンの後に続く場合は、設定によっては警告がスローされることがあります。
Zev Eisenberg 2016年

74
NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);

ファイル名、行番号、関数名を出力します。

/proj/cocoa/cdcli/cdcli.m 121 managedObjectContext managedObjectContext

__FUNCTION__C ++ではマングルされた名前が適切__PRETTY_FUNCTION__な関数名を示し、Cocoaではそれらは同じように見えます。

NSLogを無効にする適切な方法が何であるかわかりません。

#define NSLog

また、ログ出力は表示されませんでしたが、これに副作用があるかどうかはわかりません。


20

ここでは、使用するデバッグ定数の1つの大きなコレクションを示します。楽しい。

// Uncomment the defitions to show additional info.

//  #define DEBUG

//  #define DEBUGWHERE_SHOWFULLINFO

//  #define DEBUG_SHOWLINES
//  #define DEBUG_SHOWFULLPATH
//  #define DEBUG_SHOWSEPARATORS
//  #define DEBUG_SHOWFULLINFO


// Definition of DEBUG functions. Only work if DEBUG is defined.
#ifdef DEBUG 

    #define debug_separator() NSLog( @"────────────────────────────────────────────────────────────────────────────" );

    #ifdef DEBUG_SHOWSEPARATORS
        #define debug_showSeparators() debug_separator();
    #else
        #define debug_showSeparators()
    #endif

    /// /// /// ////// ///// 

    #ifdef DEBUG_SHOWFULLPATH
        #define debug_whereFull() debug_showSeparators(); NSLog(@"Line:%d : %s : %s", __LINE__,__FILE__,__FUNCTION__); debug_showSeparators(); 
    #else
        #define debug_whereFull() debug_showSeparators(); NSLog(@"Line:%d : %s : %s", __LINE__,[ [ [ [NSString alloc] initWithBytes:__FILE__ length:strlen(__FILE__) encoding:NSUTF8StringEncoding] lastPathComponent] UTF8String ] ,__FUNCTION__); debug_showSeparators(); 
    #endif

    /// /// /// ////// ///// 

    #define debugExt(args,...) debug_separator(); debug_whereFull(); NSLog( args, ##__VA_ARGS__); debug_separator();

    /// /// /// ////// ///// Debug Print Macros

    #ifdef DEBUG_SHOWFULLINFO
        #define debug(args,...) debugExt(args, ##__VA_ARGS__);
    #else
        #ifdef DEBUG_SHOWLINES
            #define debug(args,...) debug_showSeparators(); NSLog([ NSString stringWithFormat:@"Line:%d : %@", __LINE__, args ], ##__VA_ARGS__); debug_showSeparators();
        #else
            #define debug(args,...) debug_showSeparators(); NSLog(args, ##__VA_ARGS__); debug_showSeparators();
        #endif
    #endif

    /// /// /// ////// ///// Debug Specific Types

    #define debug_object( arg ) debug( @"Object: %@", arg );
    #define debug_int( arg ) debug( @"integer: %i", arg );
    #define debug_float( arg ) debug( @"float: %f", arg );
    #define debug_rect( arg ) debug( @"CGRect ( %f, %f, %f, %f)", arg.origin.x, arg.origin.y, arg.size.width, arg.size.height );
    #define debug_point( arg ) debug( @"CGPoint ( %f, %f )", arg.x, arg.y );
    #define debug_bool( arg )   debug( @"Boolean: %@", ( arg == YES ? @"YES" : @"NO" ) );

    /// /// /// ////// ///// Debug Where Macros

    #ifdef DEBUGWHERE_SHOWFULLINFO
        #define debug_where() debug_whereFull(); 
    #else
        #define debug_where() debug(@"%s",__FUNCTION__); 
    #endif

    #define debug_where_separators() debug_separator(); debug_where(); debug_separator();

    /// /// /// ////// /////

#else
    #define debug(args,...) 
    #define debug_separator()  
    #define debug_where()   
    #define debug_where_separators()  
    #define debug_whereFull()   
    #define debugExt(args,...)
    #define debug_object( arg ) 
    #define debug_int( arg ) 
    #define debug_rect( arg )   
    #define debug_bool( arg )   
    #define debug_point( arg )
    #define debug_float( arg )
#endif

19

答えが出ない新しいトリックがあります。printf代わりに使用できますNSLog。これにより、クリーンなログが得られます。

NSLogあなたはこのようなものを取得します:

2011-11-03 13:43:55.632 myApp[3739:207] Hello Word

しかし、printfあなただけが得ます:

Hello World

このコードを使用

#ifdef DEBUG
    #define NSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
    #define NSLog(...) {}              
#endif

16

この質問への私の答えは役立つかもしれません、それはDiederikが調理したものに似ているように見えます。への呼び出しを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

あなたは避けているため%s、Appleは廃止しようとしている書式指定子と避け-Wcstring-format-directive、新たに2015年に導入されたクラン警告
ジェフ

13

MACROSにアレルギーのある人のために、すべてのNSLogを無効にするために、次のコードもコンパイルできます。

void SJLog(NSString *format,...)
{
    if(LOG)
    {   
        va_list args;
        va_start(args,format);
        NSLogv(format, args);
        va_end(args);
    }
}

そして、それをNSLogのように使用します。

SJLog(@"bye bye NSLogs !");

このブログから:https : //whackylabs.com/logging/ios/2011/01/19/ios-moving-in-and-out-of-nslogs/


11

上記の回答を補足するために、特定の状況で、特にデバッグ時に、NSLogの代わりに使用すると非常に便利です。たとえば、各行のすべての日付とプロセス名/ ID情報を取り除くと、出力が読みやすくなり、起動が速くなります。

次のリンクは、単純なロギングをより良くするためのかなりの便利な弾薬を提供します。

http://cocoaheads.byu.edu/wiki/a-different-nslog


11

既存のNSLogを変更して、呼び出し元の行番号とクラスを表示するのは簡単です。プレフィックスファイルにコードを1行追加します。

#define NSLog(__FORMAT__, ...) NSLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)

3
これは素晴らしい!これをどのように迅速に行いますか?
uplearnedu.com 2015年

@AddisDev私はこれが一番好きです。とても清潔でシンプル。NSLogのみを使用しています。とにかくDLogとULogが何であるかわかりません!ありがとう。賛成投票...
Charles Robertson

@AddisDevなぜAppleがこの極めて重要なデータをデフォルトでNSLog()に追加しないのか本当に理解していませんか?奇妙な...
チャールズロバートソン

8

それは簡単です、例えば

-(void)applicationWillEnterForeground:(UIApplication *)application {

    NSLog(@"%s", __PRETTY_FUNCTION__);

}

出力: -[AppDelegate applicationWillEnterForeground:]


5

上記の回答の上に構築して、ここに私が盗用して思いついたものがあります。メモリロギングも追加されました。

#import <mach/mach.h>

#ifdef DEBUG
#   define DebugLog(fmt, ...) NSLog((@"%s(%d) " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define DebugLog(...)
#endif


#define AlwaysLog(fmt, ...) NSLog((@"%s(%d) " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);


#ifdef DEBUG
#   define AlertLog(fmt, ...)  { \
    UIAlertView *alert = [[UIAlertView alloc] \
            initWithTitle : [NSString stringWithFormat:@"%s(Line: %d) ", __PRETTY_FUNCTION__, __LINE__]\
                  message : [NSString stringWithFormat : fmt, ##__VA_ARGS__]\
                 delegate : nil\
        cancelButtonTitle : @"Ok"\
        otherButtonTitles : nil];\
    [alert show];\
}
#else
#   define AlertLog(...)
#endif



#ifdef DEBUG
#   define DPFLog NSLog(@"%s(%d)", __PRETTY_FUNCTION__, __LINE__);//Debug Pretty Function Log
#else
#   define DPFLog
#endif


#ifdef DEBUG
#   define MemoryLog {\
    struct task_basic_info info;\
    mach_msg_type_number_t size = sizeof(info);\
    kern_return_t e = task_info(mach_task_self(),\
                                   TASK_BASIC_INFO,\
                                   (task_info_t)&info,\
                                   &size);\
    if(KERN_SUCCESS == e) {\
        NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; \
        [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; \
        DebugLog(@"%@ bytes", [formatter stringFromNumber:[NSNumber numberWithInteger:info.resident_size]]);\
    } else {\
        DebugLog(@"Error with task_info(): %s", mach_error_string(e));\
    }\
}
#else
#   define MemoryLog
#endif

4

DLogへの新しい追加。リリースされたアプリケーションからデバッグを完全に削除するのではなく、それを無効にするだけです。ユーザーがデバッグを必要とする問題を抱えている場合は、リリースされたアプリケーションでデバッグ有効にし、電子メールでログデータを要求する方法を教えてください。

ショートバージョン:グローバル変数を作成し(はい、レイジーでシンプルなソリューション)、DLogを次のように変更します。

BOOL myDebugEnabled = FALSE;
#define DLog(fmt, ...) if (myDebugEnabled) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);

Jomnius iLessons iLearnedでの長い回答:リリースされたアプリケーションで動的デバッグログを行う方法


3

しばらくの間、上記のいくつかから採用されたマクロのサイトを使用してきました。制御とフィルタリングされた冗長性に重点を置いて、コンソールでのロギングに重点を置いています。多くのログ行を気にしなくても、それらのバッチを簡単にオン/オフに切り替えたい場合は、これが便利な場合があります。

最初に、上記の@Rodrigoで説明されているように、オプションでNSLogをprintfに置き換えます

#define NSLOG_DROPCHAFF//comment out to get usual date/time ,etc:2011-11-03 13:43:55.632 myApp[3739:207] Hello Word

#ifdef NSLOG_DROPCHAFF
#define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#endif

次に、ログのオンとオフを切り替えます。

#ifdef DEBUG
#define LOG_CATEGORY_DETAIL// comment out to turn all conditional logging off while keeping other DEBUG features
#endif

メインブロックで、アプリのモジュールに対応するさまざまなカテゴリを定義します。また、ロギング コールが呼び出されないロギングレベルを定義します。次に、NSLog出力のさまざまなフレーバーを定義します。

#ifdef LOG_CATEGORY_DETAIL

    //define the categories using bitwise leftshift operators
    #define kLogGCD (1<<0)
    #define kLogCoreCreate (1<<1)
    #define kLogModel (1<<2)
    #define kLogVC (1<<3)
    #define kLogFile (1<<4)
    //etc

    //add the categories that should be logged...
    #define kLOGIFcategory kLogModel+kLogVC+kLogCoreCreate

    //...and the maximum detailLevel to report (use -1 to override the category switch)
    #define kLOGIFdetailLTEQ 4

    // output looks like this:"-[AppDelegate myMethod] log string..."
    #   define myLog(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%s " format), __PRETTY_FUNCTION__, ##__VA_ARGS__);}

    // output also shows line number:"-[AppDelegate myMethod][l17]  log string..."
    #   define myLogLine(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%s[l%i] " format), __PRETTY_FUNCTION__,__LINE__ ,##__VA_ARGS__);}

    // output very simple:" log string..."
    #   define myLogSimple(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"" format), ##__VA_ARGS__);}

    //as myLog but only shows method name: "myMethod: log string..."
    // (Doesn't work in C-functions)
    #   define myLog_cmd(category,detailLevel,format,...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%@: " format), NSStringFromSelector(_cmd), ##__VA_ARGS__);}

    //as myLogLine but only shows method name: "myMethod>l17: log string..."
    #   define myLog_cmdLine(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%@>l%i: " format), NSStringFromSelector(_cmd),__LINE__ , ##__VA_ARGS__);}

    //or define your own...
   // # define myLogEAGLcontext(category,detailLevel,format, ...) if(detailLevel<0 || ((category&kLOGIFcategory)&&detailLevel<= kLOGIFdetailLTEQ)) {NSLog((@"%s>l%i (ctx:%@)" format), __PRETTY_FUNCTION__,__LINE__ ,[EAGLContext currentContext], ##__VA_ARGS__);}

#else
    #   define myLog_cmd(...)
    #   define myLog_cmdLine(...)
    #   define myLog(...)
    #   define myLogLine(...)
    #   define myLogSimple(...)
    //#   define myLogEAGLcontext(...)
#endif

したがって、kLOGIFcategoryおよびkLOGIFdetailLTEQの現在の設定では、次のような呼び出し

myLogLine(kLogVC, 2, @"%@",self);

印刷されますが、これは印刷されません

myLogLine(kLogGCD, 2, @"%@",self);//GCD not being printed

するつもりもない

myLogLine(kLogGCD, 12, @"%@",self);//level too high

個別のログ呼び出しの設定を上書きする場合は、負のレベルを使用します。

myLogLine(kLogGCD, -2, @"%@",self);//now printed even tho' GCD category not active.

私はできる限り、各行を入力するいくつかの余分な文字が価値があると思います

  1. コメントのカテゴリ全体をオンまたはオフに切り替えます(たとえば、モデルとマークされた通話のみを報告します)
  2. より高いレベルの番号、またはより低い番号でマークされた最も重要な呼び出しのみで詳細を報告する

多くの人がこれは少しやり過ぎだと思うでしょうが、誰かが目的に合っているとわかった場合に備えて。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.