In this article, we will be looking at a logging framework written in Swift. The goal of the project is to provide you with a simple and easy way to implement logging in your apps.
The oslog swift example is a logging framework written in Swift. The project is hosted on GitHub and can be found at https://github.com/thesharpbrains/oslog-swift.
Swift logging at its most natural
Evergreen is a Swift-based logging system. It’s intended to do exactly what you’d think, yet it’s so adaptable that you may use it in any way you choose.
Replace those simple print() lines in your Swift project with calls to Evergreen’s flexible logging methods, which allow you to modify the output’s verbosity, log to various destinations (e.g. a file) with custom formatting, and even measure time.
log(“Hello World!”, forLevel:.info) import Evergreen
[AppDelegate.swift|INFO] Hello, Universe!
Evergreen logging is beneficial in any Swift project, but it’s especially helpful when building a framework. Allow your framework’s users to simply change the verbosity of the output it produces.
Use the swift4 branch for Swift 4 development.
Logging is a method of recording events that occur while software is executed. To signal that specific events have happened, the software developer inserts logging calls to their code. A descriptive message, which may or may not include variable data, is used to describe an event (i.e. data that is potentially different for each occurrence of the event). Events have a significance that the developer assigns to them; this importance is also known as the degree or severity of the event.
— Taken from the Python docs.
However, not everyone is interested in logging. There are some who believe:
Cutting, skidding, on-site processing, and loading of trees or logs into trucks or skeletal cars are all part of logging.
— According to Wikipedia.
For the time being, let’s concentrate on what the Python folks have to say. They seem to understand what they’re talking about.
CocoaPods is the simplest method to include Evergreen into your project:
CocoaPods should be installed as follows:
Create a Podfile in your project’s directory or edit an existing Podfile to include Evergreen:
platform :ios, ‘8.0’ use frameworks! pod ‘Evergreen’ source ‘https://github.com/CocoaPods/Specs.git’
Allow CocoaPods to do its thing:
Use the *.xcworkspace instead of the *.xcodeproj, as is customary with CocoaPods.
Swift Package Manager is a program that allows you to manage your
The Swift Package Manager, which is included in the Swift development releases, may also be used. Simply include Evergreen as a dependent in your package’s description, like follows:
let package = Package( name: “HelloWorld”, dependencies: [.Package(url: “https://github.com/knly/Evergreen.git”, majorVersion: 0), //… ] ) import PackageDescription
You may also manually incorporate Evergreen into your project:
Evergreen should be included as a submodule:
https://github.com/knly/Evergreen.git $ git submodule add
Drag Evergreen.xcodeproj into your project’s file navigator.
Add Evergreen.framework to the Embedded Binaries section of the target configuration under General.
Note: For a more interactive overview of Evergreen’s capabilities, open the Evergreen.xcworkspace and look at the Evergreen.playground. You may also import Evergreen into a Playground in your project’s workspace to test it out.
Logging without the need for setup
log(“Hello World!”) import Evergreen log(“Hello World!”)
Without any setup, you may record events and watch a beautifully written message appear in the console. This is intended for extremely simple and fast usage. Continue reading to learn about Evergreen’s more advanced logging options.
The Use of Log Levels
You may give an incident a degree of significance or severity that corresponds to one of the log levels listed below:
- Critical: Unexpected events that have the potential to create severe issues. To deal with them, you’d want to be summoned in the middle of the night.
- Error: Unexpected events that your program does not manage. Someone should alert you to them as soon as possible.
- Warning: Unexpected events that will most likely have no impact on your software’s runtime. You’ll want to look into them at some point.
- General events that record the lifetime of software.
- Debug: Events that help you understand how your program works, mostly for debugging reasons.
- Verbose: Provides extra context by providing detailed information about the surroundings.
The logger in charge of the event also has a log level. It will not be recorded if the event’s log level is lower than the logger’s.
A logger may have one of the following log levels in addition to the ones listed above. Only in certain usage situations does assigning them to events make sense.
- All events will be recorded.
- No events will be recorded if this option is turned off.
You may adjust the verbosity of your program using log levels. Using a low log level during development and raising it in a release environment is a frequent use case, as is adjusting it for particular portions of your program and various logging destinations, such as the console or a file.
You may change Evergreen’s default log level for a simple setup. Learn how to manage the log level more precisely by reading about the logger hierarchy below.
.debug log is an abbreviation for “debug log” (“Debug”, forLevel: .debug) a log (“Info”, forLevel: .info) a log (“Warning”, forLevel: .warning) a log (“Error”, forLevel: .error) a log (“Critical”, forLevel: .critical)
Because their log level is zero, these events will not be recorded.
Evergreen.logLevel =.debug / Because their log level is >=.debug log, these events will be recorded (“Debug”, forLevel: .debug) a log (“Info”, forLevel: .info) a log (“Warning”, forLevel: .warning) a log (“Error”, forLevel: .error) Because their log level is.critical, log(“Critical”, forLevel:.critical) / These events will not be recorded. .debug log is a file that contains information on how to debug a program (“Verbose”, forLevel: .verbose)
For convenience, each log level has a matching log function:
info(“Info”) / similar to log(“Info”, forLevel:.info) //… debug(“Debug”) / equivalent to log(“Debug”, forLevel:.debug) debug(“Debug”) / equivalent to log(“Debug”, forLevel:.debug) debug(“Debug”) / equivalent to log(“Debug”, forLevel:.debug) debug(“Debug
Using the Hierarchy of Loggers
Instead of using global functions to record events, you should utilize loggers. A logger is always part of a hierarchy and inherits characteristics from its parent, such as the log level. You may set a default configuration and tweak it for particular sections of your program this way.
This is very helpful for lowering the log level of the portion of your program you’re presently working on during development.
Every logger contains a key that may be used to determine the origin of any given event. The key extends to a dot-separated key path in its hierarchy, such as “Parent.Child.”
Of course, you may create your own hierarchy manually, but Evergreen makes it easy for you to do so:
- The Evergreen.defaultLogger constant may be used to get the default logger, which is at the top of the logger hierarchy. Set a default log level using it. The default logger is also referred to by the global property Evergreen.logLevel.
- Use the global Evergreen.getLogger function or the Logger.child instance method to get the right logger. Provide a key path, such as “MyModule.MyType,” that defines the portion of your program for which the event is important. These methods will always return the same logger instance for a specified key path and, if one does not already exist, will create one.
To make a suitable logger accessible for a particular type, it is useful to utilize a constant stored attribute:
let logger = Evergreen.getLogger(“MyModule.MyType”) init() self.logger.debug(“Initializing…”) import Evergreen class MyType
You may change the logging settings for sections of a logger hierarchy after you’ve created one:
Evergreen. logLevel =.warning;/ Set the log level of defaultLogger to.warning. logger = Evergreen.getLogger(“MyModule”); Retrieve the logger using the key “MyModule,” which descends straight from the default logger logger. logLevel =.debug/ Set the log level to.debug while we work on this section of the program.
Note: The AppDelegate’s application:didFinishLaunchingWithOptions: method is an excellent location to perform this setup for production. Environment variables, as explained in the next section, are the ideal way to set temporary log level changes.
Configuration using Environment Variables
Using environment variables is the best method for temporarily configuring the logger hierarchy. You may easily enable more verbose logging for the portions of your program you’re presently working on this manner. Select your target from the toolbar menu, then Edit Scheme… > Run > Arguments and add environment variables to the list. Then dial this number:
Every environment variable with the prefix Evergreen is assessed as a logger key path, and the value of the variable is allocated to a log level. The log level descriptors, such as Debug or Warning, should be matched with the values.
For example, Evergreen = Debug or Evergreen are valid environment variable definitions. MyLogger is a verbose log.
Keeping Errors and Events Separate
Any Swift Error type (such as NSError) may be sent to Evergreen’s logging methods, either as the message or as a distinct error: argument:
debug(“Something unexpected occurred here!”, error: error) let error: Error let error: Error let error: Error let error: Error let error: Error let error: Error let error: Er
With tic and toc, you can easily estimate the duration between two events:
tic (forLevel:.debug, andLog: “Starting costly operation…”) //… toc(andLog: “Expensive operation completed!”, forLevel:.info)
[Default|DEBUG] Beginning a costly procedure… [Default|INFO] Expensive surgery completed! [ELAPSED TIME: 0] [ELAPSED TIME: 0] [ELAPSED T .0435580015182495s]
For nested timing, you may alternatively use the timerKey argument:
if var i=0; if var i=1; if var i=2;
(tic) (andLog: “Starting expensive operation…”, forLevel: .debug, timerKey: “expensiveOperation”) tic(andLog: “(i+1). iteration…”, forLevel:.verbose, timerKey: “iteration”) //… toc(andLog: “Completed expensive operation!”, forLevel:.info, timerKey: “expensiveOperation”) toc(andLog: “Completed expensive operation!”, forLevel:.info, timerKey: “expensiveOperation”) toc(andLog: “Complete
Similar events may be kept from being recorded excessively by associating a key with them in any logging call, for example:
When a logger decides that an event has to be handled, it sends it to the appropriate handlers. A handler retrieves a human-readable record from an event using its formatter and then emits the record. Handler subclasses emit records in a variety of ways:
Because Evergreen’s defaultLogger comes with a ConsoleHandler, every event in its hierarchy will be recorded to the console. Additional handlers may be simply added by adding them to the handlers array of the relevant logger:
You can also set the logLevel of a handler to provide another degree of filtering.
The Formatter class in Evergreen provides a simple method to change the format of log entries.
The string(from event: Event) method’s default implementation, which you may modify in a subclass, utilizes a list of components: To create a record from an event using instances of the Formatter, use [Formatter.Component]. Enumeration of components:
I’d be grateful for some expert input on the API and architecture. Please send me any ideas through email ([email protected]), Gitter, or by creating an issue.
The logkit is a logging framework written in Swift. It provides a simple interface for writing logs, and can be used to log into files or the console.
Frequently Asked Questions
What is Logger framework?
Logger is a framework that provides a simple interface for logging events.
What is log in Swift?
The Swift programming language is a general-purpose, multi-paradigm, compiled programming language created by Apple Inc. It is based on the Objective-C and Cocoa frameworks for Mac OS X and iOS development.
How do I log errors in Swift?
There are a number of ways to log errors in Swift. The most common way is by using the println function, which outputs text to the console window.
- swift log to file
- ios swift logging framework
- swift logging library