如何在Swift中为CocoaLumberJack实现自定义日志级别?
Swift环境下CocoaLumberjack自定义日志级别方案
核心思路
绕开库预定义的DDLogLevel枚举限制,基于可自由扩展的DDLogFlag实现自定义级别,自己封装打印入口和过滤逻辑,不需要修改库源码或者添加OC桥接代码。
具体实现步骤
1. 定义自定义日志常量
首先扩展DDLogFlag定义你需要的6个级别对应的标记,同时定义对应的级别名称和开启组合:
import CocoaLumberjack extension DDLogFlag { // 按权重从低到高定义6个自定义flag,每一个对应2的n次方 static let verbose = Self(rawValue: 1 << 0) static let debug = Self(rawValue: 1 << 1) static let info = Self(rawValue: 1 << 2) static let warn = Self(rawValue: 1 << 3) static let error = Self(rawValue: 1 << 4) static let fatal = Self(rawValue: 1 << 5) // 新增的第6个级别 } // 自定义日志级别组合,对应你需要开启的日志范围 struct CustomLogLevel { static let off: UInt = 0 static let fatal: UInt = UInt(DDLogFlag.fatal.rawValue) static let error: UInt = fatal | UInt(DDLogFlag.error.rawValue) static let warn: UInt = error | UInt(DDLogFlag.warn.rawValue) static let info: UInt = warn | UInt(DDLogFlag.info.rawValue) static let debug: UInt = info | UInt(DDLogFlag.debug.rawValue) static let verbose: UInt = debug | UInt(DDLogFlag.verbose.rawValue) static let all: UInt = UInt.max } // 级别对应名称映射 private let logFlagNames: [DDLogFlag: String] = [ .verbose: "VERBOSE", .debug: "DEBUG", .info: "INFO", .warn: "WARN", .error: "ERROR", .fatal: "FATAL" ]
2. 封装自定义打印入口
绕过库自带的打印宏,直接调用底层DDLog的日志提交方法,避免DDLogLevel枚举校验报错:
// 全局当前开启的日志级别,可动态修改 var currentLogLevel: UInt = CustomLogLevel.debug func Log( _ message: @autoclosure () -> String, flag: DDLogFlag, file: StaticString = #file, function: StaticString = #function, line: UInt = #line ) { // 先做级别过滤,符合条件才提交日志 guard currentLogLevel & flag.rawValue != 0 else { return } // 构造日志消息,level直接传flag对应的rawValue,不需要匹配预定义枚举 let logMsg = DDLogMessage( message: message(), level: DDLogLevel(rawValue: flag.rawValue) ?? .off, flag: flag, context: 0, file: String(describing: file), function: String(describing: function), line: line, tag: nil, options: .copyFile, timestamp: nil ) // 提交到DDLog,致命级别日志同步打印保证输出 DDLog.sharedInstance.log(asynchronous: flag != .fatal, message: logMsg) } // 封装各个级别的快捷调用方法 func LogV(_ message: @autoclosure () -> String) { Log(message(), flag: .verbose) } func LogD(_ message: @autoclosure () -> String) { Log(message(), flag: .debug) } func LogI(_ message: @autoclosure () -> String) { Log(message(), flag: .info) } func LogW(_ message: @autoclosure () -> String) { Log(message(), flag: .warn) } func LogE(_ message: @autoclosure () -> String) { Log(message(), flag: .error) } func LogF(_ message: @autoclosure () -> String) { Log(message(), flag: .fatal) }
3. 自定义日志格式器输出自定义级别名称
如果需要输出你自定义的级别名,需要实现自己的格式器:
class CustomLogFormatter: NSObject, DDLogFormatter { func format(message logMessage: DDLogMessage) -> String? { let levelName = logFlagNames[logMessage.flag] ?? "UNKNOWN" return "\(levelName): \(logMessage.message) [\(logMessage.fileName):\(logMessage.line) \(logMessage.function ?? "")]" } } // 配置logger的时候指定格式器即可 let consoleLogger = DDOSLogger.sharedInstance consoleLogger.logFormatter = CustomLogFormatter() DDLog.add(consoleLogger)
注意事项
- 该方案不需要修改CocoaLumberjack的源码,也不需要额外写OC桥接代码,完全兼容Swift原生实现
- 如果需要多个日志上下文,可以扩展context参数区分不同业务模块的日志级别
内容的提问来源于stack exchange,提问作者nhgrif
相关产品推荐
相关产品推荐

