A version of Apple’s SwiftLog that adds some improved formatting for app development and includes OSLog-ish string interpolation.

Feature List

  • Privacy (public, private and masked)
  • Log levels
  • FormattedLogHandler
  • Literal string
  • Numerical formats
  • Boolean formats
  • Exponential formats
  • Hexadecimal formats
  • Column formatting

I’ve also added many tests to ensure the string interpolation and privacy features are working as expected. However, I have not included any of SwiftLog’s tests since the library is simply a direct copy (see below).


// Somewhere in your code, define your log handler(s)
LoggingSystem.bootstrap { label in 
    FormattedLogHandler(label: label)

// Then in a framework or subsystem, define a logger
let logger = Logger(label: "com.benkau.logging")
logger.debug("Hello, world!")

Similar to OSLog, all interpolated values default to a private scope (in a non-DEBUG) environment, with their values redacted.

logger.debug("Logged in as \(user, privacy: .private)")
// Logged in as <redacted>

logger.debug("Fetching data from \(url, privacy: .private(.hash))")
// Fetching data from 210237823

There are conveniences for logging numerical values:

logger.debug("Pi is \(3.14159265359, format: .fixed(precision: 2))")
// Pi is 3.14

logger.debug("Current score: \(score, format: .decimal(minDigits: 2)")
// Current score: 03


The library includes a custom FormattedLogHandler that you’re free to use or create your own. The provided handler uses SFSymbols to improve readability and clarity in the console, as well as providing a simple closure based formatter so you can make it your own.

FormattedLogHandler { options in 
    // simply return your formatted log
    FormattedLogHandler(label: label) { data in
        "\(data.timestamp()) [\(data.label)] \(data.level.symbol) \(data.message)"

Obviously you can always use your own LogHandler as you can directly with SwiftLog.


The actual logging framework is a direct copy of Apple’s own SwiftLog. The reason I didn’t include it as a dependency is because there was no way for me to extend it to include string interpolation that I could see. If anyone has ideas on how to make this work, I would love to hear about them. Please open an Issue so we can discuss it as this would allow me to properly attribute and pin to a dependency version etc…


The code is packaged as a framework. You can install manually (by copying the files in the Sources directory) or using Swift Package Manager (preferred)

To install using Swift Package Manager, add this to the dependencies section of your Package.swift file:

.package(url: "", .upToNextMinor(from: "1.0.0"))