Swiftpack.co - sushichop/Puppy as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by sushichop.
sushichop/Puppy 0.6.0
A flexible logging library written in Swift
⭐️ 97
🕓 10 weeks ago
iOS macOS watchOS tvOS linux
.package(url: "https://github.com/sushichop/Puppy.git", from: "0.6.0")

Puppy

Swift5.6+ release CocoaPods CI codecov license

platforms SwiftPM|CMake|Bazel|Carthage

Puppy is a flexible logging library written in Swift 🐶

It supports multiple transports(console, file, syslog, and oslog) as loggers. It not only works alone, but also as a backend for apple/swift-log.

Furthermore, it has file log rotation feature and you can also customize the log format as you like. And it supports cross-platform(Darwin, Linux, and Windows).

Features

  • Written in Swift.
  • Supports cross-platform(Darwin, Linux, and Windows).
  • Supports console, file, syslog, and oslog as loggers.
  • Supports automatic log rotation about file logger.
  • Also Works as a backend for apple/swift-log.

Examples

Basic Usage

Logging to mutliple transports(e.g. console and file). It is recommended that the first argument of each logger be a unique reverse-order FQDN since it is also used internally for a DispatchQueue's label.

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.

Use file log rotation

Logging to file and use log rotation feature.

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)")
    }
}

Use with apple/swift-log

Logging to multiple transports(e.g. console and syslog) as a backend for apple/swift-log.

import Puppy
import Logging

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.

Here is a practical example of using Puppy with Vapor, which uses apple/swift-log internally.

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()

Customize the logging format

Customize the log format using Formattable protocol. Logging to oslog for example.

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 {
    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)
        let fileName = fileName(file)
        let moduleName = moduleName(file)
        return "\(date) \(threadID) [\(level.emoji) \(level)] \(swiftLogInfo) \(moduleName)/\(fileName)#L.\(line) \(function) \(message)".colorize(level.color)
    }
}

Create a custom logger

You can also create your own custom logger. The custom logger needs to conform to Loggerable protocol.

@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.
    }
}

License

Puppy is available under the MIT license. See the LICENSE file for details.

GitHub

link
Stars: 97
Last commit: 9 minutes ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.

Dependencies

Related Packages

Release Notes

10 weeks ago

Supports Swift 5.6 or later.

There are several breaking changes. Please check README for details.

  • Disable bitcode. #54
  • Update platform versions. #55
  • Update to Xcode 14.0.1 and Swift 5.6 or later. #56
  • Still use Xcode 13.4.1 for executing pod lib lint. #57
  • Remove a property of type FileHandle. #58
  • Remove the argument named asynchronous. #59
  • Remove and change the properties. #60
  • Change minimum platform versions. #61
  • Adopt Sendable and Loggerable. #62
  • Remove the dependency in podspec. #66
  • Update to Xcode 14.1. #69
  • Use #fileID instead of #file. #70
  • Add another example of using Puppy with Vapor. #71
  • Use struct instead of class. #72

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics