web-dev-qa-db-fra.com

Est-il vrai que l'on ne devrait pas utiliser NSLog () sur le code de production?

On me l'a dit plusieurs fois sur ce site même, mais je voulais m'assurer que c'était vraiment le cas.

Je m'attendais à pouvoir arroser les appels de fonction NSLog dans tout mon code, et que Xcode/gcc supprimerait automatiquement ces appels lors de la construction de mes versions Release/Distribution.

Dois-je éviter de l'utiliser? Si oui, quelles alternatives sont les plus courantes entre les programmeurs Objective-C expérimentés?

153
jpm

Les macros de préprocesseur sont en effet idéales pour le débogage. Il n'y a rien de mal avec NSLog (), mais il est simple de définir votre propre fonction de journalisation avec de meilleures fonctionnalités. Voici celui que j'utilise, il comprend le nom de fichier et le numéro de ligne pour faciliter le suivi des instructions de journal.

#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

J'ai trouvé plus facile de mettre cette instruction entière dans l'en-tête du préfixe plutôt que dans son propre fichier. Vous pouvez, si vous le souhaitez, créer un système de journalisation plus compliqué en faisant interagir DebugLog avec des objets Objective-C normaux. Par exemple, vous pouvez avoir une classe de journalisation qui écrit dans son propre fichier journal (ou base de données) et inclut un argument de priorité que vous pouvez définir au moment de l'exécution, de sorte que les messages de débogage ne sont pas affichés dans votre version, mais les messages d'erreur sont ( si vous faisiez cela, vous pourriez créer DebugLog (), WarningLog (), etc.).

Oh, et gardez à l'esprit #define DEBUG_MODE peut être réutilisé à différents endroits de votre application. Par exemple, dans mon application, je l'utilise pour désactiver les vérifications de clé de licence et autoriser l'application à s'exécuter uniquement avant une certaine date. Cela me permet de distribuer une copie bêta entièrement fonctionnelle et limitée dans le temps avec un minimum d'effort de ma part.

196
Marc Charbonneau

Mettez ces 3 lignes à la fin du fichier -prefix.pch:

#ifndef DEBUG
  #define NSLog(...) /* suppress NSLog when in release mode */
#endif

Vous n'avez pas besoin de définir quoi que ce soit dans votre projet, car DEBUG est défini par défaut dans votre paramètre de génération lorsque vous créez votre projet.

77
roel

Les appels NSLog peuvent être laissés dans le code de production, mais ne doivent être présents que pour des cas vraiment exceptionnels, ou des informations souhaitées qui seront enregistrées dans le journal système.

Les applications qui jonchent le journal du système sont ennuyeuses et apparaissent comme non professionnelles.

25
Matthew Schinckel

Je ne peux pas commenter réponse de Marc Charbonnea , donc je posterai ceci comme réponse.

Outre l'ajout de la macro à votre en-tête précompilé, vous pouvez utiliser les configurations de génération Target pour contrôler la définition (ou l'absence de définition) du DEBUG_MODE.

Si vous sélectionnez " Debug " configuration active, DEBUG_MODE sera défini et la macro se développera jusqu'à la définition complète de NSLog.

La sélection de la configuration active " Release " ne définira pas DEBUG_MODE et votre NSLogging est omis de la version.

Pas:

  • Cible> Obtenir des informations
  • Onglet Build
  • Recherchez "Macros de préprocesseur" (ou GCC_PREPROCESSOR_DEFINITIONS)
  • Sélectionnez la configuration: Débogage
  • Modifier la définition à ce niveau
  • Ajouter DEBUG_MODE=1
  • Sélectionnez la configuration: Release
  • confirmez DEBUG_MODE n'est pas défini dans GCC_PREPROCESSOR_DEFINITIONS

si vous omettez le caractère '=' dans la définition, vous obtiendrez une erreur du préprocesseur

Collez également ce commentaire (illustré ci-dessous) au-dessus de la définition de la macro pour vous rappeler où le DEBUG_MACRO define vient de;)

// Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS
// Configuration = Release: <empty>
//               = Debug:   DEBUG_MODE=1
23
ohhorob

MODIFIER: La méthode publiée par Marc Charbonnea , et portée à mon attention par sho , est bien meilleure que celle-ci.

J'ai supprimé la partie de ma réponse qui suggérait d'utiliser une fonction vide pour désactiver la journalisation lorsque le mode de débogage est désactivé. La partie qui traite de la définition d'une macro de préprocesseur automatique est toujours pertinente, elle le reste donc. J'ai également édité le nom de la macro du préprocesseur afin qu'il corresponde mieux à la réponse de Marc Charbonneau.


Pour obtenir le comportement automatique (et attendu) dans Xcode:

Dans les paramètres du projet, allez dans l'onglet "Build" et sélectionnez la configuration "Debug". Recherchez la section "Macros de préprocesseur" et ajoutez une macro nommée DEBUG_MODE.

...

MODIFIER: Voir réponse de Marc Charbonnea pour savoir comment activer et désactiver la journalisation avec le DEBUG_MODE macro.

11
e.James

Je suis d'accord avec Matthew. Il n'y a rien de mal avec NSLog dans le code de production. En fait, cela peut être utile à l'utilisateur. Cela dit, si la seule raison pour laquelle vous utilisez NSLog est d'aider au débogage, alors, oui, cela devrait être supprimé avant la publication.

De plus, puisque vous avez marqué cela comme une question sur l'iPhone, NSLog prend des ressources, ce dont l'iPhone a peu de choses. Si vous êtes NSLogging n'importe quoi sur l'iPhone, cela prend du temps au processeur de votre application. Fais-en bon usage.

7
August

La simple vérité est que NSLog est tout simplement lent.

Mais pourquoi? Pour répondre à cette question, découvrons ce que fait NSLog, puis comment il le fait.

Que fait NSLog exactement?

NSLog fait 2 choses:

Il écrit des messages de journal dans la fonction Apple System Logging (asl). Cela permet aux messages de journal de s'afficher dans Console.app. Il vérifie également si le flux stderr de l'application va vers un terminal (par exemple, lorsque l'application est exécutée via Xcode.) Dans l'affirmative, elle écrit le message de journal dans stderr (afin qu'il s'affiche dans la console Xcode).

Écrire sur STDERR ne semble pas difficile. Cela peut être accompli avec fprintf et la référence du descripteur de fichier stderr. Mais qu'en est-il de l'asl?

La meilleure documentation que j'ai trouvée sur ASL est un article de blog en 10 parties de Peter Hosey: link

Sans entrer dans trop de détails, le point fort (en ce qui concerne les performances) est le suivant:

Pour envoyer un message de journal à l'installation ASL, vous ouvrez essentiellement une connexion client au démon ASL et envoyez le message. MAIS - chaque thread doit utiliser une connexion client distincte. Ainsi, pour être sûr du thread, chaque fois que NSLog est appelé, il ouvre une nouvelle connexion client asl, envoie le message, puis ferme la connexion.

Des ressources ont pu être trouvées ici & ici .

4
Andrew

Du point de vue de la sécurité, cela dépend de ce qui est enregistré. Si NSLog (ou d'autres enregistreurs) écrit des informations sensibles, vous devez supprimer l'enregistreur dans le code de production.

Du point de vue de l'audit, l'auditeur ne souhaite pas examiner chaque utilisation de NSLog pour s'assurer qu'il ne consigne pas les informations sensibles. Il/elle vous dira simplement de retirer l'enregistreur.

Je travaille avec les deux groupes. Nous auditons le code, écrivons les guides de codage, etc. Notre guide requiert que la journalisation soit désactivée dans le code de production. Les équipes internes savent donc ne pas l'essayer;)

Nous rejetterons également une application externe qui se connecte en production, car nous ne voulons pas accepter le risque associé à une fuite accidentelle d'informations sensibles. Peu nous importe ce que le développeur nous dit. Cela ne vaut tout simplement pas notre temps pour enquêter.

Et rappelez-vous, nous définissons "sensible", et non le développeur;)

Je perçois également une application qui effectue beaucoup de journalisation comme une application prête à imploser. Il y a une raison pour laquelle une journalisation est effectuée/nécessaire, et ce n'est généralement pas la stabilité. C'est là-haut avec des threads de "chien de garde" qui redémarrent les services bloqués.

Si vous n'avez jamais effectué d'examen de l'architecture de sécurité (SecArch), voici le genre de choses que nous examinons.

2
jww

Comme indiqué dans d'autres réponses, vous pouvez utiliser un #define pour modifier si NSLog est utilisé ou non au moment de la compilation.

Cependant, un moyen plus flexible consiste à utiliser une bibliothèque de journalisation comme Cocoa Lumberjack qui vous permet de modifier si quelque chose est également journalisé lors de l'exécution.

Dans votre code, remplacez NSLog par DDLogVerbose ou DDLogError, etc., ajoutez un #import pour les définitions de macro, etc. et configurez les enregistreurs, souvent dans la méthode applicationDidFinishLaunching.

Pour avoir le même effet que NSLog, le code de configuration est

[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];
2
Mark

Gardez à l'esprit que NSLogs peut ralentir l'interface utilisateur/thread principal. Il est préférable de les supprimer des versions de version, sauf si cela est absolument nécessaire.

1
psy

Vous ne devriez pas être verbeux inutilement avec printf ou NSLog dans le code de version. Essayez uniquement de faire un printf ou NSLog si l'application a quelque chose de mal qui lui arrive, I.E. une erreur irrécupérable.

1
MaddTheSane

Je recommande fortement d'utiliser TestFlight pour la journalisation (gratuit). Leur méthode remplacera NSLog (à l'aide d'une macro) et vous permettra d'activer/désactiver la journalisation sur leur serveur, Apple Journal système et journal STDERR, pour tous vos appels existants à NSLog. La bonne chose à ce sujet, vous pouvez toujours consulter vos messages de journal pour les applications déployées sur les testeurs et les applications déployées dans l'App Store, sans que les journaux n'apparaissent dans le journal système de l'utilisateur. Le meilleur des deux mondes.

0
Joel