메소드 이름과 줄 번호를 인쇄하고 조건부로 NSLog를 비활성화하는 방법은 무엇입니까?


446

Xcode에서 디버깅에 대한 프레젠테이션을하고 NSLog를 효율적으로 사용하는 방법에 대한 자세한 정보를 얻고 싶습니다.

특히 두 가지 질문이 있습니다.

  • 현재 메소드의 이름 / 줄 번호를 쉽게 NSLog하는 방법이 있습니까?
  • 릴리스 코드를 컴파일하기 전에 모든 NSLog를 쉽게 "비활성화"하는 방법이 있습니까?

12
즐겨 찾기 (별이) 더 후하다 첫 번째 질문은 ... upvotes .. +1
파힘 Parkar

답변:


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

1
이것은 인수의 매크로 확장을 막습니다
diederikh

일반적으로 매크로에서 발생할 수 있습니다. 일부 매크로는 여러 줄을 생성합니다. 항상 중괄호 ;-)를 사용하는 또 다른 인수.
diederikh

great 및 cocos2d api는 비슷한 로그 문을 가지고 있습니다.
Yoon Lee

어떻게 즉 (@"%s [Line %d] " fmt)원인 fmt제어 문자열에 추가 할? 이 디버그 매크로 이외의 다른 구문은 보지 못했습니다.
Robert Altman

141

내가 찍은 DLogALog위에서, 그리고 추가 ULog제기하는 UIAlertView메시지를.

요약:

  • 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__] 메시지 : [NSString stringWithFormat : fmt , ## __ VA_ARGS__] delegate : nil cancelButtonTitle : @ "Ok"otherButtonTitles : nil]; [경고 쇼]; }
#그밖에
# ULog 정의 (...)
#endif

이것은 다음과 같습니다

UIAlertView 디버그

디 데릭 +1


ULog를 사용하여 ALog + DLog 코드를 확장 할 것입니다. 매우 유용한.
neoneye

이 코드는 DEBUG에서 실행되지 않는 경우 Xcode 5.1에서 사용되지 않는 변수 오류를 발생시킵니다. (
yonix

#define 지시문 중 일부가 세미콜론으로 끝나는 이유는 무엇입니까?
Monstieur

@Locutus 따라서 DLog명령문 뒤에 세미콜론을 넣을 필요가 없습니다 . 릴리스 빌드에서 수행 한 작업 DLog이 아무 것도 컴파일되지 않은 경우 코드에 매달려있는 세미콜론이 남게 되므로 유용 합니다. 이것은 오류는 아니지만 설정에 따라 다른 세미콜론을 따르는 경우 경고가 표시 될 수 있습니다.
Zev Eisenberg

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

파일 이름, 줄 번호 및 기능 이름을 출력합니다.

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

__FUNCTION__C ++에서 맹 글링 된 이름 __PRETTY_FUNCTION__은 멋진 함수 이름을 보여 주며 코코아에서는 동일하게 보입니다.

NSLog를 비활성화하는 올바른 방법이 무엇인지 잘 모르겠습니다.

#define NSLog

로깅 출력이 나타나지 않았지만 부작용이 있는지 모르겠습니다.


20

여기에 우리가 사용하는 디버그 상수의 큰 모음이 있습니다. 즐겨.

// 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

%sApple이 -Wcstring-format-directive2015 년에 새로 도입 한 Clang 경고 를 더 이상 사용하지 않고 사용하지 않으려는 형식 지정자를 피하기 때문에
Jeff


11

위의 답변을 보완하려면 특정 상황, 특히 디버깅 할 때 NSLog를 대체하는 것이 매우 유용 할 수 있습니다. 예를 들어, 각 줄의 모든 날짜 및 프로세스 이름 / ID 정보를 제거하면 출력을보다 읽기 쉽고 빠르게 부팅 할 수 있습니다.

다음 링크는 간단한 로깅을 훨씬 좋게 만드는 데 유용한 탄약을 제공합니다.

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


11

기존 NSLog를 쉽게 변경하여 라인 번호와 클래스를 표시 할 수 있습니다. 접두사 파일에 한 줄의 코드를 추가하십시오.

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

3
대단해! 어떻게 신속하게이 작업을 수행 하시겠습니까?
uplearnedu.com

@AddisDev 나는 이것을 최고로 좋아한다. 매우 깨끗하고 간단합니다. NSLog 만 사용합니다. 어쨌든 DLog & ULog가 무엇인지 전혀 모른다! 감사. 위로 투표 ...
찰스 로버트슨

@AddisDev 애플이 왜이 중요한 데이터를 기본적으로 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.