QuantiLogger
QuantiLogger is a super lightweight logging library for iOS development in Swift. It provides a few pre-built loggers including native os_log or a file logger. It also provides an interface for creating custom loggers.
Requirements
- Swift 5.0+
- Xcode 10+
- iOS 11.0+
- RxSwift 4.0+ (NOTE: QuantiLogger uses set of RxSwift libraries and takes advantage of its provided reactive functionality.)
Installation
Carthage
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. You can install Carthage with Homebrew using the following command:
$ brew update
$ brew install carthage
To integrate QuantiLogger into your Xcode project using Carthage, specify it in your Cartfile:
github "Qase/QuantiLogger" ~> 1.17
Run carthage update to build the framework and drag the built QuantiLogger.framework and its dependencies into your Xcode project.
CocoaPods
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods
To integrate QuantiLogger into your Xcode project using CocoaPods, specify it in your Podfile:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '11.0'
use_frameworks!
target '<Your Target Name>' do
pod 'QuantiLogger', '~> 1.17'
end
Then, run the following command:
$ pod install
Usage
Logging levels
It is possible to log on different levels. Each logger can support different levels, meaning that it records only log messages on such levels. For example multiple loggers of the same type can be set to support different levels and thus separate logging on such level. Another use case is to further filter messages of specific type declared by its level.
Although it is definitely up to the developer in which way the levels will be used, there is a recommended way how to use them since each of them serves a different purpose.
infofor mostly UI related user actionsdebugfor debugging purposesverbosefor extended debug purposes, especially when there is a need for very specific messageswarnfor warningserrorfor errorssystem(for native os_log only) matches to os_log_fault -> sends a fault-level message to the logging systemprocess(for native os_log only) matches to os_log_error -> sends an error-level message to the logging system
Pre-build loggers
ConsoleLogger
The simplest logger. Wraps print(_:separator:terminator:) function from Swift Standard Library.
SystemLogger
Wraps the native OSLog to log messages on the system level.
FileLogger
Enables logging to a file. Each log file relates to a single day data. Another day, another log file is used. numberOfLogFiles specifies the number of log files that are stored. In other words, how many days back (log files) should be kept. If the last log file is filled, the first one gets overriden using the simplest Round-robin strategy.
WebLogger
Enables logging via REST API to a target server. To reduce the traffic, logs are grouped into so-called batches when sent. A user can set the size of such batches and also a time interval between individual batches being sent.
Here is an example of log batch in JSON:
[{"severity": "VERBOSE",
"sessionName": "E598B4C1-2B08-4563-81C0-2A77E5CE0C3C",
"message":"/some/path/QuantiLoggerTests.swift - testWebLogger() - line 165: Test verbose",
"timestamp": 1529668897.318845},
{"severity": "INFO",
"sessionName":"E598B4C1-2B08-4563-81C0-2A77E5CE0C3C",
"message": "/some/path/QuantiLoggerTests.swift - testWebLogger() - line 166: Test system",
"timestamp":1529668897.3196549},
{"severity":"INFO",
"sessionName":"E598B4C1-2B08-4563-81C0-2A77E5CE0C3C",
"message":"/some/path/QuantiLoggerTests.swift - testWebLogger() - line 167: Test process",
"timestamp":1529668897.3196959
}]
Here is the set of properties a user can customize:
serverUrltarget server's urlsessionNamename of a session to log insizeOfBatchsize of a log batchtimeSpantime interval between individual batches being sent
Target server that receives logs is independent on the WebLogger. Therefore a user can implement a customized server that displays logs in a prefered way. If one does not wish to implement a customized server, we also provide a simple server solution written in Node.js.
ApplicationCallbackLogger
A special type of logger, that automatically logs all received UIApplication notifications, further called application callbacks. Here is a complete list of supported application callbacks:
UIApplicationWillTerminateUIApplicationDidBecomeActiveUIApplicationWillResignActiveUIApplicationDidEnterBackgroundUIApplicationDidFinishLaunchingUIApplicationWillEnterForegroundUIApplicationSignificantTimeChangeUIApplicationUserDidTakeScreenshotUIApplicationDidChangeStatusBarFrameUIApplicationDidReceiveMemoryWarningUIApplicationWillChangeStatusBarFrameUIApplicationDidChangeStatusBarOrientationUIApplicationWillChangeStatusBarOrientationUIApplicationProtectedDataDidBecomeAvailableUIApplicationBackgroundRefreshStatusDidChangeUIApplicationProtectedDataWillBecomeUnavailable
The logger is integrated and set automatically, thus it logs all application callbacks on debug level as is. By using setApplicationCallbackLogger(with: [ApplicationCallbackType]?) on LogManager a user can specific application callbacks to be logged (all of them are logged by default). If an empty array is passed, all application callbacks will be logged. If nil is passed, none of application callbacks will be logged. By using setApplicationCallbackLogger(onLevel: Level) a user can set a specific level on which to log application callbacks (debug is used by default). By using setApplicationCallbackLogger(with: [ApplicationCallbackType]?, onLevel: Level) a user can set both, application callbacks and a level at the same time.
MetaInformationLogger
A special type of logger, that enables to log various meta information about the application and the host application. Here is a complete list of supported meta information:
identifierapplication unique identifiercompilerused compiler versionversionCFBundleShortVersionString a.k.a. version of the applicationbuildNumberCFBundleVersion a.k.a. build number of the applicationmodelTypemodel of the application's host devicecurrentOSVersioncurrent OS version of the application's host deviceupTimeboot time of the applicationlanguagelocalization of the application's host device
The logger is accessible outside of the framework using logMetaInformation(_: [MetaInformationType]) method on LogManager. It allows to explicitly list meta information that should be logged. If not specified explicitely, all the meta information will be logged.
Creating custom loggers
There is a possibility of creating custom loggers just by implementing Logging protocol. In the simplest form, the custom logger only needs to implement log(_:onLevel:) and levels() methods. Optionaly it can also implement configure() method in case there is some configuration necessary before starting logging.
Here is an example of a custom logger that enables logging to Crashlytics:
import Fabric
import Crashlytics
class CrashLyticsLogger: QuantiLogger.Logging {
open func configure() {
Fabric.with([Crashlytics.self])
}
open func log(_ message: String, onLevel level: Level) {
CLSLogv("%@", getVaList(["[\(level.rawValue) \(Date().toFullDateTimeString())] \(message)"]))
}
open func levels() -> [Level] {
return [.verbose, .info, .debug, .warn, .error]
}
}
Initialization
Logging initialization is done through LogManager Singleton instance. The LogManager holds an array of all configured loggers and then manages the logging.
Here is an example of how to initialize the logger to use FileLogger, ConsoleLogger and previously created custom CrashLyticsLogger:
let logManager = LogManager.shared
let fileLogger = FileLogger()
fileLogger.levels = [.warn, .error]
logManager.add(fileLogger)
let systemLogger = ConsoleLogger()
systemLogger.levels = [.verbose, .info, .debug, .warn, .error]
logManager.add(systemLogger)
let crashlyticsLogger = CrashLyticsLogger()
logManager.add(crashlyticsLogger)
Logging
Logging is done using a simple QLog(_:onLevel) macro function. Such function can be used anywhere, where QuantiLogger is imported.
Example of how to log:
QLog("This is the message to be logged.", onLevel: .info)
Concurrency modes
QuantiLogger supports 3 different concurrency modes at the moment. The mode is set using loggingConcurrencyMode property of LogManager. Default value is asyncSerial.
syncSerial
Logging task is dispatched synchronously on a custom serial queue, where all loggers perform their tasks serially one by one.
asyncSerial
Logging task is dispatched asynchronously on a custom serial queue, where all loggers perform their tasks serially one by one.
syncConcurrent
Logging task is dispatched synchronously on a custom serial queue, where all loggers perform their tasks concurrently.
Sending file logs via mail
The framework also provides LogFilesViaMailViewController that has a pre-configured controller that, when presented, will offer the option to send all log files via mail. It is constructed using init(withRecipients:) where withRecipients is [String] containing all mail recipients.
Example can be seen in a form of SendLogFilesViaMailViewController within QuantiLoggerExample which is a working example within the framework (clone the project to see).
Displaying file logs in UITableView
The framework also provides FileLoggerTableViewDatasource which is a pre-configured UITableViewDataSource containing all log files merged, each log = a single UITableViewCell.
Example can be seen in a form of LogListTableViewController within QuantiLoggerExample which is a working example within teh framework (clone the project to see).
License
QuantiLogger is released under the MIT License.




