如何在CocoaLumberJack从Swift实现自定义日志级别?



我在一个Swift项目中使用CocoaLumberjack。我想实现自定义日志级别/标志,因为我想使用6而不是默认的5,并且更喜欢不同的名称。

这样做的文档没有帮助。它只是Objective-C的一个解决方案。

事实上,DDLogFlag被定义为NS_OPTIONS意味着我实际上可以简单地忽略这里的预定义值,创建我自己的常量,并编写一些包装代码来从一个转换到另一个。

然而,DDLogLevel被定义为NS_ENUM,这意味着Swift不会很高兴我试图实例化一些东西说0b111111,这不是枚举中存在的值。如果它是NS_OPTIONS,就像DDLogFlag一样,我可以忽略库中已有的定义,并使用我想要的任何有效的UInt值。

据我所知,我只需要写一些Objective-C代码来定义我自己的DDLogLevel,DDLogFlag的替代品,并编写一个自定义函数来传递并访问DDLogMessage上的这些属性。但这感觉很糟糕。

我如何在CocoaLumberjack中使用我自己的自定义日志级别?

这确实只可能在Objective-C现在-也只有#define日志宏。即使在那时,我也能想象"现代"ObjC编译器会对传递给DDLogMessage的类型发出警告。

这里的文档确实有点过时了,并且源于Objective-C更接近C的时代,而现在它更接近Swift…: -)

然而,最后DDLogLevelDDLogFlag都被存储为NSUInteger。这意味着理论上可以取任何NSUInteger值(Swift中也称为UInt)。

要定义自己的级别,只需创建一个enum MyLogLevel: UInt { /*...*/ },然后编写自己的日志记录函数。这些函数实际上可以转发到现有的函数:

extension DDLogFlag {
public static let fatal = DDLogFlag(rawValue: 0x0001)
public static let failure = DDLogFlag(rawValue: 0x0010)
}
public enum MyLogLevel: UInt {
case fatal = 0x0001
case failure = 0x0011
}
extension MyLogLevel {
public static var defaultLevel: MyLogLevel = .fatal
}
@inlinable
public func LogFatal(_ message: @autoclosure () -> Any,
level: MyLogLevel = .defaultLevel,
context: Int = 0,
file: StaticString = #file,
function: StaticString = #function,
line: UInt = #line,
tag: Any? = nil,
asynchronous async: Bool = asyncLoggingEnabled,
ddlog: DDLog = .sharedInstance) {
_DDLogMessage(message(), level: unsafeBitCast(level, to: DDLogLevel.self), flag: .fatal, context: context, file: file, function: function, line: line, tag: tag, asynchronous: async, ddlog: ddlog)
}

unsafeBitCast在这里工作,因为最终它只是一个UInt_DDLogMessage不切换电平,而是对flag进行位掩码检查。


免责声明:我自己就是一个CocoaLumberjack的维护者。


我们不建议在Swift中使用自定义日志级别。它没有太多的好处,像swift-log这样的日志框架也使用预定义的日志级别。

然而,我个人也可以想象用NS_OPTIONS而不是NS_ENUM来声明DDLogLevel。Swift覆盖也使用可扩展的OSLogType。如果这是您想看到的东西,请打开PR以便我们与团队讨论。我们需要在API兼容性上小心一点,但就像我说的,这是完全可行的。

旁注:我可以问一下你需要自定义级别吗?

最新更新