Como imprimir o nome do método e o número da linha e desabilitar condicionalmente o NSLog?

446

Estou fazendo uma apresentação sobre depuração no Xcode e gostaria de obter mais informações sobre o uso eficiente do NSLog.

Em particular, tenho duas perguntas:

  • existe uma maneira de NSLog facilmente o nome / número da linha do método atual?
  • existe uma maneira de "desativar" todos os NSLogs facilmente antes de compilar o código de lançamento?
rédea
fonte
12
primeira pergunta onde os favoritos (estrela) são mais do que votados ... +1 ..
Fahim Parkar 17/08

Respostas:

592

Aqui estão algumas macros úteis em torno do NSLog que eu uso muito:

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

A macro DLog é usada apenas para saída quando a variável DEBUG está definida (-DDEBUG nos sinalizadores C dos projetos para a confirmação de depuração).

ALog sempre produzirá texto (como o NSLog normal).

A saída (por exemplo, ALog (@ "Hello world")) ficará assim:

-[LibraryController awakeFromNib] [Line 364] Hello world
morrerikh
fonte
Por que você tem um ##? Eu pensei que era para colar argumentos juntos, mas você não está colando em nada.
Casebash
1
Isso evita a possível expansão macro dos argumentos
dieerikh 31/01
Isso pode acontecer com macros em geral; algumas macros produzem várias linhas. Apenas outro argumento para sempre usar chaves ;-).
diederikh
A API great e cocos2d tem a instrução de log semelhante.
Yoon Lee
Como isso (@"%s [Line %d] " fmt)faz com que o fmtapêndice seja adicionado à cadeia de controle? Não vi essa sintaxe além da macro de depuração.
Robert Altman
141

Eu peguei DLoge ALogde cima, e adicionei o ULogque gera umaUIAlertView mensagem.

Para resumir:

  • DLogserá exibido NSLogapenas quando a variável DEBUG estiver configurada
  • ALog sempre sairá como NSLog
  • ULogmostrará o UIAlertViewúnico quando a variável DEBUG estiver configurada
#ifdef DEBUG
# define DLog (fmt, ...) NSLog ((@ "% s [Linha% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS__);
#outro
# define DLog (...)
#fim se
#define ALog (fmt, ...) NSLog ((@ "% s [Linha% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS__);
#ifdef DEBUG
# define ULog (fmt, ...) {UIAlertView * alert = [[UIAlertView aloc] initWithTitle: [NSString stringWithFormat: @ "% s \ n [Linha% d]", __PRETTY_FUNCTION__, __LINE__] mensagem: [NSString stringWithFormat: fmt , ## __ VA_ARGS__] delegado: nulo cancelButtonTitle: @ "Ok" otherButtonTitles: nil]; [show de alerta]; }
#outro
# define ULog (...)
#fim se

Isto é o que parece:

Depurar UIAlertView

+1 Diederik

Whitneyland
fonte
Vou estender meu código ALog + DLog com ULog também. Muito útil.
neoneye
Este código causa um erro de variável não utilizado no Xcode 5.1 se não estiver sendo executado no DEBUG :(
yonix 18/03/14
Por que algumas das diretivas #define terminam com ponto e vírgula?
Monstieur
@Locutus Então você não precisa colocar um ponto e vírgula após a DLogdeclaração. Isso é útil porque, se você o fez, nas compilações da versão, não DLogé compilado e você fica com um ponto-e-vírgula danificado no seu código. Isso não é um erro, mas pode gerar um aviso, dependendo das configurações, se seguir outro ponto e vírgula.
Zev Eisenberg
74
NSLog(@"%s %d %s %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);

Envia o nome do arquivo, o número da linha e o nome da função:

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

__FUNCTION__em C ++ mostra o nome mutilado __PRETTY_FUNCTION__mostra um bom nome da função, no cacau eles parecem iguais.

Não sei ao certo qual é a maneira correta de desabilitar o NSLog.

#define NSLog

E nenhuma saída de log apareceu, no entanto, não sei se isso tem efeitos colaterais.

stefanB
fonte
20

Aqui está uma grande coleção de constantes de depuração que usamos. Aproveitar.

// 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
Equipe de Desenvolvimento SEQOY
fonte
19

Há um novo truque que nenhuma resposta dá. Você pode usar em seu printflugar NSLog. Isso fornecerá um log limpo:

Com NSLog você obtém coisas assim:

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

Mas com printfvocê só tem:

Hello World

Use este código

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

Minha resposta a esta pergunta pode ajudar, parece que ela é semelhante à que Diederik inventou. Você também pode substituir a chamada NSLog()por uma instância estática de sua própria classe de log customizada, para adicionar um sinalizador de prioridade às mensagens de depuração / aviso / erro, enviar mensagens para um arquivo ou banco de dados, bem como para o console ou praticamente tudo o que você pode pensar.

#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
Marc Charbonneau
fonte
Porque você se esquivou %sespecificador de formato que a Apple está tentando depreciar e evitou -Wcstring-format-directiveaviso Clang recentemente introduzido em 2015.
Jeff
11

Para complementar as respostas acima, pode ser bastante útil usar um substituto para o NSLog em determinadas situações, especialmente durante a depuração. Por exemplo, livrar-se de todas as informações de nome e identificação de data e processo em cada linha pode tornar a saída mais legível e rápida de inicializar.

O link a seguir fornece um pouco de munição útil para tornar o registro simples muito mais agradável.

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

Quinn Taylor
fonte
11

É fácil alterar os NSLogs existentes para exibir o número da linha e a classe a partir da qual eles são chamados. Adicione uma linha de código ao seu arquivo de prefixo:

#define NSLog(__FORMAT__, ...) NSLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
AddisDev
fonte
3
Isso é ótimo! como você faria isso rapidamente?
Uplearnedu.com
@AddisDev Eu gosto mais disso. Muito limpo e simples. Eu só uso o NSLog. Eu não tenho idéia do que DLog e ULog são de qualquer maneira! Obrigado. Até votado ...
Charles Robertson
@AddisDev Realmente não entendo por que a Apple não adiciona esses dados de importância vital ao NSLog () por padrão? Bizarro ...
Charles Robertson
8

É simples, por exemplo

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

    NSLog(@"%s", __PRETTY_FUNCTION__);

}

Saída: - [AppDelegate applicationWillEnterForeground:]

Venkat Reddy
fonte
5

construindo sobre as respostas acima, eis o que plagiei e o que descobri. Também foi adicionado log de memória.

#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
Dickey Singh
fonte
4

Nova adição ao DLog. Em vez de remover totalmente a depuração do aplicativo liberado, desative-o apenas. Quando o usuário tiver problemas, o que exigiria depuração, apenas diga como habilitar a depuração no aplicativo lançado e solicitar dados de log por email.

Versão curta: crie uma variável global (sim, solução lenta e simples) e modifique o DLog da seguinte forma:

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

Resposta mais longa no Jomnius iLessons iLearned: Como fazer log de depuração dinâmica no aplicativo liberado

JOM
fonte
3

Há algum tempo eu uso um site de macros adotado por vários acima. Meu foco é fazer logon no console, com ênfase na verbosidade controlada e filtrada ; se você não se importa com muitas linhas de log, mas deseja ativar e desativar lotes com facilidade, pode ser útil.

Primeiro, opcionalmente substituo o NSLog por printf, conforme descrito por @Rodrigo acima

#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

Em seguida, ative ou desative o logon.

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

No bloco principal, defina várias categorias correspondentes aos módulos no seu aplicativo. Defina também um nível de registro acima do qual as chamadas de registro não serão chamadas. Em seguida, defina vários tipos de saída do 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

Assim, com as configurações atuais de kLOGIFcategory e kLOGIFdetailLTEQ, uma chamada como

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

irá imprimir, mas isso não

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

nem vai

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

Se você deseja substituir as configurações de uma chamada de log individual, use um nível negativo:

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

Acho que os poucos caracteres extras de digitação de cada linha valem o máximo que posso

  1. Ative ou desative uma categoria inteira de comentários (por exemplo, relate apenas as chamadas marcadas como Modelo)
  2. relate detalhes detalhados com números de nível mais alto ou apenas as chamadas mais importantes marcadas com números mais baixos

Tenho certeza que muitos acharão isso um pouco exagerado, mas no caso de alguém achar que é adequado a seus propósitos ..

cate
fonte