Jak wydrukować nazwę Metody i numer linii i warunkowo wyłączyć NSLog?

Robię prezentację na temat debugowania w Xcode i chciałbym uzyskać więcej informacji na temat efektywnego korzystania z NSLog.

W szczególności mam dwa pytania:

  • czy jest jakiś sposób na łatwe Nslogowanie nazwy / numeru linii bieżącej metody?
  • czy istnieje sposób na łatwe "wyłączenie" wszystkich Nslogów przed kompilacją kodu wydania?
Author: rein, 2009-06-09

13 answers

Oto kilka przydatnych makr wokół NSLog, których często używam:

#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__)

Makro DLog jest używane tylko wtedy, gdy zmienna debugowania jest ustawiona (- DDEBUG w flagach C projektów dla potwierdzenia debugowania).

ALog zawsze wyświetli tekst (jak zwykły NSLog).

Wyjście (np. ALog(@"Hello world") ) będzie wyglądało tak:

-[LibraryController awakeFromNib] [Line 364] Hello world
 582
Author: diederikh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-03 20:10:31

Wziąłem DLog i ALog z góry i dodałem ULog co podnosi UIAlertView wiadomość.

Do podsumowania:

  • DLog wyświetli się tak jak NSLog tylko wtedy, gdy zmienna DEBUG jest ustawiona
  • ALog będzie zawsze wyświetlać jak NSLog
  • ULog wyświetli UIAlertView tylko wtedy, gdy zmienna DEBUG jest ustawiona
#ifdef DEBUG
#   define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define 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]; [alert show]; }
#else
#   define ULog(...)
#endif

Tak to wygląda:

Debug UIAlertView

+ 1 Diederik

 141
Author: Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-26 13:25:02
NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);

Wypisuje nazwę pliku, numer linii i nazwę funkcji:

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

__FUNCTION__ w C++ pokazuje zniekształconą nazwę __PRETTY_FUNCTION__ pokazuje ładną nazwę funkcji, w cocoa wyglądają tak samo.

Nie jestem pewien, jaki jest właściwy sposób wyłączenia NSLog, zrobiłem:

#define NSLog

I nie pojawił się żaden wynik logowania, jednak nie wiem, czy ma to jakieś skutki uboczne.

 73
Author: stefanB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-28 11:47:29

Tutaj jedna duża kolekcja stałych debugowania, których używamy. Smacznego.

// 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
 20
Author: SEQOY Development Team,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-04 17:35:04

Są nowe sztuczki, które nie dają odpowiedzi. Możesz użyć printf zamiast NSLog. To da ci czysty dziennik:

Z NSLog dostajesz takie rzeczy:

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

Ale z printf otrzymujesz tylko:

Hello World

Użyj tego kodu

#ifdef DEBUG
    #define NSLog(FORMAT, ...) fprintf(stderr,"%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
    #define NSLog(...) {}              
#endif
 19
Author: Rodrigo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-02 14:20:05

Moja odpowiedź nato pytanie może pomóc, wygląda na to, że jest podobne do tego, które przygotował Diederik. Możesz również zastąpić wywołanie NSLog() statyczną instancją własnej niestandardowej klasy logging, w ten sposób możesz dodać flagę priorytetu dla komunikatów debug/warning/error, wysyłać wiadomości do pliku lub bazy danych, jak również do konsoli, lub cokolwiek innego, co możesz wymyślić.

#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
 16
Author: Marc Charbonneau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:00

Wyłączanie wszystkich Nslogów, dla kogoś uczulonego na makra, tutaj jest coś, co możesz również skompilować:

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

I używaj go prawie jak NSLog:

SJLog(@"bye bye NSLogs !");

Z tego bloga: http://whackylabs.com/rants/?p=134

 13
Author: chunkyguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-04 17:59:39

Aby uzupełnić powyższe odpowiedzi, bardzo przydatne może być użycie zamiennika dla NSLog w pewnych sytuacjach, szczególnie podczas debugowania. Na przykład pozbycie się wszystkich informacji o dacie i nazwie / ID procesu w każdej linii może sprawić, że wyjście będzie bardziej czytelne i szybsze do uruchomienia.

Poniższy link dostarcza sporej ilości amunicji, która ułatwia proste logowanie.

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

 11
Author: Quinn Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-10 06:11:28

Łatwo jest zmienić istniejące Nslogi, aby wyświetlały numer linii i klasę, z której są wywoływane. Dodaj jeden wiersz kodu do pliku prefiksu:

#define NSLog(__FORMAT__, ...) NSLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
 11
Author: AddisDev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-02 00:29:37

jest to proste, na przykład

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

    NSLog(@"%s", __PRETTY_FUNCTION__);

}

Wyjście: - [AppDelegate applicationWillEnterForeground:]

 6
Author: Venkat Reddy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-29 07:18:09

Opierając się na powyższych odpowiedziach, oto co wymyśliłem. Dodano również rejestrowanie pamięci.

#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
 5
Author: Dickey Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-09 02:03:04

Nowy dodatek do DLog. Zamiast całkowicie usuwać debugowanie z wydanej aplikacji, wyłącz ją tylko. Jeśli użytkownik ma problemy, które wymagają debugowania, po prostu powiedz, jak włączyć debugowanie w wydanej aplikacji i zażądaj danych dziennika przez e-mail.

Skrócona wersja: Utwórz zmienną globalną (tak, leniwe i proste rozwiązanie) i zmodyfikuj DLog w następujący sposób:

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

Dłuższa odpowiedź w Jomnius iLessons iLearned: Jak zrobić dynamiczne Logowanie debugowania Zastosowanie

 4
Author: JOM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-07 05:21:06

Od jakiegoś czasu używam strony makr zaadoptowanych z kilku powyższych. Moje skupiają się na logowaniu w Konsoli, z naciskiem na kontrolowaną i filtrowaną szczegółowość ; Jeśli nie masz nic przeciwko wielu linijkom dziennika, ale chcesz łatwo włączyć i wyłączyć ich partie, to może Ci się to przydać.

Po pierwsze, opcjonalnie zamieniam nslog na printf zgodnie z opisem @Rodrigo powyżej

#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

Następnie włączam lub wyłączam logowanie.

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

W głównym bloku zdefiniuj różne kategorie odpowiadające modułom w Twojej aplikacji. Zdefiniuj również poziom logowania , powyżej którego wywołania logowania nie będą wywoływane. Następnie zdefiniuj różne smaki wyjścia 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

Tak więc, z aktualnymi ustawieniami dla kLOGIFcategory i kLOGIFdetailLTEQ, wywołanie podobne do

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

Wydrukuje, ale to nie

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

Nor will

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

Jeśli chcesz nadpisać ustawienia dla pojedynczego wywołania dziennika, użyj negatywnego poziom:

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

Uważam, że kilka dodatkowych znaków wpisywania każdej linii jest wart, Jak mogę wtedy

    [34]} Włącz lub wyłącz całą kategorię komentarza (np. zgłoś tylko te wywołania oznaczone jako Model)
  1. raport o szczegółach z numerami wyższego poziomu lub po prostu najważniejszych połączeń oznaczonych numerami niższymi

Jestem pewien, że wielu uzna to za lekką przesadę, ale na wypadek, gdyby ktoś uznał, że odpowiada to ich celom..

 3
Author: cate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-12 13:59:53