PrettyLog 是一个小的 Swift Package,可以使 Xcode Console 中的日志记录更加美观。
dependencies: [
.package(url: "https://github.com/bennokress/PrettyLog", .upToNextMajor(from: "1.0.0"))
]
使用 PrettyLog,您可以使您的 print 语句更漂亮、更有用。只需将这个 ...
print("User tapped Continue Button")
... 替换为这个
logD("User tapped Continue Button")
到目前为止一切顺利。但是,使用 PrettyLog,您还有更多选择...
logV("A verbose log")
logD("A debug log")
logI("An info log")
logW("A warning log")
logE("An error log")
logV("Got an API Response ...", category: .service)
logI("Saving Token from API: \(token)", category: .storage)
logV("User tapped Continue Button", category: .user)
logE("Username and Password did not match", category: .manager)
logW("Or create your own Category ...", category: .custom("Announcement"))
logV(service, "Got an API Response ...", category: .service)
logW(screen, element, "Username too long", joinedBy: " → ", category: .manager)
let error = NetworkError.notFound
let exception = NSException(name: .portTimeoutException, reason: nil)
log(error, category: .service)
log(exception, category: .service)
PrettyLog 中包含我经常使用的类别。 这些可能与您的项目中真正有用的类别有所不同,因此我让您可以轻松定义自己的类别。 只需像这样扩展 LogCategory
extension LogCategory {
/// This custom category can be used like all the predefined ones: logV("Running Unit Tests ...", category: .todo)
static var todo: LogCategory { .custom("To Do") }
}
PrettyLog 包含一些默认的日志级别,但这并不意味着您仅限于这些级别。 要定义您自己的级别,请像这样扩展 LogLevel
extension LogLevel {
/// This custom level can be used like all the predefined ones, it has to be called with the universal `log` method though: `log("The login method is not yet implemented", category: .todo, as: .todo)
static var todo: LogLevel { .custom(emoji: "🟣", priority: 200) }
}
如果您想将自定义日志级别与所有预定义的级别一起使用,您可能需要在代码中的某个地方定义一个全局方法,例如 logT
/// Log messages in the provided order with TODO level
/// - Parameters:
/// - messages: One or more strings and string-convertible objects to include in the log statement
/// - separator: The separator between messages (defaults to `-`)
/// - Attention: No log will be created, if `messages` is empty or `nil`.
public func logT(_ messages: String?..., joinedBy separator: String = " - ") {
PrettyLogProxy.log(messages, joinedBy: separator, as: .todo, category: .todo)
}
请参阅此 README 的集成部分的 'Import once' 部分,以找到定义此方法的合适位置。
PrettyLog 可以轻松地通过日志目标将日志消息发送到不同的目标。 包中预定义的是 ConsoleLog
,它将所有日志级别的语句发送到 Xcode 控制台。 在实际应用程序中,您可能希望使用不同于普通 print
的本地解决方案来记录到后端和 Web 服务或本地。 这就是 LogTarget
协议的用武之地。 它只需要您指定如何处理由 LogLevel
、消息 (String
) 和 LogCategory
组成的日志语句。 此外,您可以指定一个 logPriorityRange
,它会在将传入的日志语句发送到自定义定义的处理程序之前,过滤掉不符合定义的范围要求的传入日志语句。
一个例子是自定义控制台日志目标,它仅在应用程序在特定环境中运行时才记录日志
import Foundation
import PrettyLog
struct Console: LogTarget {
/// Create the log statement with a consistent design.
/// - Parameters:
/// - level: The log level is responsible for the emoji displayed in the log statement.
/// - message: The message is printed to the right of the log level emoji.
/// - category: The category is printed to the left of the log level emoji.
func createLog(_ level: LogLevel, message: String, category: LogCategory) {
print("\(prefix(level: level, category: category)) \(message)")
}
var logPriorityRange: ClosedRange<LogLevel>? {
App.shared.isDeveloperVersion ? .allowAll : .allowNone
}
// MARK: Private Helpers
private var currentTimestamp: String {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss.SSS"
return formatter.string(from: Date())
}
private func prefix(level: LogLevel, category: LogCategory) -> String {
"\(currentTimestamp) \(category.truncatedOrPadded(to: 20)) \(level.emoji)"
}
}
使用 PrettyLog 时,您基本上有两种选择
由于您可能在整个应用程序中记录日志,因此在每个文件中导入 PrettyLog 可能会变得很麻烦,但这是一个选择。
import Foundation
import PrettyLog
struct MyModel {
func doStuff() {
logV("Doing some stuff ...")
}
}
另一种选择是在您的应用程序中的某个位置创建一个 Swift 文件,该文件充当 PrettyLog 的代理。 这使您可以导入 PrettyLog 并全局定义日志方法一次。
//
// 📄 PrettyLog.swift
// 👨🏼💻 Author: Benno Kress
//
import Foundation
import PrettyLog
/// Log messages in the provided order with VERBOSE level
/// - Parameters:
/// - messages: One or more strings and string-convertible objects to include in the log statement
/// - separator: The separator between messages (defaults to `-`)
/// - category: The category of the log message (defaults to `.uncategorized`)
/// - Attention: No log will be created, if `messages` is empty or `nil`.
func logV(_ messages: String?..., joinedBy separator: String = " - ", category: LogCategory = .uncategorized) {
PrettyLogProxy.logV(messages, joinedBy: separator, category: category)
}
/// Log messages in the provided order with DEBUG level
/// - Parameters:
/// - messages: One or more strings and string-convertible objects to include in the log statement
/// - separator: The separator between messages (defaults to `-`)
/// - category: The category of the log message (defaults to `.uncategorized`)
/// - Attention: No log will be created, if `messages` is empty or `nil`.
func logD(_ messages: String?..., joinedBy separator: String = " - ", category: LogCategory = .uncategorized) {
PrettyLogProxy.logD(messages, joinedBy: separator, category: category)
}
/// Log messages in the provided order with INFO level
/// - Parameters:
/// - messages: One or more strings and string-convertible objects to include in the log statement
/// - separator: The separator between messages (defaults to `-`)
/// - category: The category of the log message (defaults to `.uncategorized`)
/// - Attention: No log will be created, if `messages` is empty or `nil`.
func logI(_ messages: String?..., joinedBy separator: String = " - ", category: LogCategory = .uncategorized) {
PrettyLogProxy.logI(messages, joinedBy: separator, category: category)
}
/// Log messages in the provided order with WARNING level
/// - Parameters:
/// - messages: One or more strings and string-convertible objects to include in the log statement
/// - separator: The separator between messages (defaults to `-`)
/// - category: The category of the log message (defaults to `.uncategorized`)
/// - Attention: No log will be created, if `messages` is empty or `nil`.
func logW(_ messages: String?..., joinedBy separator: String = " - ", category: LogCategory = .uncategorized) {
PrettyLogProxy.logW(messages, joinedBy: separator, category: category)
}
/// Log messages in the provided order with ERROR level
/// - Parameters:
/// - messages: One or more strings and string-convertible objects to include in the log statement
/// - separator: The separator between messages (defaults to `-`)
/// - category: The category of the log message (defaults to `.uncategorized`)
/// - Attention: No log will be created, if `messages` is empty or `nil`.
func logE(_ messages: String?..., joinedBy separator: String = " - ", category: LogCategory = .uncategorized) {
PrettyLogProxy.logE(messages, joinedBy: separator, category: category)
}
/// Log an `Error` with ERROR level.
/// - Parameters:
/// - error: The error to log
/// - category: The category of the log message (defaults to `.uncategorized`)
/// - Attention: No log will be created, if `error` is `nil`.
func log(_ error: Error?, category: LogCategory = .uncategorized) {
PrettyLogProxy.log(error, category: category)
}
/// Log a `NSException` with ERROR level.
/// - Parameters:
/// - exception: The exception to log
/// - category: The category of the log message (defaults to `.uncategorized`)
/// - Attention: No log will be created, if `exception` is `nil`.
func log(_ exception: NSException?, category: LogCategory = .uncategorized) {
PrettyLogProxy.log(exception, category: category)
}
/// Log with ERROR level and crash the app.
/// - Parameters:
/// - messages: One or more strings and string-convertible objects to include in the log statement
/// - separator: The separator between messages (defaults to `-`)
/// - category: The category of the log message
/// - Attention: No log will be created, if `messages` is empty or `nil`.
func fatalLog(_ messages: String?..., joinedBy separator: String = " - ", category: LogCategory = .uncategorized) -> Never {
PrettyLogProxy.logE(messages, joinedBy: separator, category: category)
let messageComponents = messages.compactMap { $0 }
let statement = messageComponents.joined(separator: separator)
fatalError(statement)
}
// TODO: Add custom global log methods if needed -> for example: if you have custom LogLevel and LogCategory `.todo`, you could define `logT` for that.
// /// Log messages in the provided order with TODO level
// /// - Parameters:
// /// - messages: One or more strings and string-convertible objects to include in the log statement
// /// - separator: The separator between messages (defaults to `-`)
// /// - Attention: No log will be created, if `messages` is empty or `nil`.
// public func logT(_ messages: String?..., joinedBy separator: String = " - ") {
// PrettyLogProxy.log(messages, joinedBy: separator, as: .todo, category: .todo)
// }
👨🏻💻 Benno Kress
欢迎贡献、提交问题和提出功能请求!
随意查看 问题页面。
版权所有 © 2022 Benno Kress。
此项目已获得 MIT 许可。
此 README 是由 ❤️ 使用 readme-md-generator 生成的