Swift logging


A logging package for swift projects. ("swiftwood" is a pun of "driftwood" since logs are often just tossed into the stream of events to be lost amidst the wilderness)

Heavily inspired by SwiftyBeaver, but infinitely simpler. Additionally includes support for (semi)automatic censoring of sensitive data.

No remote logging destination is currently included. It isn't that hard to create one, just conform to SwiftwoodDestination, batch up a few logs, and then send them off to your server. I intend to add a generic implementation/example in the future, as time provides. This would be a good suggestion for a contributor.

Initial Setup

fileprivate let setupLock = NSLock()
fileprivate var loggingIsSetup = false

func setupLogging() {
	defer { setupLock.unlock() }
	guard loggingIsSetup == false else { return }
	loggingIsSetup = true

	let consoleDestination = ConsoleLogDestination(maxBytesDisplayed: -1)
	consoleDestination.minimumLogLevel = .verbose

then call setupLogging() somewhere early in your app lifecycle.


log.verbose("Something small happened")
//10/04/2022 00:49:40.107 💜 VERBOSE SwiftwoodTests.swift testLogging():19 - Something small happened
log.debug("Some minor update")
//10/04/2022 00:49:40.109 💚 DEBUG SwiftwoodTests.swift testLogging():20 - Some minor update
log.info("Look at me")
//10/04/2022 00:49:40.111 💙 INFO SwiftwoodTests.swift testLogging():21 - Look at me
log.warning("uh oh")
//10/04/2022 00:49:40.113 💛 WARNING SwiftwoodTests.swift testLogging():22 - uh oh
log.error("Failed successfully")
//10/04/2022 00:49:40.115 ❤️ ERROR SwiftwoodTests.swift testLogging():23 - Failed successfully

Censoring Sensitive Data

Simply conform anything you want to censor to CensoredLogItem and when you log the item individually and have censoring on for your destination, it will appear as **CENSORED** in the log.


struct CensoredPassword: CensoredLogItem, RawRepresentable {
	let rawValue: String

let consoleDestination = ConsoleLogDestination(maxBytesDisplayed: -1, shouldCensor: true) // Console destinations default to `false` censorship
let fileDestination = try FilesDestination(logFolder: URL(pretend this is a valid url), shouldCensor: true) // File destinations default to `true` censorship

let password = CensoredPassword(rawValue: "password1234!")
log.info("regular string", password) // regular string CensoredPassword: **CENSORED*
log.info("regular string \(password)") // regular string CensoredPassword(rawValue: "password!1234")

Note how if you use string interpolation, censorship will fail!

Alternatively, if you want to obfuscate but reveal a bit, you can provide a custom censoredDescription:

struct CensoredKey: CensoredLogItem, RawRepresentable, CustomStringConvertible {
	let rawValue: String

	var description: String { rawValue }
	var censoredDescription: String {
			rawValue.count > 10,
			let start = rawValue.index(rawValue.endIndex, offsetBy: -3, limitedBy: rawValue.startIndex)
		else { return "***" }
		return "***" + String(rawValue[start..<rawValue.endIndex])

let key = CensoredKey(rawValue: "thisisalongkey")
log.info("My key is:", key) // My key is: ***key
log.info("My key is: \(key)") // My key is: thisisalongkey

Be sure not to use string interpolation for values you want to censor!

See tests for additional nuance and examples


  • Swift Tools 5.7.0
View More Packages from this Author


  • None
Last updated: Tue Nov 22 2022 19:21:55 GMT-0500 (GMT-05:00)