web-dev-qa-db-fra.com

Comment imprimer le nom de la méthode et le numéro de ligne et désactiver conditionnellement NSLog?

Je fais une présentation sur le débogage dans Xcode et j'aimerais obtenir plus d'informations sur l'utilisation efficace de NSLog.

En particulier, j'ai deux questions:

  • y at-il un moyen de facilement NSLog le nom/numéro de ligne de la méthode actuelle?
  • y at-il un moyen de "désactiver" tous les NSLogs facilement avant de compiler pour le code de version?
444
rein

Voici quelques macros utiles autour de NSLog que j'utilise beaucoup:

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

La macro DLog est utilisée pour générer uniquement lorsque la variable DEBUG est définie (-DDEBUG dans les indicateurs C du projet pour la configuration de débogage).

ALog produira toujours du texte (comme le NSLog standard).

La sortie (par exemple, ALog (@ "Hello world")) ressemblera à ceci:

-[LibraryController awakeFromNib] [Line 364] Hello world
591
diederikh

J'ai pris DLog et ALog d'en haut, et j'ai ajouté ULog, ce qui déclenche un message UIAlertView.

Résumer:

  • DLog affichera comme NSLog uniquement lorsque la variable DEBUG est définie
  • ALog restituera toujours comme NSLog
  • ULog affichera le UIAlertView uniquement lorsque la variable DEBUG est définie
 # ifdef DEBUG 
 # définir DLog (fmt, ...) NSLog ((@ "% s [Ligne% d]" fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS __); 
 # else 
 # définir DLog (...) 
 # endif 
 # définir ALog (fmt, ...) NSLog ((@ "% s [Ligne% d] "fmt), __PRETTY_FUNCTION__, __LINE__, ## __ VA_ARGS __); 
 # ifdef DEBUG 
 # définir ULog (fmt, ...) {UIAlertView * alert = [[UIAlertView alloc] initWithTit: [NSString stringWithFormat: @ "% s\n [Ligne% d]", __PRETTY_FUNCTION__, __LINE__] message: [NSString stringWithFormat: fmt, ## __ VA_ARGS__] delegate: nil cancelButtonTitle: @ "Ok", autre; [émission d'alerte]; } 
 # else 
 # définir ULog (...) 
 # endif 

Voici à quoi ça ressemble:

Debug UIAlertView

+1 Diederik

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

Nom du fichier de sortie, numéro de ligne et nom de la fonction:

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

__FUNCTION__ en C++ indique le nom mutilé __PRETTY_FUNCTION__ indique le nom de la fonction Nice. Dans le cacao, leur apparence est identique.

Je ne sais pas quelle est la bonne façon de désactiver NSLog, je l’ai fait:

#define NSLog

Et aucune sortie de journalisation n'est apparue, cependant je ne sais pas si cela a des effets secondaires.

74
stefanB

Voici une grande collection de constantes de débogage que nous utilisons. Prendre plaisir.

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

Il y a un nouveau truc qui ne donne pas de réponse. Vous pouvez utiliser printf à la place de NSLog. Cela vous donnera un journal propre:

Avec NSLog vous obtenez des choses comme ceci:

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

Mais avec printf vous n’obtenez que:

Hello World

Utilisez ce code

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

Ma réponse à cette question pourrait peut-être aider. Elle ressemble à celle que Diederik a préparée. Vous pouvez également vouloir remplacer l'appel à NSLog() par une instance statique de votre propre classe de journalisation personnalisée. Vous pouvez ainsi ajouter un indicateur de priorité pour les messages de débogage/avertissement/d'erreur, ainsi que pour envoyer des messages à un fichier ou à une base de données. en tant que console, ou à peu près tout ce que vous pouvez penser.

#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
Marc Charbonneau

En désactivant tous les NSLogs, pour une personne allergique au MACROS, voici quelque chose que vous pouvez également compiler:

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

Et utilisez-le presque comme NSLog:

SJLog(@"bye bye NSLogs !");

Depuis ce blog: http://whackylabs.com/rants/?p=134

13
chunkyguy

Pour compléter les réponses ci-dessus, il peut être très utile d’utiliser un remplaçant pour NSLog dans certaines situations, notamment lors du débogage. Par exemple, le fait de supprimer toutes les informations de date et de nom/identifiant de processus sur chaque ligne peut rendre la sortie plus lisible et plus rapide à démarrer.

Le lien suivant fournit un peu de munitions utiles pour rendre la journalisation simple beaucoup plus agréable.

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

11
Quinn Taylor

Il est facile de modifier vos NSLogs existants pour afficher le numéro de ligne et la classe à partir desquels ils sont appelés. Ajoutez une ligne de code à votre fichier de préfixe:

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

C'est simple, par exemple

void) applicationWillEnterForeground: (UIApplication *) application {

    NSLog(@"%s", __PRETTY_FUNCTION__);

}

--- (Sortie: - [AppDelegate applicationWillEnterForeground:]

7
Venkat Reddy

construisant au-dessus des réponses ci-dessus, voici ce que j’ai plagié et proposé. Également ajouté la journalisation de la mémoire.

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

Nouvelle addition à DLog. Au lieu de supprimer totalement le débogage de l'application publiée, ne le désactivez que. Lorsque l'utilisateur a des problèmes nécessitant un débogage, indiquez simplement comment activer le débogage dans les applications publiées et demander les données du journal par courrier électronique.

Version courte: créez une variable globale (oui, solution simple et lente) et modifiez DLog comme ceci:

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

Réponse plus longue chez Jomnius iLessons iLearned: Procédure de journalisation de débogage dynamique dans une application publiée

4
JOM

Depuis quelque temps, j'utilise un site de macros adoptées par plusieurs d'entre elles. Je me concentre sur la journalisation dans la console, en mettant l’accent sur verbosité contrôlée et filtrée; Si cela ne vous dérange pas beaucoup de lignes de journal, mais que vous voulez facilement activer/désactiver des lots, alors cela peut vous être utile.

Tout d'abord, je remplace éventuellement NSLog avec printf comme décrit par @Rodrigo ci-dessus

#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

Ensuite, j'activer ou désactiver la connexion.

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

Dans le bloc principal, définissez divers catégories correspondant aux modules de votre application. Définissez également une journalisation nivea au-dessus de laquelle les appels de journalisation ne seront pas appelés. Puis définissez divers variantes de la sortie 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

Ainsi, avec les paramètres actuels de kLOGIFcategory et kLOGIFdetailLTEQ, un appel comme

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

imprimera mais cela ne sera pas

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

ni sera

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

Si vous souhaitez remplacer les paramètres d'un appel de journal individuel, utilisez un niveau négatif:

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

Je trouve que les quelques caractères supplémentaires de frappe de chaque ligne valent la peine, alors je peux

  1. Activer ou désactiver une catégorie entière de commentaires (par exemple, ne signaler que les appels marqués du modèle)
  2. signaler des détails précis avec des numéros de niveau supérieur ou uniquement les appels les plus importants marqués avec des numéros inférieurs

Je suis sûr que beaucoup trouveront cela un peu exagéré, mais juste au cas où quelqu'un trouve que cela convient à leurs objectifs.

3
cate