Description
an apple/swift-log api compatible library, both out of the box and highly extensible.
LogDog alternatives and similar libraries
Based on the "Logging" category.
Alternatively, view LogDog alternatives based on common mentions on social networks and blogs.
-
XCGLogger
A debug log framework for use in Swift projects. Allows you to log details to the console (and optionally a file), just like you would have with NSLog() or print(), but with additional information, such as the date, function name, filename and line number. -
Dotzu
DISCONTINUED. Debbuger tool for iOS developer. Display logs, network request, device informations, crash logs while using the app. -
TinyConsole
๐ฑ๐ฌ๐ฆ TinyConsole is a micro-console that can help you log and display information inside an iOS application, where having a connection to a development computer is not possible. -
CleanroomLogger
CleanroomLogger provides an extensible Swift-based logging API that is simple, lightweight and performant -
Atlantis
A powerful input-agnostic swift logging framework made to speed up development with maximum readability. -
Puree
DISCONTINUED. [Obsoleted] A log collector for iOS (new version! -> https://github.com/cookpad/Puree-Swift) -
CleanroomASL
DISCONTINUED. A Swift-based API for reading from & writing to the Apple System Log (more commonly known somewhat inaccurately as "the console") -
TraceLog
TraceLog is a highly configurable, flexible, portable, and simple to use debug logging system for Swift and Objective-C applications running on Linux, macOS, iOS, watchOS, and tvOS. -
CacheAdvance
A performant cache for logging systems. CacheAdvance persists log events 30x faster than SQLite.
CodeRabbit: AI Code Reviews for Developers

* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of LogDog or a related project?
README
LogDog
user-friendly logging apple/swift-log api compatible
Usage
LogDog is designed to work out of the box, you can use the pre-configured logger anytime, anywhere:
sugar.debug("hi")
sugar.error("somethings went wrong")
Or, make a local copy and do some changes:
var logger = suggar
logger["path"] = "/me"
logger.debug("hi")
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
logger.info("hi")
SugarLogHandler
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"] = {
AuthService.shared.userId
}
return handler
}
let logger = Logger(label: "app")
logger.error("Something went wrong")
Sink
Sinks process log records.
A sink can be a formatter, or a filter, a hook, or a chain of other sinks.
Formatter
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
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Filter
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.
DSL
Or use the built-in expressive dsl to create one.
let sink = LogSinks.BuiltIn.short
.when(.path)
.contains("private")
.deny
let sink = LogSinks.BuiltIn.short
.when(.level)
.greaterThanOrEqualTo(.error)
.allow
Concat
Sinks are chainable, a sink
can concatenate another sink
.
let sink = sinkA + sinkB + sinkC // + sinkD + ...
// or
let sink = sinkA
.concat(sinkB)
.concat(sinkC)
// .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 ๐
Encode
let sink = LogSinks.firstly
.encode(JSONEncoder())
Crypto
let sink = LogSinks.firstly
.encode(JSONEncoder())
.encrypt(using: key, cipher: .ChaChaPoly)
Compress
let sink = LogSinks.firstly
.encode(JSONEncoder())
.compress(.COMPRESSION_LZFSE)
Schedule
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)
.compress(.COMPRESSION_LZFSE)
Hook
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.
LogSinks.firstly
.hook {
$0.parameters["currentUserId"] = AuthService.shared.userId
}
.hook(.appName, .appVersion, .date) /* , ..., a lot of built-in hooks */
.encode(JSONEncoder())
/*
{
"label": "app",
"level": "debug",
"metadata": {
// ...
}
// ...
"currentUserId": "1",
"appName": "LogDog",
"appVersion": "0.0.1",
"date": "2020-11-19T01:12:37.001Z"
}
*/
Appender
Appenders are destinations of log records.
Built-in Appenders
OSLogAppender
Append strings to the underlying OSLog
.
let appender = OSLogAppender(osLog)
TextLogAppender
Append strings to the underlying TextOutputStream
.
let appender = TextLogAppender(stream)
let stdout = TextLogAppender.stdout
let stderr = TextLogAppender.stderr
MultiplexLogAppender
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/*, ...*/)
FileLogAppender
WIP
- [ ] async
- [ ] auto rotate
- [ ] ...
Community
In addition to the sinks/appenders mentioned above, you can also find more integrations at LogDogCommunity!
LogDogChalk
Color the output of LogDog.
LogDogCryptoSwift
Encrypt the output of LogDog.
LogDogCocoaLumberjack
Append the output of LogDog to CocoaLumberjack.
Don't have the sink/appender you want? Contributions are welcome!
Installation
Swift Package Manager
.package(url: "https://github.com/luoxiu/LogDog.git", from: "0.2.0"),
CocoaPods
pod 'LogDog', '~> 0.2.0'