SwiftyBeaver
SwiftyBeaver is the colorful, extensible, lightweight logger in Swift 2. Made for use in development & release.
Unique Feature Set
- Log to Xcode Console and / or log to a file
- Add custom log destination handlers to log to Loggly, Redis, etc.
- Colored output to Xcode Console(!), log file, etc.
- Uses own serial background queues/threads for a great performance
- Log levels which are below the set minimum are not executed for even better release performance
- Increases productivity & saves a lot of time thanks to "Needle in the Haystack" mode
- Easy & convenient configuration
- Use multiple logging destinations & settings, even for the same type
- Already comes with good defaults
- Use
log.debug("foo")
syntax - Get started with 2 lines of code
- Simple installation via Carthage, CocoaPods, Swift Package Manager or download
- Very detailed logging (optional):
- time (with microsecond precision)
- level (output in color)
- thread name (if not main thread)
- filename, function & line
- message (can be string or a variable of any type)
- Has just ~350 lines of source code, easy to understand
- Native support for leading Xcode development plugins
Please follow SwiftyBeaver on Twitter to stay up-to-date on new versions & see the Change Log.
Colors!
Before we start, 2 screenshots of colored example output.
Xcode Console
Terminal.app
While tailing the log file.
Watch the intro video "SwiftyBeaver in 60 Seconds":
Looks good, tell me more!
Requirements
- iOS 8.0+ / Mac OS X 10.9+
- Xcode 7
Installation
Platform & Installation Support
\ | iOS 8+ | OSX 10.9+ | watchOS 2+ | tvOS 9+ |
---|---|---|---|---|
Swift Package Manager | ✅ | ✅ | ✅ | ✅ |
Carthage | ✅ | ✅ | ✅ | ✅ |
CocoaPods | ✅ | ✅ | ✅ | ✅ |
Download | ✅ | ✅ | ✅ | ✅ |
For installation details please see the next points.
via Carthage
You can use Carthage to install SwiftyBeaver by adding that to your Cartfile:
github "SwiftyBeaver/SwiftyBeaver"
via CocoaPods
To use CocoaPods just add this to your Podfile:
pod 'SwiftyBeaver'
via Swift Package Manager (Swift 2.2)
To use SwiftyBeaver as a Swift Package Manager package just add the following in your Package.swift file.
import PackageDescription
let package = Package(
name: "HellowWorld",
dependencies: [
.Package(url: "https://github.com/SwiftyBeaver/SwiftyBeaver.git", majorVersion: 0)
]
)
or Download
- Download the latest release zip from here
- Drag & drop the
/sources
folder into your project (make sure "Copy items if needed" is checked) - Rename the "sources" group to "SwiftyBeaver" if you'd like
Note: You don't have to import SwiftyBeaver
if you install this way.
Usage
Let's go!
Add that near the top of your AppDelegate.swift
to be able to use SwiftyBeaver in your whole project.
import SwiftyBeaver
let log = SwiftyBeaver.self
At the the beginning of your AppDelegate:didFinishLaunchingWithOptions()
add the SwiftyBeaver log destinations (console, file, etc.) and then you can already do the following log level calls globally (colors included):
// add log destinations. at least one is needed!
let console = ConsoleDestination() // log to Xcode Console
let file = FileDestination() // log to default swiftybeaver.log file
log.addDestination(console)
log.addDestination(file)
// Now let’s log!
log.verbose("not so important") // prio 1, VERBOSE in silver
log.debug("something to debug") // prio 2, DEBUG in blue
log.info("a nice information") // prio 3, INFO in green
log.warning("oh no, that won’t be good") // prio 4, WARNING in yellow
log.error("ouch, an error did occur!") // prio 5, ERROR in red
// log anything!
log.verbose(123)
log.info(-123.45678)
log.warning(NSDate())
log.error(["I", "like", "logs!"])
log.error(["name": "Mr Beaver", "address": "7 Beaver Lodge"])
Destination Properties
You can log to Xcode Console, to one or multiple files and to other, custom log destinations. Each log destination is an instance of a Destination class with it’s own set of properties with defaults.
The properties should be set before or directly after the .addDestination(...)
call. Please see some examples further down below.
Core Properties
The following core properties are available for every destination and must be set individually for every destination instance!
Property | Default | Description |
---|---|---|
.detailOutput | true | Logs date, file, function, line, level, message. If set to false then just date, level, message are logged. |
.colored | true | Colored output or not |
.minLevel | SwiftyBeaver.Level.Verbose | Any level with a priority lower than that level is not logged. Possible values are SwiftyBeaver.Level.Verbose, .Debug, .Info .Warning, .Error. Use .addMinLevelFilter() to find the needle in the haystack (see further below). |
.dateFormat | "yyyy-MM-dd HH:mm:ss.SSS" | Logs current date and time including milliseconds. If you set an empty String then no date is added to the log. |
.levelString.Verbose, .Debug, .Info, .Warning, .Error | "VERBOSE", "DEBUG", etc. | Sets a custom string representing the log level. On default it is the log level as uppercase word. |
Log to Console
To log to Xcode Console just instantiate ConsoleDestination()
, optionally adjust properties and then add the instance to SwiftyBeaver itself.
Example:
let console = ConsoleDestination() // get new console destination
console.detailOutput = false // log simple (date, level, message)
console.dateFormat = "HH:mm:ss" // simpler date format
log.addDestination(console) // add to SwiftyBeaver to use destination
Log to File
SwiftyBeaver can write logs to a file by instantiating and adding of the FileDestination()
class. Logging in a different format to multiple files is possible if several file destination instances are created and added. If a file is not existing then it is created.
Additional to above mentioned core properties the file destination also comes with the following properties:
Property | Default | Description |
---|---|---|
.logFileURL | DocumentDirectory+"swiftybeaver.log" | The default filename is swiftybeaver.log and it is stored in the app’s DocumentDirectory. During development it is recommended to change that logfileURL to /tmp/swiftybeaver.log so that the file can be tailed by a Terminal app using the CLI command tail -f /tmp/swiftybeaver.log . |
Example with logging to 2 files in parallel:
let file = FileDestination() // get new file destination instance
// uses standard logging to swiftybeaver.log
file.detailOutput = false
file.colored = true
file.minLevel = Level.Verbose
file.dateFormat = "HH:mm:ss.SSS"
log.addDestination(file) // add to SwiftyBeaver to use destination
// the second file with different properties and custom filename
let file2 = FileDestination()
file2.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
file2.minLevel = Level.Info
file2.levelString.Error = "Beaver Alarm!"
file2.logFileURL = NSURL(string: "file:///tmp/app_info.log")!
log.addDestination(file2)
Own Logging Destinations
It is very easy to write own custom logging destinations, for example to Loggly, Logstash, Redis, Postgres, because all log formatting and preparation logic is already done in SwiftyBeaver.swift and BaseDestination.swift for you!
All logging destination classes need to subclass BaseDestination()
and just need to override the send()
method. By calling super.send(...)
you already receive the finally formatted log string which can then be edited or directly sent / stored at any other system, storage or server.
To get started, please check the destination classes ConsoleDestination.swift and FileDestination.swift which do the logging to Xcode Console and File.
If you wrote some great new destinations then please contribute them!
The Needle in the Haystack
After a while every software project is full of log.verbose()
or log.debug()
statements. Fixing a small bug in the middle of the application logic often requires reading and parsing of hundreds of log messages until you find the message you are really interested in.
This really annoying issue could until now just be fixed by commenting out all unnecessary log.verbose()
or log.debug()
lines in the module or whole software - a tedious, time-consuming task just to focus on a bug in a single file or function.
But SwiftyBeaver comes with a much better solution called MinLevelFilters.
A MinLevelFilter overrules the minimum log level of the destination for a certain file or folder name pattern and a function or function name pattern. SwiftyBeaver’s MinLevelFilters are so flexible that you can add multiple filters per destination and the filter pattern themselve are very easy to understand and can have a huge positive impact on your productivity during development and debugging.
How to add a MinLevelFilter
Let's assume the following every-day-work example: you have a grown project, it is full of log.verbose()
and log.debug()
. You currently work on the the file MyViewController.swift
and you are just interested in the log.verbose()
lines of the file. So what do you need to do?
Firstly, set the general minimum log level for the whole app to .Info
:
let console = ConsoleDestination()
console.minLevel = .Info
Secondly, add a MinLevelFilter which sets the MinLevel for the file MyViewController.swift
to .Verbose
.
console.addMinLevelFilter(.Verbose, path: "MyViewController.swift")
Now when you run your app you will just see logging output of level .Info
and higher and additionally all logging output from MyViewController.swift
due to the minLevelFilter .Verbose
of the file.
MinLevelFilters Are Very Flexible
Internally SwiftyBeaver checks on every log event if the absolute path of the source file and the function name of the log statement do match the filter arguments.
The matching itself is done by checking if the strings do either match or the source strings contain the filter strings. The matching is case-sensitive and for path it compares the absolute path.
Let’s take an example for better understanding:
let console = ConsoleDestination()
console.minLevel = .Info // just log if .Info or higher if not filter matches
// some path examples with matching pattern
var path = "MyViewController.swift" // matches all filenames containing MyViewController.swift
path = "MyViewController" // matches file names & folder names containing MyViewController
path = "ViewController" // ViewController, MyViewController, ViewController/foo, etc.
path = "MyLib/" // matches files & folders inside MyLib, IloveMyLib or We/LoveMyLib folder
console.addMinLevelFilter(.Verbose, path: path)
And an example to match all function names which contain the word init
in files which have the word ViewController
in their absolute path:
var path = "ViewController" // pattern *ViewController*
var function = "init" // function pattern *init*
console.addMinLevelFilter(.Verbose, path: path, function: function)
That's great, isn’t it? Please keep in mind that a destination can have multiple MinLevelFilters.
And finally a complete and more complex example which:
- sets the default minLevel of the project to
.Info
- sets the minLevel of all files in the folder
MyLib
to.Verbose
- sets the minLevel of all function names which contain the word
setup
to.Debug
:
let c = ConsoleDestination()
c.minLevel = .Info // just log if .Info or higher
console.addMinLevelFilter(.Verbose, path: "MyLib/")
console.addMinLevelFilter(.Debug, path: "", "setup")
log.addDestination(console)
No Colors?!
If Xcode does not show the log level word in color and you activated that option then you still may need the additional Xcode-Colors plugin.
Simple installation of the plugin:
- Download the file XcodeColors.xcplugin.zip
- Unzip it to "~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/" (if this directory path does not exist, you can just create it)
- Restart Xcode & allow the plugin
Now it should work. If not then please create an issue.
Clickable Hyperlink to Source in Console
SwiftyBeaver supports Krzysztof Zabłocki’s great Xcode Plugin KZLinkedConsole which adds a clickable link to each line that is logged in Xcode Console. The link leads to the file and line of the log message and is a great helper during Console debugging!
Simple installation of the plugin:
- Download the file KZLinkedConsole.xcplugin.zip
- Unzip it to "~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/" (if this directory path does not exist, you can just create it)
- Restart Xcode & allow the plugin
Contact & Contribute
If you have questions please contact Sebastian via the dedicated SwiftyBeaver Twitter account. Feature requests or bugs are better reported and discussed as Github Issue.
Please contribute back any great stuff, especially logging destinations and ways to make SwiftyBeaver even more flexible, elegant and awesome! Each new bugfix, feature request or addition/change should be put in a dedicated pull request to simplify discussion and merging.
Thanks for testing, sharing, staring & contributing - Happy Logging!
License
SwiftyBeaver is released under the MIT License.