2009-06-09 24 views
434

Tôi đang thực hiện bản trình bày về gỡ lỗi trong Xcode và muốn nhận thêm thông tin về cách sử dụng NSLog hiệu quả.Làm thế nào để in ra tên phương thức và số dòng và vô hiệu hóa điều kiện NSLog?

Trong đó, tôi có hai câu hỏi:

  • là có một cách dễ dàng NSLog số tên/dòng phương pháp hiện tại không?
  • có cách nào để "vô hiệu hóa" tất cả NSLogs dễ dàng trước khi biên dịch cho mã phát hành không?
+12

** câu hỏi đầu tiên ở đó yêu thích (dấu sao) nhiều hơn ... + +1 .. –

Trả lời

572

Dưới đây là một số macro hữu ích xung quanh NSLog tôi sử dụng rất nhiều:

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

Các DLog vĩ mô được sử dụng để chỉ ra khi biến DEBUG được thiết lập (-DDEBUG trong cờ C của dự án cho confirguration debug) .

ALog sẽ luôn xuất văn bản (như NSLog thông thường).

Sản lượng (ví dụ ALog (@ "Hello world")) sẽ trông như thế này:

-[LibraryController awakeFromNib] [Line 364] Hello world 
+0

Tại sao bạn có ##?Tôi nghĩ rằng đó là để đối chiếu với nhau, nhưng bạn không dán vào bất cứ thứ gì. – Casebash

+1

Điều này ngăn chặn việc mở rộng vĩ mô có thể có của các đối số – diederikh

+0

Điều đó có thể xảy ra với các macro nói chung; một số macro mang lại nhiều dòng. Chỉ cần một đối số để luôn luôn sử dụng niềng răng ;-). – diederikh

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

Đầu ra tập tin tên, số dòng, và tên hàm:

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

__FUNCTION__ trong C++ cho thấy đọc sai tên __PRETTY_FUNCTION__ thấy tên hàm đẹp, trong cacao họ đều giống nhau.

Tôi không chắc chắn cách đúng đắn của việc vô hiệu hóa NSLog là gì, tôi đã làm:

#define NSLog 

Và không có đầu ra đăng nhập xuất hiện, tuy nhiên tôi không biết nếu điều này có bất kỳ tác dụng phụ.

16

câu trả lời của tôi để this question có thể giúp đỡ, có vẻ như nó là tương tự như một Diederik nấu chín lên. Bạn cũng có thể muốn thay thế cuộc gọi thành NSLog() bằng phiên bản tĩnh của lớp ghi nhật ký tùy chỉnh của riêng bạn, theo cách đó bạn có thể thêm cờ ưu tiên cho thông báo lỗi/cảnh báo/lỗi, gửi thư đến tệp hoặc cơ sở dữ liệu cũng như bảng điều khiển, hoặc khá nhiều bất cứ điều gì khác bạn có thể nghĩ đến.

#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 
+0

Bởi vì bạn đã tránh định dạng '% s' mà Apple đang cố gắng từ chối và tránh cảnh báo Clang-format-directive' Clang mới được giới thiệu vào năm 2015. – Jeff

11

Để bổ sung các câu trả lời ở trên, bạn có thể sử dụng thay thế cho NSLog trong một số trường hợp nhất định, đặc biệt khi gỡ lỗi. Ví dụ, việc loại bỏ tất cả các ngày tháng và xử lý thông tin tên/id trên mỗi dòng có thể làm cho đầu ra dễ đọc hơn và khởi động nhanh hơn.

Liên kết sau đây cung cấp khá nhiều đạn hữu ích để thực hiện việc ghi nhật ký đơn giản hơn rất nhiều.

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

20

Đây là một tập hợp lớn các hằng số gỡ lỗi mà chúng tôi sử dụng. Thưởng thức.

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

Vô hiệu hóa tất cả NSLogs, cho ai đó bị dị ứng với các macro, đây là điều mà bạn có thể biên dịch quá:

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

Và, sử dụng nó gần giống như NSLog:

SJLog(@"bye bye NSLogs !"); 

Từ này blog: http://whackylabs.com/rants/?p=134

140

Tôi đã chụp DLogALog từ trên cao và thêm ULog làm tăng thông báo UIAlertView.

Để tóm tắt:

  • DLog chí đầu ra như NSLog chỉ khi biến DEBUG được thiết lập
  • ALog sẽ luôn đầu ra như NSLog
  • ULog sẽ hiển thị các UIAlertView chỉ khi biến DEBUG được thiết lập
 
#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 

Đây là những gì nó trông giống như:

Debug UIAlertView

+1 Diederik

+0

Tôi cũng sẽ mở rộng mã ALog + DLog của mình bằng ULog. Rất hữu dụng. – neoneye

+0

Mã này gây ra lỗi biến không sử dụng trong Xcode 5.1 nếu không chạy trong DEBUG: ( – yonix

+0

Tại sao một số lệnh #define kết thúc bằng dấu chấm phẩy? – Monstieur

4

Ngoài mới để DLog. Thay vì gỡ bỏ hoàn toàn gỡ lỗi khỏi ứng dụng được phát hành, chỉ vô hiệu hóa nó. Khi người dùng gặp sự cố, điều này sẽ yêu cầu gỡ lỗi, chỉ cần cho biết cách bật gỡ lỗi trong ứng dụng đã phát hành và yêu cầu dữ liệu nhật ký qua email.

phiên bản ngắn: tạo biến toàn cục (có, giải pháp lười biếng và đơn giản) và sửa đổi DLog như thế này:

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

Còn câu trả lời tại Jomnius iLessons iLearned: How to Do Dynamic Debug Logging in Released Application

19

Có một thủ thuật mới mà không trả lời cho. Bạn có thể sử dụng printf thay vì NSLog. Điều này sẽ cung cấp cho bạn một bản ghi sạch:

Với NSLog bạn có được những điều như thế này:

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

Nhưng với printf bạn chỉ nhận được:

Hello World 

Sử dụng mã này

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

xây dựng trên đầu trang của câu trả lời ở trên, đây là những gì tôi đạo văn và đã đưa ra . Cũng đã thêm ghi nhật ký bộ nhớ.

#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 
11

Thật dễ dàng để thay đổi NSLogs hiện tại của bạn để hiển thị số dòng và lớp mà từ đó chúng được gọi. Thêm một dòng mã vào tệp tiền tố của bạn:

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

Điều này thật tuyệt! Bạn sẽ làm điều này nhanh như thế nào? –

+0

@AddisDev Tôi thích điều này tốt nhất. Rất sạch sẽ và đơn giản. Tôi chỉ sử dụng NSLog. Tôi không biết DLog & ULog là gì Dù sao, hãy bình chọn ... –

+0

@AddisDev Tôi thực sự không hiểu tại sao Apple không thêm dữ liệu quan trọng này vào NSLog() theo mặc định? Bizarre ... –

3

Trong một thời gian tôi đã sử dụng một trang web macro được áp dụng từ một số ở trên. Tôi tập trung vào việc đăng nhập vào Bảng điều khiển, với sự nhấn mạnh vào được kiểm soát & độ dài được lọc; nếu bạn không nhớ nhiều dòng đăng nhập nhưng muốn dễ dàng chuyển đổi hàng loạt trong số đó trên & tắt, thì bạn có thể thấy điều này hữu ích.

Trước tiên, tôi tùy chọn thay thế NSLog với printf như mô tả của @Rodrigo trên

#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 

Tiếp theo, tôi chuyển sang đăng nhập hoặc tắt.

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

Trong khối chính, xác định khác nhau loại tương ứng với module trong ứng dụng của bạn. Đồng thời xác định mức độ ghi nhật ký ở mức ở trên mà cuộc gọi ghi nhật ký sẽ không được gọi. Sau đó xác định khác nhau hương vị sản lượng 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 

Như vậy, với các thiết lập hiện tại cho kLOGIFcategory và kLOGIFdetailLTEQ, một cuộc gọi như

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

sẽ in nhưng điều này sẽ không

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

cũng không phải

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

Nếu bạn muốn ghi đè lên các thiết lập cho cuộc gọi đăng nhập cá nhân, sử dụng một mức độ tiêu cực:

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

tôi thấy vài nhân vật phụ gõ mỗi dòng có giá trị như tôi có thể sau đó

  1. Bật hoặc tắt toàn bộ danh mục nhận xét (ví dụ: chỉ báo cáo những cuộc gọi được đánh dấu Model)
  2. báo cáo về chi tiết đẹp với những con số mức độ cao hơn hoặc chỉ các cuộc gọi quan trọng nhất được đánh dấu bằng con số thấp hơn

Tôi chắc chắn nhiều người sẽ tìm thấy điều này một chút của một overkill, nhưng chỉ trong trường hợp ai đó tìm thấy nó phù hợp với mục đích của họ ..

6

nó rất đơn giản, ví dụ

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

NSLog(@"%s", __PRETTY_FUNCTION__); 

}

Đầu ra: - [AppDelegate applicationWillEnterForeground:]

Các vấn đề liên quan