Puppy

Swift5.6+ release CocoaPods CI codecov license

platforms SwiftPM|CMake|Bazel|Carthage

Puppy 是一个用 Swift 编写的灵活的日志库 🐶

它支持多种传输方式(控制台、文件、syslog 和 oslog)作为日志记录器。它不仅可以独立工作,还可以作为 apple/swift-log 的后端。

此外,它还具有文件日志轮转功能,并且您可以根据需要自定义日志格式。而且它支持 跨平台(Darwin、Linux 和 Windows)

特性

示例

基本用法

记录到多种传输方式(例如,控制台和文件)。建议每个记录器的第一个参数是唯一的反向顺序 FQDN,因为它也在内部用作 DispatchQueue 的标签。

import Puppy

let console = ConsoleLogger("com.example.yourapp.console", logLevel: .info)
let fileURL = URL(fileURLWithPath: "./foo.log").absoluteURL
let file = FileLogger("com.example.yourapp.file",
                      logLevel: .info,
                      fileURL: fileURL,
                      filePermission: "600")  // Default permission is "640". 

var log = Puppy()
log.add(console)
log.add(file)

log.debug("DEBUG message")  // Will NOT be logged.
log.info("INFO message")    // Will be logged.
log.error("ERROR message")  // Will be logged.

使用文件日志轮转

记录到文件并使用日志轮转功能。

import Puppy

class ViewController: UIViewController {
    let fileURL = URL(fileURLWithPath: "./logs/foo.log").absoluteURL
    let rotationConfig = RotationConfig(suffixExtension: .date_uuid,
                                        maxFileSize: 10 * 1024 * 1024,
                                        maxArchivedFilesCount: 3)
    let delegate = SampleFileRotationDelegate()
    let fileRotation = try! FileRotationLogger("com.example.yourapp.filerotation",
                                                fileURL: fileURL,
                                                rotationConfig: rotationConfig,
                                                delegate: delegate)

    override func viewDidLoad() {
        super.viewDidLoad()
        var log = Puppy()
        log.add(fileRotation)
        log.info("INFO message")
        log.warning("WARNING message")
    }
}

class SampleFileRotationDelegate: FileRotationLoggerDelegate {
    func fileRotationLogger(_ fileRotationLogger: FileRotationLogger,
                            didArchiveFileURL: URL, toFileURL: URL) {
        print("didArchiveFileURL: \(didArchiveFileURL), toFileURL: \(toFileURL)")
    }
    func fileRotationLogger(_ fileRotationLogger: FileRotationLogger,
                            didRemoveArchivedFileURL: URL) {
        print("didRemoveArchivedFileURL: \(didRemoveArchivedFileURL)")
    }
}

apple/swift-log 一起使用

作为 apple/swift-log 的后端,记录到多种传输方式(例如,控制台和 syslog)。

import Puppy

let console = ConsoleLogger("com.example.yourapp.console")
let syslog = SystemLogger("com.example.yourapp.syslog")

var puppy = Puppy()
puppy.add(console)
puppy.add(syslog)

LoggingSystem.bootstrap {
    var handler = PuppyLogHandler(label: $0, puppy: puppy)
    // Set the logging level.
    handler.logLevel = .trace
    return handler
}

var log = Logger(label: "com.example.yourapp.swiftlog")

log.trace("TRACE message")  // Will be logged.
log.debug("DEBUG message")  // Will be logged.

这是一个将 PuppyVapor 一起使用的实际示例,Vapor 内部使用了 apple/swift-log

import App
import Vapor  // Vapor 4.67.4
import Puppy

let fileURL = URL(fileURLWithPath: "./server-logs/bar.log").absoluteURL
let rotationConfig = RotationConfig(suffixExtension: .numbering,
                                    maxFileSize: 30 * 1024 * 1024,
                                    maxArchivedFilesCount: 5)
let fileRotation = try FileRotationLogger("com.example.yourapp.server",
                                          fileURL: fileURL,
                                          rotationConfig: rotationConfig)
var puppy = Puppy()
puppy.add(fileRotation)

// https://docs.vapor.codes/basics/logging/
var env = try Environment.detect()
try LoggingSystem.bootstrap(from: &env) { (logLevel) -> (String) -> LogHandler in
    return { label -> LogHandler in
        var handler = PuppyLogHandler(label: label, puppy: puppy)
        handler.logLevel = .info
        return handler
    }
}
let app = Application(env)
defer { app.shutdown() }
try configure(app)
try app.run()

自定义日志格式

使用 Formattable 协议自定义日志格式。例如,记录到 oslog。

import Puppy

class ViewController: UIViewController {
    let logFormat = LogFormatter()
    let oslog = OSLogger("com.yourapp.oslog", logFormat: logFormat)

    override func viewDidLoad() {
        super.viewDidLoad()
        var log = Puppy()
        log.add(oslog)
        log.info("INFO message")
        log.warning("WARNING message")
    }
}

struct LogFormatter: LogFormattable {
    private let dateFormat = DateFormatter()

    init() {
        dateFormat.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
    }

    func formatMessage(_ level: LogLevel, message: String, tag: String, function: String,
                       file: String, line: UInt, swiftLogInfo: [String : String],
                       label: String, date: Date, threadID: UInt64) -> String {
        let date = dateFormatter(date, withFormatter: dateFormat)
        let fileName = fileName(file)
        let moduleName = moduleName(file)
        return "\(date) \(threadID) [\(level.emoji) \(level)] \(swiftLogInfo) \(moduleName)/\(fileName)#L.\(line) \(function) \(message)".colorize(level.color)
    }
}

创建自定义日志记录器

您也可以创建自己的自定义日志记录器。自定义日志记录器需要遵循 Loggerable 协议。

@preconcurrency import Dispatch
import Puppy

public struct CustomLogger: Loggerable {
    public let label: String
    public let queue: DispatchQueue
    public let logLevel: LogLevel
    public let logFormat: LogFormattable?

    public init(_ label: String, logLevel: LogLevel = .trace, logFormat: LogFormattable? = nil) {
        self.label = label
        self.queue = DispatchQueue(label: label)
        self.logLevel = logLevel
        self.logFormat = logFormat
    }

    public func log(_ level: LogLevel, string: String) {
        // Implements the logging feature here.
    }
}

许可证

Puppy 在 MIT 许可证下可用。有关详细信息,请参阅 LICENSE 文件。