
XCGLOGGER是用于在Swift Projects中使用的原始调试日志模块。
Swift不包括C预处理器,因此开发人员无法使用他们在Objective-C中使用的调试日志#define宏。这意味着我们传统的生成良好调试日志的方式不再有效。诉诸普通的旧print电话意味着您会丢失很多有用的信息,或者要求您键入更多代码。
XCGLOGGER允许您将详细信息登录到控制台(以及可选的文件或其他自定义目的地),就像使用NSLog()或print()一样,但是还有其他信息,例如日期,函数名称,文件名和行号。
从中走:
Simple message
因此:
2014-06-09 06:44:43.600 [Debug] [AppDelegate.swift:40] application(_:didFinishLaunchingWithOptions:): Simple message
执行:
git submodule add https://github.com/DaveWoodCom/XCGLogger.git
在您的存储库文件夹中。
将以下行添加到您的Cartfile中。
github "DaveWoodCom/XCGLogger" ~> 7.1.5
然后运行carthage update --no-use-binaries或仅仅是carthage update 。有关迦太基的安装和使用的详细信息,请访问其项目页面。
在Swift中运行5.0及以上的开发人员需要将$(SRCROOT)/Carthage/Build/iOS/ObjcExceptionBridging.framework添加到其输入文件中的“复制迦太基框架构建阶段”。
将类似于以下行的内容添加到您的Podfile中。您可能需要根据平台,版本/分支等进行调整。
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '12.0'
use_frameworks!
pod 'XCGLogger', '~> 7.1.5'
单独指定POD XCGLogger将包括核心框架。我们开始添加亚种,以允许您包括可选组件:
pod 'XCGLogger/UserInfoHelpers', '~> 7.1.5' :包含一些实验代码,以帮助使用UserInfo词典来标记日志消息。
然后运行pod install 。有关Cocoapods的安装和使用的详细信息,请访问其官方网站。
注意:在Cocoapods 1.4.0之前,不可能使用具有快速版本混合物的多个POD。您可能需要确保为正确的Swift版本配置每个POD(检查工作空间的POD项目中的目标)。如果您手动调整项目的SWIFT版本,则下次运行pod install时将重置。您可以将post_install挂钩添加到您的Podfile中,以自动设置正确的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.2n"
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.2n"
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)
使用:
此快速启动方法的目的是为了让您与记录器一起运行。但是,您应该在下面使用高级用法来充分利用此库。
将XCGLOGGER项目作为子项目添加到您的项目中,并添加适当的库作为目标的依赖。在目标的General选项卡下,添加XCGLogger.framework和ObjcExceptionBridging.framework到Embedded Binaries部分。
然后,在每个源文件中:
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:可以是String或URL 。如果该文件已经存在,则将在我们使用该文件之前清除。省略参数或将其设置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行代码下快速启动和快速运行。但是它可以更大的控制和灵活性。
可以将记录器配置为将日志消息传递到各种目的地。使用上面的基本设置,Logger将将日志消息输出到标准Xcode调试控制台,如果提供了路径,则可以选择一个文件。您很可能需要将日志发送到更有趣的地方,例如Apple系统控制台,数据库,第三方服务器或其他应用程序(例如NSlogger)。这是通过将目的地添加到记录器来实现的。
这是配置记录器以输出到Apple系统日志和文件的示例。
// 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问题,一个用于网络,另一种用于数据问题。
每个日志目的地都可以具有自己的日志级别。为了方便起见,您可以在日志对象本身上设置日志级别,并将该级别传递给每个目的地。然后设置需要不同的目的地。
注意:只能将目标对象添加到一个logger对象中,将其添加到第二个对象将将其从第一个删除。
另外,您可以使用封闭来初始化全局变量,以便在一个地方完成所有初始化
let log : XCGLogger = {
let log = XCGLogger ( identifier : " advancedLogger " , includeDefaultDestinations : false )
// Customize as needed
return log
} ( )注意:这会懒惰地创建日志对象,这意味着直到实际需要之前就不会创建它。这延迟了应用程序信息详细信息的初始输出。因此,如果您还没有在应用程序启动中登录某些内容let _ = log则建议在应用程序启动时强制在应用didFinishLaunching启动时创建日志对象。
您可以记录字符串:
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的新手,您现在可以创建过滤器以应用于您的记录器(或特定目的地)。创建和配置过滤器(下面的示例),然后将它们添加到Logger或目标对象中,将可选的filters属性设置为包含过滤器的数组。过滤器以数组中存在的顺序应用。在处理过程中,询问每个过滤器是否应将日志消息排除在日志之外。如果有任何过滤器不包括日志消息,则将其排除在外。过滤器无法扭转排除另一个过滤器的排除。
如果目标的filters属性nil ,则使用日志filters属性。要拥有一个目标日志所有内容,同时让所有其他目的地过滤一些东西,请将过滤器添加到日志对象中,并将一个目标的filters属性设置为空数组[] 。
注意:与目的地不同,您可以将相同的过滤对象添加到多个登录器和/或多个目的地。
要将所有日志消息排除在特定文件中,请创建类似的排除过滤器:
log . filters = [ FileNameFilter ( excludeFrom : [ " AppDelegate.swift " ] , excludePathWhenMatching : true ) ] excludeFrom:取一个Array<String>或Set<String>因此您可以同时指定多个文件。
excludePathWhenMatching:默认为true因此您可以省略它,除非您也想匹配路径。
要仅适用于文件的特定集合的日志消息,请使用includeFrom: Initializer创建过滤器。也可以仅切换inverse属性以将排除过滤器翻转为包含过滤器。
为了通过标签过滤日志消息,您当然必须能够在日志消息上设置标签。现在,每个日志消息都可以包含附加到其附加的用户定义的数据,将由过滤器(和/或格式化器等)使用。这是用userInfo: Dictionary<String, Any>对象来处理的。字典键应为命名式字符串,以避免与未来添加的碰撞。官方密钥将从com.cerebralgardens.xcglogger开始。 XCGLogger.Constants.userInfoKeyTags可以访问标签键。您绝对不想打字,因此请随时创建一个全局快捷方式: let tags = XCGLogger.Constants.userInfoKeyTags 。现在,您可以轻松地标记您的日志:
let sensitiveTag = " Sensitive "
log . debug ( " A tagged log message " , userInfo : [ tags : sensitiveTag ] )标签的值可以是Array<String> , Set<String> ,也可以是String ,具体取决于您的需求。过滤时它们都以相同的方式工作。
根据您的工作流程和用法,您可能会创建更快的方法来设置userInfo字典。有关其他可能的快捷方式,请参见下文。
现在,您已经标记了日志,可以轻松过滤:
log . filters = [ TagFilter ( excludeFrom : [ sensitiveTag ] ) ]就像FileNameFilter一样,您可以使用includeFrom:或inverse切换以仅包含具有指定标签的日志消息。
开发人员的过滤就像通过标签过滤,仅使用XCGLogger.Constants.userInfoKeyDevs的userInfo键。实际上,这两个过滤器都是UserInfoFilter类的子类,您可以使用它们来创建其他过滤器。请参阅下面的XCGLOGGER。
在具有多个开发人员的大型项目中,您可能需要开始标记日志消息,并指出添加了该消息的开发人员。
虽然非常灵活,但userInfo字典可能会有些麻烦。您可以简单地使用一些可能使用的方法。我仍在自己测试它们,因此它们还没有正式属于图书馆的一部分(我喜欢反馈或其他建议)。
我创建了一些实验代码来帮助创建UserInfo词典。 (如果使用CocoApods,请包括可选的UserInfoHelpers亚种)。检查iOS演示应用程序以查看使用中的应用。
有两个符合UserInfoTaggingProtocol协议的结构。 Tag和Dev 。
您可以对适合您项目的每个项目创建一个扩展名。例如:
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我目前看到了一些当前的问题,这就是为什么我现在将其设置为可选/实验的原因。我很想听听改进的评论/建议。
|只要没有Set s,就可以合并字典。如果其中一个词典包含一个Set ,则它将使用其中一个,而无需合并它们。如果双方都有相同键的设置,则更喜欢左侧。userInfo:参数需要字典,因此您不能传递单个开发对象或标记对象。您需要在|运算符使其自动转换为兼容词典。例如,如果您只想要一个标签,则必须手动访问.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或使用其中一种方法: verboseExec , debugExec ,infoexec, infoExec , warningExec , errorExec和severeExec 。
您可以创建自己的DateFormatter对象并将其分配给记录器。
let dateFormatter = DateFormatter ( )
dateFormatter . dateFormat = " MM/dd/yyyy hh:mma "
dateFormatter . locale = Locale . current
log . dateFormatter = dateFormatterXCGlogger支持将格式代码添加到日志消息中,以在各个地方启用颜色。最初的选项是使用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 ,则将使用Logger的formatters属性。
有关创建自己的自定义格式化器的信息,请参见下面的XCGlogger。
通过使用Swift Build Frags,可以在调试与分期/生产中使用不同的日志级别。转到构建设置 - > 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使用记录器的高级配置(请参见上面的高级用法)时,您现在可以指定该记录器附加到现有日志文件,而不是自动覆盖它。
添加可选的shouldAppend:初始化FileDestination对象时的参数。您还可以添加appendMarker:参数以将标记添加到日志文件中,以指示应用程序的新实例开始附加。默认情况下,如果省略了参数,我们将添加-- ** ** ** --将其设置nil以跳过附加标记。
let fileDestination = FileDestination(writeToFile: "/path/to/file", identifier: "advancedLogger.fileDestination", shouldAppend: true, appendMarker: "-- Relauched App --")
登录到文件时,您可以选择将日志文件自动旋转到存档的目标,并使Logger自动创建一个新的日志文件,以代替旧文件。
使用AutoRotatingFileDestination类创建目的地,并设置以下属性:
targetMaxFileSize :一旦文件大于此,自动旋转
targetMaxTimeInterval :这秒后自动旋转
targetMaxLogFiles :要保留的存档日志数量,较旧的日志文件将自动删除
这些都是记录仪的准则,而不是硬限制。
您可以创建替代日志目的地(内置的日志目的地)。您的自定义日志目标必须实现DestinationProtocol协议。实例化对象,配置它,然后将其添加到add(destination:)的XCGLogger对象中。您可以继承两个基本目标类( BaseDestination和BaseQueuedDestination ),以便为您处理大部分过程,要求您仅在自定义类中实现一种附加方法。查看ConsoleDestination和FileDestination的示例。
您还可以创建自定义过滤器或格式化器。看看提供的版本作为起点。请注意,过滤器和格式化器可以在处理时更改日志消息。这意味着您可以创建一个过滤器,该过滤器剥离密码,突出显示特定单词,加密消息等。
XCGlogger是Swift的最佳记录仪,因为像您这样的社区的贡献。您可以通过多种方式可以帮助继续使其变得伟大。
注意:提交拉动请求时,请使用许多巨大的提交经文。当需要组合新版本时需要合并几个拉动请求时,它更容易合并。
如果您发现此库有帮助,那么您肯定会发现此其他工具有帮助:
看门狗:https://watchdogforxcode.com/
另外,请查看我的其他一些项目:
更改日志现在在其自己的文件中:changelog.md