采用os_log API同时保持向后兼容性

时间:2017-07-10 21:53:20

标签: ios objective-c macos logging macros

我正在尝试将新的日志记录和活动跟踪API的支持添加到库中,以便为尚未采用最新版本操作系统(iOS或macOS)的库的用户保持向后兼容性。我正在为每个级别的日志记录定义自定义日志记录宏,然后对于较旧的操作系统,则回退到NSLog。我有这个问题,有一个问题。

如果您希望它们显示在日志输出中,则新API要求您将任何非常量非标量值标记为显式public。这就是我的宏的调用:

UZKLogInfo("Reading file %{public}@ from archive", fileName);

这适用于包含os_log的SDK(例如iOS 10.0或更高版本),但是当我使用早期版本编译以便我的宏回退到NSLog时,我收到编译器警告:

  

在os_log()/ os_trace()之外使用'public'格式说明符注释

打印的日志行如下所示:

Reading file <decode: missing data> from archive

这是我的宏定义的简化版本(仅包括info定义并简化了条件:

#if UNIFIED_LOGGING_SUPPORTED
    @import os.log;

    #define UZKLogInfo(format, ...) os_log_info(OS_LOG_DEFAULT, format, ##__VA_ARGS__);
#else // Fall back to regular NSLog
    #define UZKLogInfo(format, ...) NSLog(@format, ##__VA_ARGS__);
#endif

有没有办法在后备情况下从format删除“{public}”文本(某种字符串替换?)?或者是否有另一种方法来支持旧的和新的API而不放弃我在日志中总是显示的信息级别?我需要使用宏(根据last year's WWDC session on the topic,否则我将丢失呼叫站点元数据。

1 个答案:

答案 0 :(得分:2)

我选择在宏中执行NSString替换,并将编译器警告作为其中的一部分进行抑制,因此可以为每一行完成,而不是对整个文件或项目进行全局操作。它看起来像这样:

#if UNIFIED_LOGGING_SUPPORTED
    @import os.log;

    #define UZKLogInfo(format, ...) os_log_info(OS_LOG_DEFAULT, format, ##__VA_ARGS__);

#else // Fall back to regular NSLog

    #define _removeLogFormatTokens(format) [@format stringByReplacingOccurrencesOfString:@"{public}" withString:@""]
    #define _stringify(a) #a
    #define _nsLogWithoutWarnings(format, ...) \
        _Pragma( _stringify( clang diagnostic push ) ) \
        _Pragma( _stringify( clang diagnostic ignored "-Wformat-nonliteral" ) ) \
        _Pragma( _stringify( clang diagnostic ignored "-Wformat-security" ) ) \
        NSLog(_removeLogFormatTokens(format), ##__VA_ARGS__); \
        _Pragma( _stringify( clang diagnostic pop ) )

    #define UZKLogInfo(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__);
#endif

它的召唤如下:

UZKLogInfo("Message: %@", anObjectToLog);