The SRG Logger library provides a simple way to unify logging between SRG SSR libraries and applications, but can be used by any other application or library as well.
Five logging levels are available, which should match most needs:
Verbose
for detailed technical information.Debug
for debugging information.Info
for information that may be helpful for troubleshooting errors.Warning
for information about conditions which might lead to a failure.Error
for information about failures.
The library automatically bridges with standard logging frameworks, in the following order:
- If your project uses CocoaLumberjack, messages will be forwarded to it.
- If your project can use Apple unified logging, available starting from iOS 10, tvOS 10 and watchOS 3, messages will be forwarded to the system console.
If neither is available, no logging will take place. You can install a verbose NSLog
based logger, provided as well, if you need a quick way to setup logging (this logger logs all messages and can slow down your application).
The library does not provide any logging to NSLogger. You can namely automatically bridge CocoaLumberjack into NSLogger using Cédric Luthi's interface between them.
The library is suitable for applications running on iOS 12, tvOS 12, watchOS 5 and above. The project is meant to be compiled with the latest Xcode version.
If you want to contribute to the project, have a look at our contributing guide.
The library must be integrated using Swift Package Manager directly within Xcode. You can also declare the library as a dependency of another one directly in the associated Package.swift
manifest.
When you want to use classes or functions provided by the library in your code, you must import it from your source files first. In Objective-C:
@import SRGLogger;
or in Swift:
import SRGLoggerSwift
This requires your target to link against the corresponding Swift package product.
To log a message, simply call the macro corresponding to the desired level. In Objective-C:
SRGLogInfo(@"com.myapp", @"Weather", @"The temperature is %@", @(temperature));
or in Swift:
SRGLogInfo(subsystem: "com.myapp", category: "Weather", message: "The temperature is \(temperature)")
You can provide two optional arguments when logging a message:
- A subsystem, here
com.myapp
, which identifies the library or application you log from. - A category, here
Weather
, which identifies which part of the code the log is related to.
To avoid specifiying the subsystem in your application or library each time you call the macro, you can define your own set of helpers which always set this value consistently, for example in Objective-C:
#define MyAppLogVerbose(category, format, ...) SRGLogVerbose(@"com.myapp", category, format, ##__VA_ARGS__)
#define MyAppLogDebug(category, format, ...) SRGLogDebug(@"com.myapp", category, format, ##__VA_ARGS__)
#define MyAppLogInfo(category, format, ...) SRGLogInfo(@"com.myapp", category, format, ##__VA_ARGS__)
#define MyAppLogWarning(category, format, ...) SRGLogWarning(@"com.myapp", category, format, ##__VA_ARGS__)
#define MyAppLogError(category, format, ...) SRGLogError(@"com.myapp", category, format, ##__VA_ARGS__)
or in Swift:
func MyAppLogVerbose(category: String?, message: String, file: String = #file, function: String = #function, line: UInt = #line) {
SRGLogVerbose(subsystem: "com.myapp", category: category, message: message, file: file, function: function, line: line)
}
func MyAppLogDebug(category: String?, message: String, file: String = #file, function: String = #function, line: UInt = #line) {
SRGLogDebug(subsystem: "com.myapp", category: category, message: message, file: file, function: function, line: line)
}
func MyAppLogInfo(category: String?, message: String, file: String = #file, function: String = #function, line: UInt = #line) {
SRGLogInfo(subsystem: "com.myapp", category: category, message: message, file: file, function: function, line: line)
}
func MyAppLogWarning(category: String?, message: String, file: String = #file, function: String = #function, line: UInt = #line) {
SRGLogWarning(subsystem: "com.myapp", category: category, message: message, file: file, function: function, line: line)
}
func MyAppLogError(category: String?, message: String, file: String = #file, function: String = #function, line: UInt = #line) {
SRGLogError(subsystem: "com.myapp", category: category, message: message, file: file, function: function, line: line)
}
If the default log handler does not suit your needs (or if you simply want to inhibit logging), set a new handler to forward the messages and contextual information to your other logger. In Objective-C:
[SRGLogger setLogHandler:^(NSString * _Nonnull (^ _Nonnull message)(void), SRGLogLevel level, NSString *const _Nullable subsystem, NSString *const _Nullable category, const char * _Nonnull file, const char * _Nonnull function, NSUInteger line) {
// Foward information to another logger
}];
or in Swift:
SRGLogger.setLogHandler { (message, level, subsystem, category, file, function, line) in
// Foward information to another logger
}
Logging can be performed from any thread.
If you are using Apple unified logging and do not see the logs:
-
Check that the scheme you use does not have the
OS_ACTIVITY_MODE
environment variable set todisable
, orOS_ACTIVITY_DT_MODE
set toNO
. -
If you do not see lower level logs in the
Console.app
, ensure that the items Include Info Messages and Include Debug Messages are checked in the consoleAction
menu. If these options are grayed out, try updating the logging configuration for your subsystem first by running the following command from a terminal:$ sudo log config --mode "level:debug" --subsystem <subsystem>
-
Use the search to locate entries for your application name, and right-click on an entry to filter by application, subsystem or category
-
Read the official documentation if you still have issues
This logger implementation is heavily based on a Cédric Luthi's Stack Overflow post.
See the LICENSE file for more information.