简体   繁体   English

如何禁用日志记录?

[英]How to disable logging?

I have an app that is making use of UITextChecker class provided by Apple. 我有一个使用Apple提供的UITextChecker类的应用程序。 This class has a following bug: If the iOS device is offline (expected to be often for my app) each time I call some of UITextChecker s methods it logs following to console: 此类有以下错误:如果iOS设备每次我调用UITextChecker的某些方法都脱机时(预期对于我的应用程序来说经常如此),它将记录到控制台:

2016-03-08 23:48:02.119 HereIsMyAppName [4524:469877] UITextChecker sent string:isExemptFromTextCheckerWithCompletionHandler: to com.apple.TextInput.rdt but received error Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.TextInput.rdt was invalidated."

I do not want to have logs spammed by this messages. 我不希望此邮件发送垃圾邮件。 Is there a way to disable logging from code? 有没有办法禁用代码日志记录? I would disable logging before call to any of UITextChecker s methods and reenable it afterwards. 我将在调用UITextChecker的任何方法之前禁用日志记录,然后再启用它。 Or is there perhaps any way how to disable logging selectively per class (event if it is foundation class not mine)? 还是有什么办法可以有选择地禁用每个类的日志记录(如果是基础类而不是我的,则会发生事件)? Or any other solution? 或其他解决方案?

Warning : This answer uses the private-yet-sort-of-documented Cocoa C functions _NSSetLogCStringFunction() and _NSLogCStringFunction() . 警告 :此答案使用了尚未公开的可可C函数_NSSetLogCStringFunction()_NSLogCStringFunction()

_NSSetLogCStringFunction() is an interface created by Apple to handle the implementation function for NSLog . _NSSetLogCStringFunction()是Apple创建的用于处理NSLog的实现功能的接口。 It was initially exposed for WebObjects to hook into NSLog statements on Windows machines, but still exists in the iOS and OS X APIs today. WebObjects最初暴露给Windows机器上的NSLog语句,但如今仍存在于iOS和OS X API中。 It is documented in this support article. 支持文章中对此进行了记录。

The function takes in a function pointer with the arguments const char* message , the string to log, unsigned length , the length of the message, and a BOOL withSysLogBanner which toggles the standard logging banner. 该函数接收带有参数const char* message ,要记录的字符串, unsigned length ,消息的长度以及带有BOOL withSysLogBannerBOOL withSysLogBanner的函数指针,该BOOL withSysLogBanner切换标准日志记录BOOL withSysLogBanner的信息。 If we create our own hook function for logging that doesn't actually do anything (an empty implementation rather than calling fprintf like NSLog does behind-the-scenes), we can effectively disable all logging for your application. 如果我们创建自己的钩子函数来进行日志记录,而实际上它并没有做任何事情(一个空的实现,而不是像NSLog那样在幕后调用fprintf ),那么我们可以有效地禁用应用程序的所有日志记录。

Objective-C Example (or Swift with bridging header): Objective-C示例(或带有桥接头的Swift):

extern void _NSSetLogCStringFunction(void(*)(const char*, unsigned, BOOL));

static void hookFunc(const char* message, unsigned length, BOOL withSysLogBanner) { /* Empty */ }

// Later in your application

_NSSetLogCStringFunction(hookFunc);

NSLog(@"Hello _NSSetLogCStringFunction!\n\n");  // observe this isn't logged

An example implementation of this can be found in YILogHook , which provides an interface to add an array of blocks to any NSLog statement (write to file, etc). 可以在YILogHook中找到此示例的实现,它提供了一个接口,用于将块数组添加到任何NSLog语句(写入文件等)。

Pure Swift Example: 纯Swift示例:

@asmname("_NSSetLogCStringFunction") // NOTE: As of Swift 2.2 @asmname has been renamed to @_silgen_name
func _NSSetLogCStringFunction(_: ((UnsafePointer<Int8>, UInt32, Bool) -> Void)) -> Void

func hookFunc(message: UnsafePointer<Int8>, _ length: UInt32, _ withSysLogBanner: Bool) -> Void { /* Empty */ }

_NSSetLogCStringFunction(hookFunc)

NSLog("Hello _NSSetLogCStringFunction!\n\n");  // observe this isn't logged

In Swift, you can also chose to ignore all of the block parameters without using hookFunc like so: 在Swift中,您还可以选择忽略所有块参数,而无需使用hookFunc如下所示:

_NSSetLogCStringFunction { _,_,_ in }

To turn logging back on using Objective-C, just pass in NULL as the function pointer: 要使用Objective-C重新登录,只需传入NULL作为函数指针:

_NSSetLogCStringFunction(NULL);

With Swift things are a little different, since the compiler will complain about a type mismatch if we try to pass in nil or a nil pointer ( NULL is unavailable in Swift). 与Swift有所不同,因为如果我们尝试传递nilnil指针,编译器将抱怨类型不匹配(在Swift中NULL不可用)。 To solve this, we need to access another system function, _NSLogCStringFunction , to get a pointer to the default logging implementation, retain that reference while logging is disabled, and set the reference back when we want to turn logging back on. 为了解决这个问题,我们需要访问另一个系统函数_NSLogCStringFunction ,以获取指向默认日志记录实现的指针,在禁用日志记录时保留该引用,并在希望重新打开日志记录时将其设置回。

I've cleaned up the Swift implementation of this by adding a NSLogCStringFunc typedef : 我通过添加NSLogCStringFunc typedef清理了Swift的实现:

/// Represents the C function signature used under-the-hood by NSLog
typealias NSLogCStringFunc = (UnsafePointer<Int8>, UInt32, Bool) -> Void

/// Sets the C function used by NSLog
@_silgen_name("_NSSetLogCStringFunction") // NOTE: As of Swift 2.2 @asmname has been renamed to @_silgen_name
func _NSSetLogCStringFunction(_: NSLogCStringFunc) -> Void

/// Retrieves the current C function used by NSLog
@_silgen_name("_NSLogCStringFunction")
func _NSLogCStringFunction() -> NSLogCStringFunc

let logFunc = _NSLogCStringFunction() // get function pointer to the system log function before we override it

_NSSetLogCStringFunction { (_, _, _) in } // set our own log function to do nothing in an anonymous closure

NSLog("Observe this isn't logged.");

_NSSetLogCStringFunction(logFunc) // switch back to the system log function

NSLog("Observe this is logged.")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM