ObjcExceptionBriding 7.1.5

ObjcExceptionBriding 7.1.5

Dave Wood维护。



XCGLogger

badge-language badge-platforms badge-license

badge-swiftpm badge-cocoapods badge-carthage

badge-mastodon badge-twitter

badge-sponsors badge-patreon

tl;dr

XCGLogger是Swift项目中使用的原始调试日志模块。

Swift不包含C预处理程序,因此开发人员无法像在Objective-C中那样使用调试日志的#define宏。这意味着我们传统的生成良好调试日志的方法不再有效。仅仅使用print调用意味着您将丢失大量有用的信息,或者需要输入更多的代码。

XCGLogger允许您将详细信息记录到控制台(并且可选地记录到文件或其他自定义目标),就像使用NSLog()print()一样,但提供额外的信息,例如日期、函数名、文件名和行号。

从以下内容进入

简单消息

到以下内容

2014-06-09 06:44:43.600 [Debug] [AppDelegate.swift:40] application(_:didFinishLaunchingWithOptions:): 简单消息

示例

Example

通信(致谢AlamoFire)

  • 如果您需要帮助,请使用Stack Overflow(标签'xcglogger')。
  • 如果您想提出一个一般性问题,请使用Stack Overflow
  • 如果您发现了一个错误,请打开一个问题。
  • 如果您有一个功能请求,请打开一个问题。
  • 如果您想做出贡献,请提交一个拉取请求。
  • 如果您使用XCGLogger,请在GitHub上为该项目Star。

安装

Git子模块

执行

git submodule add https://github.com/DaveWoodCom/XCGLogger.git

在您的仓库文件夹中。

将以下行添加到您的Cartfile中。

github "DaveWoodCom/XCGLogger" ~> 7.1.1

然后运行carthage update --no-use-binaries或只需运行carthage update。有关Carthage的安装和使用详情,请访问其项目页面

运行Swift 5.0及以上版本的开发者需要在Copy Carthage Frameworks构建阶段将$(SRCROOT)/Carthage/Build/iOS/ObjcExceptionBriding.framework添加到他们的输入文件中。

将类似以下内容添加到您的Podfile中。您可能需要根据平台、版本/分支等进行调整。

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '15.0'
use_frameworks!

pod 'XCGLogger', '~> 7.1.1'

指定pod XCGLogger将包括核心框架。我们开始添加subspec以允许您包括可选组件

pod 'XCGLogger/UserInfoHelpers', '~> 7.1.1':包括一些实验性代码,帮助处理使用UserInfo字典来标记日志消息。

然后运行pod install。有关CocoaPods的安装和使用详情,请访问其官方网站

注意:在CocoaPods 1.4.0之前,无法使用具有不同Swift版本的多个pod。您需要确保每个pod都已配置为正确的Swift版本(检查工作区中的pod项目的目标)。如果您手动调整项目的Swift版本,下次运行pod install时,它将会重置。您可以在podfile中添加一个post_install钩子来自动设置正确的Swift版本。这基本上尚未经过测试,我不确定这是一个好的解决方案,但它似乎可以工作。

post_install do |installer|
    installer.pods_project.targets.each do |target|
        if ['SomeTarget-iOS', 'SomeTarget-watchOS'].include? "#{target}"
            print "Setting #{target}'s SWIFT_VERSION to 4.2\n"
            target.build_configurations.each do |config|
                config.build_settings['SWIFT_VERSION'] = '4.2'
            end
        else
            print "Setting #{target}'s SWIFT_VERSION to Undefined (Xcode will automatically resolve)\n"
            target.build_configurations.each do |config|
                config.build_settings.delete('SWIFT_VERSION')
            end
        end
    end

    print "Setting the default SWIFT_VERSION to 3.2\n"
    installer.pods_project.build_configurations.each do |config|
        config.build_settings['SWIFT_VERSION'] = '3.2'
    end
end

当然,您可以根据需要调整这些问题。

将以下条目添加到您的包依赖项中

.Package(url: "https://github.com/DaveWoodCom/XCGLogger.git", majorVersion: 7)

向后兼容性

使用

  • Swift 5.0 使用 XCGLogger 版本 7.1.1
  • Swift 4.2 使用 XCGLogger 版本 6.1.0
  • Swift 4.1 使用 XCGLogger 版本 6.0.4
  • Swift 4.0 使用 XCGLogger 版本 6.0.2
  • Swift 3.0-3.2 使用 XCGLogger 版本 5.0.5
  • Swift 2.3 使用 XCGLogger 版本 3.6.0
  • Swift 2.2 使用 XCGLogger 版本 3.5.3
  • Swift 2.0-2.1 使用 XCGLogger 版本 3.2
  • Swift 1.2 使用 XCGLogger 版本 2.0
  • Swift 1.1和以下使用 XCGLogger 版本 1.0

基本使用(快速入门)

此快速入门方法旨在让您快速开始使用日志记录器。但是,您应该使用下面的高级使用方法来充分利用这个库。

将XCGLogger项目作为子项目添加到您的项目中,并将适当的库添加为您的目标(s)的依赖项。在您的目标的常规选项卡下,将XCGLogger.frameworkObjcExceptionBridging.framework添加到嵌入的二进制文件部分。

然后,在每个源文件中

import XCGLogger

在您的AppDelegate(或其他全局文件)中,声明一个全局常量指向默认的XCGLogger实例。

let log = XCGLogger.default

application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) // iOS, tvOS

applicationDidFinishLaunching(_ notification: Notification) // macOS

函数中,配置您需要的选项

log.setup(level: .debug, showThreadName: true, showLevel: true, showFileNames: true, showLineNumbers: true, writeToFile: "path/to/file", fileLevel: .debug)

writeToFile:的值可以是StringURL。如果文件已存在,在我们使用它之前将清除它。省略参数或将它设置为nil可以只输出到控制台。您可以可选地设置不同的日志级别进行文件输出,使用fileLevel:参数。将其设置为nil或省略以使用与控制台相同的日志级别。

然后,每当您想要记录一些内容时,请使用方便的方法之一

log.verbose("A verbose message, usually useful when working on a specific problem")
log.debug("A debug message")
log.info("An info message, probably useful to power users looking in console.app")
log.notice("A notice message")
log.warning("A warning message, may indicate a possible error")
log.error("An error occurred, but it's recoverable, just info about what happened")
log.severe("A severe error occurred, we are likely about to crash now")
log.alert("An alert error occurred, a log destination could be made to email someone")
log.emergency("An emergency error occurred, a log destination could be made to text someone")

不同的方法设置消息的日志级别。XCGLogger只会打印与当前日志级别设置相等或更高级别的消息。因此,具有.error级别的记录器只会输出到.error.severe.alert.emergency级别的日志消息。

高级使用(推荐)

XCGLogger旨在简单易用,并且您可以用尽可能少的2行代码快速使用。但它在更大的控制和灵活性方面提供了更多功能。

可以将记录器配置为将日志消息发送到各种目的地。使用上述基本设置,记录器会将日志消息输出到标准的Xcode调试控制台,并可选地将消息输出到提供路径的文件。很可能会导致您想将日志发送到更多有趣的地方,例如Apple系统控制台、数据库、第三方服务器或另一个应用程序,如NSLogger。这是通过向记录器中添加目标来实现的。

这是配置记录器同时输出到苹果系统日志和文件的示例。

// Create a logger object with no destinations
let log = XCGLogger(identifier: "advancedLogger", includeDefaultDestinations: false)

// Create a destination for the system console log (via NSLog)
let systemDestination = AppleSystemLogDestination(identifier: "advancedLogger.systemDestination")

// Optionally set some configuration options
systemDestination.outputLevel = .debug
systemDestination.showLogIdentifier = false
systemDestination.showFunctionName = true
systemDestination.showThreadName = true
systemDestination.showLevel = true
systemDestination.showFileName = true
systemDestination.showLineNumber = true
systemDestination.showDate = true

// Add the destination to the logger
log.add(destination: systemDestination)

// Create a file log destination
let fileDestination = FileDestination(writeToFile: "/path/to/file", identifier: "advancedLogger.fileDestination")

// Optionally set some configuration options
fileDestination.outputLevel = .debug
fileDestination.showLogIdentifier = false
fileDestination.showFunctionName = true
fileDestination.showThreadName = true
fileDestination.showLevel = true
fileDestination.showFileName = true
fileDestination.showLineNumber = true
fileDestination.showDate = true

// Process this destination in the background
fileDestination.logQueue = XCGLogger.logQueue

// Add the destination to the logger
log.add(destination: fileDestination)

// Add basic app info, version info etc, to the start of the logs
log.logAppDetails()

根据您的需求,您可以分别配置每个日志目标的不同选项。

另一个常见的使用模式是拥有多个记录器,可能一个用于UI问题,一个用于网络,另一个用于数据问题。

每个日志目标都可以有其自己的日志级别。作为方便,您可以在日志对象本身上设置日志级别,并将其传递给每个目标。然后设置那些需要不同设置的目标。

注意:一个目标对象只能添加到一个记录器对象中,添加到第二个将会将它从第一个中移除。

使用闭包进行初始化

或者,您可以使用闭包来初始化您的全局变量,这样所有的初始化都将在一个地方完成

let log: XCGLogger = {
    let log = XCGLogger(identifier: "advancedLogger", includeDefaultDestinations: false)

	// Customize as needed
    
    return log
}()

注意:这会延迟创建对象,直到真正需要时才创建。因此,这会延迟应用程序详细信息输出。因此,如果您在应用程序启动时不记录任何内容,我建议在didFinishLaunching方法的顶部添加一行let _ = log来强制创建日志对象。

记录任何内容

您可以记录字符串

log.debug("Hi there!")

或几乎您想要的任何内容

log.debug(true)
log.debug(CGPoint(x: 1.1, y: 2.2))
log.debug(MyEnum.Option)
log.debug((4, 2))
log.debug(["Device": "iPhone", "Version": 7])

过滤日志消息

从XCGLogger 4开始,您现在可以创建应用于记录器(或特定目标)的过滤器。创建并配置您的过滤器(以下为示例),然后将它们添加到记录器或目标对象,通过设置可选的filters属性为数组,该数组包含要添加的过滤器。过滤器是按在数组中存在的顺序应用的。在处理过程中,每个过滤器都会被询问是否应该排除日志消息。如果有任何过滤器排除日志消息,则该消息将被排除。过滤器没有反向排除另一个过滤器的途径。

如果一个目标的filters属性是nil,则使用记录器上filters属性。为了使一个目标记录所有内容,同时使所有其他目标筛选某些内容,将过滤器添加到记录器对象,并将那个目标的filters属性设置为空数组[]

注意:与目标不同,您可以将相同的过滤器对象添加到多个记录器和/或多个目标中。

按文件名过滤

要排除来自特定文件的日志消息,创建一个排除过滤器,如下所示

log.filters = [FileNameFilter(excludeFrom: ["AppDelegate.swift"], excludePathWhenMatching: true)]

excludeFrom:接受一个ArraySet,因此您可以同时指定多个文件。

excludePathWhenMatching:默认为true,因此除非您想要匹配路径,否则可以省略它。

要仅包含特定文件集的日志消息,请使用includeFrom:初始化器创建过滤器。也可以通过切换inverse属性来翻转排除过滤器为包含过滤器。

按标签过滤

为了按标签过滤日志消息,您必须能够设置日志消息上的标签。现在每个日志消息都可以附加额外的、由用户定义的数据,供筛选器(和/或格式化器等)使用。这使用userInfo: Dictionary对象处理。字典键应是一个命名空间字符串,以避免与未来添加的内容冲突。官方键将以com.cerebralgardens.xcglogger开始。标签键可以通过XCGLogger.Constants.userInfoKeyTags访问。您肯定不希望输入这个,所以您可以创建一个全局快捷方式:let tags = XCGLogger.Constants.userInfoKeyTags。现在您可以轻松地标记日志

let sensitiveTag = "Sensitive"
log.debug("A tagged log message", userInfo: [tags: sensitiveTag])

标签的值可以是ArraySet或只是一个String,具体取决于您的需求。它们在筛选时会同样工作。

根据您的工作流程和用法,您可能会创建更快速的方法来设置userInfo字典。请参阅以下的其他可能快捷方式。

现在你已经对你的日志进行了标记,可以轻松地进行过滤

log.filters = [TagFilter(excludeFrom: [sensitiveTag])]

就像 FileNameFilter 一样,你可以使用 includeFrom: 或切换 inverse 来只包含具有特定标记的日志消息。

按开发者过滤

按开发者过滤与按标签过滤完全相同,只是使用 XCGLogger.Constants.userInfoKeyDevsuserInfo 键。实际上,这两个过滤都是 UserInfoFilter 类的子类,你可以使用它来创建额外的过滤。请参阅下文中的 扩展 XCGLogger

混合匹配

在具有多个开发者的大型项目中,你可能希望开始标记日志消息,以及指出添加消息的开发者。

尽管非常灵活,但 userInfo 字典使用起来可能会有些繁琐。这里有几种你可以使用的简单方法。我仍在自我测试这些方法,所以它们还不是库的官方部分(我非常希望获得反馈或建议)。

我创建了一些实验性代码来帮助创建 UserInfo 字典。如果使用 CocoaPods,请包含可选的 UserInfoHelpers subspec。查看 iOS 示例应用程序以查看其使用情况。

有两个结构体符合 UserInfoTaggingProtocol 协议。是 TagDev

你可以为这些中的每一个扩展创建一个结构体,以适合你的项目。例如

extension Tag {
    static let sensitive = Tag("sensitive")
    static let ui = Tag("ui")
    static let data = Tag("data")
}

extension Dev {
    static let dave = Dev("dave")
    static let sabby = Dev("sabby")
}

除了这些类型外,还有一个重载操作符 |,可以用来将它们合并到一个与日志调用中的 UserInfo: 参数兼容的字典中。

然后你可以这样记录消息

log.debug("A tagged log message", userInfo: Dev.dave | Tag.sensitive)

我发现这些 UserInfoHelpers 有一些当前问题。这就是为什么我目前将其标记为可选/实验性的。我非常希望听到关于改进的评论/建议。

  1. 重载操作符 | 在没有 Set 的情况下会合并字典。如果一个字典中包含一个 Set,它将使用其中一个,而不合并它们。如果有相同的键对两者都有集合,则优先选择左侧。
  2. 由于 userInfo: 参数需要一个字典,你不能传入单个 Dev 或 Tag 对象。你必须使用至少两个与 | 操作符一起使用,以使其自动转换为兼容的字典。例如,如果你想只有一个 Tag,你必须手动获取 .dictionary 参数:userInfo: Tag("Blah").dictionary

选择性执行代码

所有日志方法都是基于闭包的。使用与 Swift 的 assert() 函数相同的语法糖,这种方法确保我们不会浪费资源构建那些根本不会输出的日志消息,同时同时保持干净的调用位置。

例如,以下日志语句如果抑制了调试日志级别,则不会浪费资源

log.debug("The description of \(thisObject) is really expensive to create")

同样,假设你必须在迭代一个循环以进行一些计算并在记录结果之前结束。在 Objective-C 中,你可以将代码块放在 #if #endif 之间,以防止代码执行。但在 Swift 中,以前你仍需要处理该循环,浪费资源。使用 XCGLogger,它就这么简单:

log.debug {
    var total = 0.0
    for receipt in receipts {
        total += receipt.total
    }

    return "Total of all receipts: \(total)"
}

在需要选择性执行代码而不生成日志行的情况下,返回 nil,或使用以下方法之一:verboseExecdebugExecinfoExecwarningExecerrorExecsevereExec

自定义日期格式

你可以创建自己的 DateFormatter 对象并将其分配给记录器。

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy hh:mma"
dateFormatter.locale = Locale.current
log.dateFormatter = dateFormatter

使用颜色增强日志消息

XCGLogger 支持向日志消息添加格式化代码,以便在多个位置启用颜色。原始选项是使用 XcodeColors 插件。然而,Xcode(从版本 8 开始)已经不再官方支持插件。你仍然可以在终端窗口中通过文件目的地对象添加颜色来查看你的日志,但你现在不能在 Xcode 中查看颜色。你可以使用 ANSI 颜色支持来向你的文件目的地对象添加颜色,并通过终端窗口查看日志。这为你提供了一些额外的选项,例如添加加粗、斜体或(请不要)闪烁!

一旦启用,每个日志级别都可以有自己的颜色。这些颜色可以根据需要进行自定义。如果使用多个日志记录器,您还可以分别设置每个日志记录器的颜色。

设置 ANSI 格式化的示例

if let fileDestination: FileDestination = log.destination(withIdentifier: XCGLogger.Constants.fileDestinationIdentifier) as? FileDestination {
    let ansiColorLogFormatter: ANSIColorLogFormatter = ANSIColorLogFormatter()
    ansiColorLogFormatter.colorize(level: .verbose, with: .colorIndex(number: 244), options: [.faint])
    ansiColorLogFormatter.colorize(level: .debug, with: .black)
    ansiColorLogFormatter.colorize(level: .info, with: .blue, options: [.underline])
    ansiColorLogFormatter.colorize(level: .notice, with: .green, options: [.italic])
    ansiColorLogFormatter.colorize(level: .warning, with: .red, options: [.faint])
    ansiColorLogFormatter.colorize(level: .error, with: .red, options: [.bold])
    ansiColorLogFormatter.colorize(level: .severe, with: .white, on: .red)
    ansiColorLogFormatter.colorize(level: .alert, with: .white, on: .red, options: [.bold])
    ansiColorLogFormatter.colorize(level: .emergency, with: .white, on: .red, options: [.bold, .blink])
    fileDestination.formatters = [ansiColorLogFormatter]
}

与过滤器一样,您可以为多个日志记录器和/或多个目标使用相同的格式化对象。如果目标对象的 formatters 属性是 nil,则将使用日志记录器的 formatters 属性。

有关创建自己的自定义格式器的信息,请参见下面的 扩展 XCGLogger

备用配置

使用 Swift 构建设置标志,可以在调试与预发布/生产之间使用不同的日志级别。转到“构建设置”->“Swift 编译器”->“自定义标志”->“其他 Swift 标志”,并将 -DDEBUG 添加到“调试”条目中。

#if DEBUG
    log.setup(level: .debug, showThreadName: true, showLevel: true, showFileNames: true, showLineNumbers: true)
#else
    log.setup(level: .severe, showThreadName: true, showLevel: true, showFileNames: true, showLineNumbers: true)
#endif

您可以用类似的方式设置任意数量的选项。查看更新的 iOSDemo 应用,了解使用不同选项时如何使用不同的日志目标,搜索 USE_NSLOG

后台日志处理

默认情况下,提供的日志目标将按其被调用的线程处理日志。这是为了确保在调试应用程序时立即显示日志消息。您可以在日志调用后立即添加断点,并在断点被触发时查看结果。

但是,如果您没有积极调试应用程序,在当前线程上处理日志可能会引入性能损失。现在,您可以指定一个目标,它使用您选择的派发队列(或甚至使用默认提供的)处理其日志。

fileDestination.logQueue = XCGLogger.logQueue

或者

fileDestination.logQueue = DispatchQueue.global(qos: .background)

当与上述 备用配置 方法结合使用时,这一点尤其有效。

#if DEBUG
    log.setup(level: .debug, showThreadName: true, showLevel: true, showFileNames: true, showLineNumbers: true)
#else
    log.setup(level: .severe, showThreadName: true, showLevel: true, showFileNames: true, showLineNumbers: true)
    if let consoleLog = log.logDestination(XCGLogger.Constants.baseConsoleDestinationIdentifier) as? ConsoleDestination {
        consoleLog.logQueue = XCGLogger.logQueue
    }
#endif

追加到现有日志文件

在日志记录器的高级配置(见上方的 高级使用)中,您现在可以指定日志记录器向现有日志文件追加,而不是自动覆盖它。

在初始化 FileDestination 对象时添加可选的 shouldAppend: 参数。您还可以添加 appendMarker: 参数来在日志文件中添加一个标记,指示您的应用程序的新实例从该位置开始追加。默认情况下,如果省略该参数,我们将添加 -- ** ** ** --。将其设置为 nil 以跳过添加标记。

let fileDestination = FileDestination(writeToFile: "/path/to/file", identifier: "advancedLogger.fileDestination", shouldAppend: true, appendMarker: "-- Relauched App --")

自动日志文件轮换

在向文件记录时,您可以选择自动将日志文件轮换到归档目标,并由日志记录器自动创建新的日志文件以替换旧文件。

使用 AutoRotatingFileDestination 类创建目标,并设置以下属性

targetMaxFileSize: 文件大于此大小时自动轮换

targetMaxTimeInterval: 此秒数后自动轮换

targetMaxLogFiles: 要保留的存档日志文件数,较旧的文件将自动删除

这些都是对日志记录器的指南,而不是硬性限制。

扩展 XCGLogger

您可以创建除内置之外的其他日志目标。您的自定义日志目标必须实现 DestinationProtocol 协议。实例化您的对象,配置它,然后将它添加到 XCGLogger 对象中,使用 add(destination:)。有两个基类 (BaseDestinationBaseQueuedDestination),您可以从中继承以处理大多数流程,您只需在自定义类中实现一个额外的方法。请参考 ConsoleDestinationFileDestination 作为示例。

您还可以创建自定义过滤器或格式化对象。以提供的版本为起点进行参考。请注意,过滤器和格式化程序可以在处理过程中修改日志消息。这意味着您可以创建一个过滤器来删除密码、突出显示特定单词、加密消息等。

贡献

XCGLogger 是 Swift 最好用的日志库,因为得到了像您这样社区成员的贡献。您有很多方式可以帮助持续改进它。

  1. GitHub 上为项目 star。
  2. 报告您发现的问题/错误。
  3. 建议新功能。
  4. 提交 pull requests。
  5. 下载并安装我的一个应用程序: https://www.cerebralgardens.com/apps/ 尝试我的最新应用程序: All the Rings
  6. 您还可以访问我的 Patreon 并进行财务捐赠。

注意:在提交 pull request 时,请尽可能使用多个小提交而不是一个大的提交。这样在需要合并多个 pull request 以创建新版本时,合并会更容易。

待办事项

  • 添加一些高级用例的更多示例
  • 添加更多日志目的地类型
  • 添加 Objective-C 支持
  • 添加 Linux 支持

更多

如果您觉得这个库很有帮助,您肯定也会觉得这个其他工具很有用。

Watchdog: https://watchdogforxcode.com/

此外,请查看我的其他项目

变更日志

变更日志现在有自己的文件: CHANGELOG.md