Swiftpack.co -  luoxiu/LogDog as Swift Package
Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
user-friendly logging
.package(url: "https://github.com/luoxiu/LogDog.git", from: "0.2.0")


user-friendly logging

apple/swift-log api compatible


LogDog is designed to work out of the box, you can use the pre-configured logger anytime, anywhere:


sugar.error("somethings went wrong")

Or, make a local copy and do some changes:

var logger = suggar
logger["path"] = "/me"


You can quickly create a logger with just a label, it will use the predefined log handler:

var logger = Logger.sugar("worker:a")
logger.level = .info



The core component that makes this all work is SugarLogHandler.

The following code snippet shows how to create a SugarLogHandler and use it to bootstrap the logging system.

LoggingSystem.bootstrap { label in

    // ! to create your own `SugarLogHandler`, you need a `sink`, an `appender` and an optional `errorHandler`. 
    let sink = LogSinks.Builtin.short
    let appender = TextLogAppender.stdout
    let errorHandler = { error: Error in
        print("LogError: \(error)")

    var handler = SugarLogHandler(label: label, sink: sink, appender: appender, errorHandler: errorHandler)

    // ! use dynamicMetadata to register values that are evaluted on logging.
    handler.dynamicMetadata["currentUserId"] = {
    return handler

let logger = Logger(label: "app")
logger.error("Something went wrong")


Sinks process log records.

A sink can be a formatter, or a filter, a hook, or a chain of other sinks.


You can create a formatter sink with just a closure.

let sink = LogSinks.firstly
    .format {
        "\($0.entry.level.uppercased) \($0.entry.message)\n"
// Output:
//     DEBUG hello

Or use the built-in neat formatters directly.

let short = LogSinks.BuiltIn.short

// Output:
//     E: bad response
//     C: can not connect to db

let medium = LogSinks.BuiltIn.medium  // default sink for sugar loggers

// Output:
//     20:40:56.850 E/App main.swift.39: bad response url=/me, status_code=404
//     20:40:56.850 C/App main.swift.41: can not connect to db

let long = LogSinks.BuiltIn.long

// Output:
//     ╔════════════════════════════════════════════════════════════════════════════════
//     ║ 2020-11-15 20:46:31.157  App  ERROR     (main.swift:39  run(_:))
//     ╟────────────────────────────────────────────────────────────────────────────────
//     ║ bad response
//     ╟────────────────────────────────────────────────────────────────────────────────
//     ║ url=/me
//     ║ status_code=404
//     ╚════════════════════════════════════════════════════════════════════════════════


You can create a filter sink with just a closure.

let sink = LogSinks.firstly
    .filter {
        $0.entry.source != "LogDog"
// logs from `LogDog` will not be output.


Or use the built-in expressive dsl to create one.

let sink = LogSinks.BuiltIn.short
let sink = LogSinks.BuiltIn.short


Sinks are chainable, a sink can concatenate another sink.

let sink = sinkA + sinkB + sinkC // + sinkD + ...

// or
let sink = sinkA
    // .concat(sinkD) ...

LogDog ships with many commonly used operators.

Prefix & Suffix

let sink = LogSinks.BuiltIn.short
    .prefix("🎈 ")
// Output:
//     🎈 E: bad response

let sink = LogSinks.BuiltIn.short
    .suffix(" 🎈")
// Output:
//     E: bad response 🎈


let sink = LogSinks.firstly


let sink = LogSinks.firstly
    .encrypt(using: key, cipher: .ChaChaPoly)


let sink = LogSinks.firstly


Sinks's processing can be time-consuming, if you don't want it to slow down your work, you can using Scheduler to make logging asynchronous.

let sink = LogSinks.firstly
    .sink(on: dispatchQueue) // or an operationQueue, or some other custom schedulers, for example, an eventLoop.
    .encode(JSONEncoder()) // time-consuming processing begins.
    .encrypt(using: key, cipher: .ChaChaPoly)


Because of Scheduler, the logging may be asynchronous.

It means that the sinking may be in a different context,

You can use hook with entry.parameters to capture and pass the context.

private struct CustomSinkContext: LogParameterKey {
    typealias Value = CustomSinkContext

    let date = Date()
    let thread = LogHelper.thread

let customSink: AnyLogSink<Void, String> = AnyLogSink {

    // ! beforeSink: in the same context as the log generation.
    $0.parameters[CustomSinkContext.self] = .init()
} sink: { record, next in

    // ! sink: may not be in the same context as the log generation.

    record.sink(next: next) { (record) -> String? in
        guard let context = record.entry.parameters[CustomSinkContext.self] else {
            return nil

        let time = LogHelper.format(context.date, using: "HH:mm:ss.SSS")
        let thread = context.thread
        // ...

Please note, when using encode, parameters with string as key will also be encoded.

  .hook { 
     $0.parameters["currentUserId"] = AuthService.shared.userId
  .hook(.appName, .appVersion, .date) /* , ..., a lot of built-in hooks */
  "label": "app",
  "level": "debug",
  "metadata": {
    // ...
  // ...
  "currentUserId": "1",
  "appName": "LogDog",
  "appVersion": "0.0.1",
  "date": "2020-11-19T01:12:37.001Z"


Appenders are destinations of log records.

Built-in Appenders


Append strings to the underlying OSLog.

let appender = OSLogAppender(osLog)


Append strings to the underlying TextOutputStream.

let appender = TextLogAppender(stream)

let stdout = TextLogAppender.stdout
let stderr = TextLogAppender.stderr


Append outputs to the underlying appenders.

// when `concurrent` is `true`, a dispatch group is used to make the appending of all appenders parallel. 
let appender = MultiplexLogAppender(concurrent: true, a, b, c, d/*, ...*/)



  • ☐ async
  • ☐ auto rotate
  • ☐ ...


In addition to the sinks/appenders mentioned above, you can also find more integrations at LogDogCommunity!


Color the output of LogDog.


Encrypt the output of LogDog.


Append the output of LogDog to CocoaLumberjack.

Don't have the sink/appender you want? Contributions are welcome!


Swift Package Manager

.package(url: "https://github.com/luoxiu/LogDog.git", from: "0.2.0"),


pod 'LogDog', '~> 0.2.0'


Stars: 15
Last commit: 17 weeks ago

Ad: Job Offers

iOS Software Engineer @ Perry Street Software
Perry Street Software is Jack’d and SCRUFF. We are two of the world’s largest gay, bi, trans and queer social dating apps on iOS and Android. Our brands reach more than 20 million members worldwide so members can connect, meet and express themselves on a platform that prioritizes privacy and security. We invest heavily into SwiftUI and using Swift Packages to modularize the codebase.


Release Notes

25 weeks ago

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