74 votes

NSLog sur les appareils sous iOS 10 / Xcode 8 semble être tronqué? Pourquoi?

Pourquoi la sortie de la console est-elle incomplète dans Xcode 8 / iOS 10?

entrez la description de l'image ici

74voto

xiaofan Points 1

Une solution temporaire, il suffit de redéfinir tous les NSLOG à printf dans un fichier d’en-tête global.

 #define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
 

50voto

Elist Points 960

Dans iOS 10 & Xcode 8, Apple est passé de la bonne vieille ASL (Pomme Journal Système) à un nouveau système d'enregistrement appelé Unified logging. NSLog des appels sont en fait de déléguer à nouveau os_log de l'API. (source: https://developer.apple.com/reference/os/logging):

Important

Unifiée enregistrement est disponible dans iOS 10.0, et plus tard, macOS et 10.12 plus tard, tvOS 10.0, et plus tard, et watchOS 3.0 et versions ultérieures, et annule et remplace ASL (Apple Enregistreur du Système) et le Syslog Api. Historiquement, journal les messages ont été écrits à des endroits précis sur le disque, telles que /etc/system.journal. Le unifiée, système d'enregistrement stocke les messages dans la mémoire et dans une banque de données, plutôt que d'écrire un texte basé sur les fichiers de log.

Et

Important

Message du journal des lignes de plus que le système du maximum de la longueur du message est tronqué quand stockées par le système de journalisation. Messages complets sont visible lors de l'utilisation du journal d'outil de ligne de commande pour afficher un flux en direct de de l'activité. Gardez à l'esprit, cependant, que le streaming de données de journal est un activité coûteuse.

Le "système de la longueur maximale de la" limitation est révélé dans le SDK de l'en-tête de 1024 caractères formatée variables, comme le fait remarquer @Hot_Leaks (source: <os/log.h>):

/*!  
 * @function os_log  
 *   
 * ...  
 *  
 * There is a physical cap of 1024 bytes per log line for dynamic content,  
 * such as %s and %@, that can be written to the persistence store.  
 * All content exceeding the limit will be truncated before it is  
 * written to disk.  
 *
 * ... 
 *
 */  
#define os_log(log, format, ...)    os_log_with_type(log, OS_LOG_TYPE_DEFAULT, format, ##__VA_ARGS__)

Puisque la taille de la mémoire tampon limitation semble être codées en dur dans l' libsystem_trace.dylib, je ne vois pas un moyen de contourner cela, mais pour imprimer une chaîne littérale au lieu de forme variable (%@), ou de scission de la chaîne mise en forme des variables < 1024 cordes.

printf pendant le débogage, depuis le débogueur (Xcode) montre le processus de sortie / erreur de cours d'eau, mais il ne sera pas envoyé à l'appareil de journal lui-même. Cela signifie que xfdai la solution ne sera pas vous aider lors de l'utilisation d'autres journaux des applications telles que macOS est Console App, ou avec la question du jour sur la non-corrigés des applications (telles que l'AppStore l'application en cours d'exécution sur l'appareil du client).


L'extension de xfdai de réponse pour les applications déployées

Dans les applications déployées / non-debug, il n'y a pas moyen de voir soit NSLogs ou printfs.

La seule façon d'avoir des messages d'imprimer directement sur le périphérique de journal (qui peut être consulté à l'aide de Xcode -> Fenêtre -> Appareils, mac la Console de l'Application ou de la 3e partie des utilitaires tels que deviceconsole) appelle os_log l'API (qui est le successeur de l' ASL utilisé depuis iOS 10).

Voici un mondial de l'en-tête de fichier que j'utilise pour redéfinir NSLog comme un appel à l' _os_log_internal sur iOS 10:

#ifndef PrefixHeader_pch
#define PrefixHeader_pch

#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif

#import <os/object.h>
#import <os/activity.h>

/*
 *  System Versioning Preprocessor Macros
 */

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

// os_log is only supported when compiling with Xcode 8.
// Check if iOS version > 10 and the _os_log_internal symbol exists,
// load it dynamically and call it.
// Definitions extracted from #import <os/log.h>

#if OS_OBJECT_SWIFT3
OS_OBJECT_DECL_SWIFT(os_log);
#elif OS_OBJECT_USE_OBJC
OS_OBJECT_DECL(os_log);
#else
typedef struct os_log_s *os_log_t;
#endif /* OS_OBJECT_USE_OBJC */

extern struct os_log_s _os_log_default;

extern __attribute__((weak)) void _os_log_internal(void *dso, os_log_t log, int type, const char *message, ...);

// In iOS 10 NSLog only shows in device log when debugging from Xcode:
#define NSLog(FORMAT, ...) \
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {\
    void(*ptr_os_log_internal)(void *, __strong os_log_t, int, const char *, ...) = _os_log_internal;\
    if (ptr_os_log_internal != NULL) {\
        _Pragma("clang diagnostic push")\
        _Pragma("clang diagnostic error \"-Wformat\"")\
        _os_log_internal(&__dso_handle, OS_OBJECT_GLOBAL_OBJECT(os_log_t, _os_log_default), 0x00, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);\
        _Pragma("clang diagnostic pop")\
    } else {\
        NSLog(FORMAT, ##__VA_ARGS__);\
    }\
} else {\
    NSLog(FORMAT, ##__VA_ARGS__);\
}

#endif /* PrefixHeader_pch */

10voto

Cseh Tamás Points 916

C'est une "fonctionnalité" iOS 10 uniquement. Utilisez ceci à la place:

 printf("%s", [logString UTF8String]);
 

3voto

Andy Vene Points 21

Vous pouvez utiliser cette méthode. Fractionner tous les 800 caractères. Ou peut être réglé. NSLOG je pense tronquer tous les 1000 caractères. Si string est inférieur à 800, un simple NSLog sera utilisé. Ceci est utile pour les chaînes longues Json et utilise la console. printf utilise la fenêtre de débogage Xcode et non la console.

     -(void) JSLog:(NSString*)logString{

            int stepLog = 800;
            NSInteger strLen = [@([logString length]) integerValue];
            NSInteger countInt = strLen / stepLog;

            if (strLen > stepLog) {
            for (int i=1; i <= countInt; i++) {
                NSString *character = [logString substringWithRange:NSMakeRange((i*stepLog)-stepLog, stepLog)];
                NSLog(@"%@", character);

            }
            NSString *character = [logString substringWithRange:NSMakeRange((countInt*stepLog), strLen-(countInt*stepLog))];
            NSLog(@"%@", character);
            } else {

            NSLog(@"%@", logString);
            }

    }
 

2voto

Leslie Godwin Points 258

Sur iOS 10:

  1. printf() fonctionne dans la console de Xcode mais pas dans le journal de la console du périphérique.
  2. NSLog tronque aux deux endroits.

Ce que je fais pour l'instant est de scinder mes chaînes NSLog en lignes et d'enregistrer chaque ligne individuellement.

 - (void) logString: (NSString *) string
{
    for (NSString *line in [string componentsSeparatedByCharactersInSet: [NSCharacterSet newlineCharacterSet]])
    {
        NSLog(@"%@", line);
    }
}
 

Cela fonctionne sur la console, mais n'est pas facile à lire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X