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

Почему вывод консоли отображается неполным в Xcode 8/iOS 10?

введите описание изображения здесь

Ответ 1

Временное решение, просто переопределите все NSLOG - printf в глобальном файле заголовка.

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

Ответ 2

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

Внимание!

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

и

Внимание!

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

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

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

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


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

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

Единственный способ отправить сообщения непосредственно в журнал устройства (к которому можно получить доступ с помощью Xcode → Window → Devices, Mac Console App или сторонних утилит, таких как 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 */

Ответ 3

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

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

Ответ 4

В iOS 10:

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

То, что я делаю сейчас, это разбиение строк NSLog на строки и запись каждой строки по отдельности.

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

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

Ответ 5

Вы можете использовать этот метод. Разделить каждые 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);
            }

    }