NSLog на устройствах в iOS 10 / Xcode 8 кажется усеченным? Причина?


Почему вывод консоли показывает неполный в Xcode 8 / iOS 10?

5 59

5 ответов:

временное решение, просто пересмотреть все NSLOG to printf в глобальном заголовочном файле.

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

в iOS 10 и Xcode 8 Apple переключилась с старого доброго ASL (системный журнал Apple) в новую систему ведения журнала под названием Unified logging. NSLog вызовы фактически делегируя новый os_log API. (источник:https://developer.apple.com/reference/os/logging):

важно

единое ведение журнала доступно в iOS 10.0 и более поздних версиях, macOS 10.12 и позже, tvOS 10.0 и позже, и watchOS 3.0 и позже, и заменяет ASL (системный регистратор Apple) и API системного журнала. Исторически журнал сообщения записывались в определенные места на диске, например системы /и т. д./.бревно. Единая система ведения журнала хранит сообщения в памяти и в хранилище данных, а не для записи в текстовые файлы журналов.

и

важно

строки сообщений журнала, превышающие максимальную длину сообщения системы, усекаются при хранении системой ведения журнала. Полные сообщения являются видимый при использовании инструмента командной строки журнала для просмотра живого потока деятельность. Однако имейте в виду, что потоковые данные журнала являются дорогостоящая деятельность.

ограничение "максимальная длина сообщения системы" показано в заголовке SDK, чтобы быть 1024 символов для форматированных переменных, как отмечено @Hot_Leaks (источник:<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__)

поскольку ограничение размера буфера, похоже, жестко закодировано в libsystem_trace.dylib, Я не вижу пути вокруг него, но для печати строкового литерала вместо форматированной переменной (%@), или разбить форматированные строковые переменные на

printf будет работать во время отладки, так как отладчик (Xcode) показывает потоки out / error процесса, но он не будет отправлен в журнал самого устройства. Это означает, что решение xfdai не поможет вам при использовании других приложений журнала, таких как macOS Console приложение, или с проблемой, возникающей в не отлаженных приложениях (таких как Приложение AppStore работает на устройстве клиента).


расширение ответа xfdai на развернутые приложения

в развернутых приложений / не-отладочные построения, нет никакого способа, чтобы увидеть, как NSLogили printf s.

единственный способ печати сообщений непосредственно в журнал устройств (доступ к которому можно получить с помощью Xcode - > Window - > Devices, консольного приложения mac или сторонних утилит, таких как deviceconsole) является звоню os_log API (который является преемником ASL используется с iOS 10).

вот глобальный файл заголовка, который я использую для переопределения NSLog как позвонить _os_log_internal на 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 */

это iOS 10 только "функция". Используйте этот код:

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

на iOS 10:

  1. printf() работает внутри консоли Xcode, но не работает в журнале консоли устройства.
  2. NSLog усекает в обоих местах.

то, что я сейчас делаю, это расщепление моего NSLog строки в строки и протоколирование каждой строки по отдельности.

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

это работает в консоли, но не легко читать.

вы можете использовать этот метод. Разделите каждые 800 символов. Или может быть установлен. NSLOG я думаю усечь каждые 1000 символов. Если строка меньше 800 будет использовать простой NSLog. Это полезно для длинных строк JSON и использует консоль. printf использует окно отладки Xcode, а не консоль.

    -(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);
            }

    }