iOS 10 / Xcode 8 设备上的 NSLog 似乎被截断了?为什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39584707/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
NSLog on devices in iOS 10 / Xcode 8 seems to truncate? Why?
提问by iPeta
采纳答案by xfdai
A temporary solution, just redefine all NSLOG
to printf
in a global header file.
一个临时解决方案,只需在全局头文件中重新定义 allNSLOG
即可printf
。
#define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
回答by Elist
In iOS 10 & Xcode 8, Apple switched from the good old ASL
(Apple System Log) to a new logging system called Unified logging
. NSLog
calls are in fact delegating to new os_log
API's. (source: https://developer.apple.com/reference/os/logging):
在 iOS 10 和 Xcode 8 中,Apple 从旧的ASL
(Apple System Log)切换到了一个名为Unified logging
. NSLog
调用实际上是委托给新的os_log
API。(来源:https: //developer.apple.com/reference/os/logging):
Important
Unified logging is available in iOS 10.0 and later, macOS 10.12 and later, tvOS 10.0 and later, and watchOS 3.0 and later, and supersedes ASL (Apple System Logger) and the Syslog APIs. Historically, log messages were written to specific locations on disk, such as /etc/system.log. The unified logging system stores messages in memory and in a data store, rather than writing to text-based log files.
重要的
统一日志记录适用于 iOS 10.0 及更高版本、macOS 10.12 及更高版本、tvOS 10.0 及更高版本以及 watchOS 3.0 及更高版本,并取代 ASL(Apple System Logger)和 Syslog API。历史上,日志消息被写入磁盘上的特定位置,例如 /etc/system.log。统一日志系统将消息存储在内存和数据存储中,而不是写入基于文本的日志文件。
And
和
Important
Log message lines greater than the system's maximum message length are truncated when stored by the logging system. Complete messages are visible when using the log command-line tool to view a live stream of activity. Bear in mind, however, that streaming log data is an expensive activity.
重要的
当日志系统存储时,大于系统最大消息长度的日志消息行将被截断。使用日志命令行工具查看活动的实时流时,可以看到完整的消息。但是请记住,流式传输日志数据是一项昂贵的活动。
The "system's maximum message length" limitation is revealed in the SDK's header to be 1024 characters for formatted variables, as noted by @Hot_Leaks (source: <os/log.h>
):
正如@Hot_Leaks(来源:)所指出的,“系统的最大消息长度”限制在 SDK 的标头中显示为 1024 个字符的格式化变量<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__)
Since the buffer size limitation seems to be hard-coded into libsystem_trace.dylib
, I don't see a way around it but to print a string literal instead of a formatted variable (%@
), or split the formatted string variables to < 1024 strings.
由于缓冲区大小限制似乎被硬编码到 中libsystem_trace.dylib
,我没有找到解决方法,只能打印字符串文字而不是格式化变量 ( %@
),或者将格式化字符串变量拆分为 < 1024 个字符串。
printf
will work during debugging, since the debugger (Xcode) shows the process's out / error streams, but it will not be sent to the device log itself. This means that xfdai's solution will not help you when using other log applications such as macOS's Console
App, or with issue's emerging on non-debugged applications (such as AppStore application running on customer's device).
printf
将在调试期间工作,因为调试器 (Xcode) 显示进程的输出/错误流,但不会发送到设备日志本身。这意味着 xfdai 的解决方案在使用其他日志应用程序(例如 macOS 的Console
App)时,或在未调试的应用程序(例如在客户设备上运行的 AppStore 应用程序)上出现问题时,将无法帮助您。
Extending xfdai's answer to deployed applications
将 xfdai 的答案扩展到已部署的应用程序
In deployed applications / non-debug builds, there's no way to see either NSLog
s or printf
s.
在已部署的应用程序/非调试版本中,无法看到NSLog
s 或printf
s。
The only way to have messages printed directly to the device log (which can be accessed using Xcode -> Window -> Devices, mac's Console App or 3rd party utilities such as deviceconsole) is calling os_log
API's (which is the successor of ASL
used since iOS 10).
将消息直接打印到设备日志的唯一方法(可以使用 Xcode -> Window -> Devices、mac 的控制台应用程序或第 3 方实用程序(例如deviceconsole)进行访问)是调用os_log
API(这是ASL
自 iOS 10 以来使用的继承者))。
Here's a global header file I'm using to redefine NSLog
as a call to _os_log_internal
on 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 */
回答by Tamás Cseh
It's an iOS 10 only "feature". Use this instead:
这是 iOS 10 唯一的“功能”。改用这个:
printf("%s", [logString UTF8String]);
回答by Leslie Godwin
On iOS 10:
在 iOS 10 上:
printf()
works inside Xcode's console but doesn't work on the device's console log.NSLog
truncates in both places.
printf()
在 Xcode 的控制台内工作,但不适用于设备的控制台日志。NSLog
在两个地方截断。
What I'm doing for now is splitting my NSLog
strings into lines and logging each line individually.
我现在正在做的是将我的NSLog
字符串分成几行并单独记录每一行。
- (void) logString: (NSString *) string
{
for (NSString *line in [string componentsSeparatedByCharactersInSet: [NSCharacterSet newlineCharacterSet]])
{
NSLog(@"%@", line);
}
}
This works on the console, but isn't easy to read.
这适用于控制台,但不容易阅读。
回答by Andy Vene
You can use this method. Split every 800 chars. Or can be set. NSLOG i think truncate every 1000 chars. If string is less than 800 will use a simple NSLog. This is useful for Json long strings and uses the console. printf uses Xcode debug window not the console.
您可以使用此方法。每 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);
}
}
回答by catanore
This doesn't provide a nice output, but prints all necessary information for long logs, even on console.
这不会提供很好的输出,但会打印长日志的所有必要信息,即使在控制台上也是如此。
func Log(_ logString: String?) {
if logString?.isEmpty ?? false { return }
NSLog("%@", logString!)
Log(String(logString!.dropFirst(1024)))
}
回答by Giang
from @xfdai answer, add pretty function and line
来自@xfdai 的回答,添加漂亮的功能和线条
#define NSLog(FORMAT, ...) printf("%s:%d %s\n", __PRETTY_FUNCTION__,__LINE__,[[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String])
with date
有日期
#define NSLog(FORMAT, ...) printf("%s %s:%d %s\n", [[[NSDate date] description] UTF8String],__PRETTY_FUNCTION__,__LINE__,[[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String])