Swifty Logger

Why Logger?

If you’re familiar with print, then you’ll understand the purpose of Logger.

As with print(), Logger messages are directed to the Apple System Log .

However, Logger adds a number of important features not provided by print():

Each log message is associated with a debugLevel value indicating the importance of that message. This enables you to very easily do things like squelch out low-priority messages—such as those logged with. Error and. debugLevel severity values—in production binaries, thereby lessening the amount of work your App Store build does at runtime. To make it more readable it has the glyphs which will help to give the pictorial info of type of message.

Example: ❗= Error, 🚧 =Warning, ⛳=Success and 📣=Information.

Finding where your code is issuing log messages. Logger makes it easy. With print(), it can sometimes be difficult to figure out what code is responsible for those log messages. When a developer logs the message programmatically, it may not be possible to find its source. Logger outputs the file, function and line responsible for each log message, so you can literally go straight to the source.

Configurable Logger. You can define the verbose level .debugLevel to get only that level or below level messages.

//  Logger.swift
//  Created by Santosh Botre on 18/07/17.
//  Copyright © 2017

import Foundation
/**
Available Log level for Logger
- None:    Print no message
- Error:   Error messages
- Warning: Warning messages
- Success: Success messages
- Info:    Info messages
- All:     All messages
*/
enum LoggerLevels: Int {
case None = 0
case Error
case Warning
case Success
case Info
case All
}
class Logger {
//Default debugLevel is All. Logger enabled for all the levels
#if DEBUG
var debugLevel: LoggerLevels = .All
#else
var debugLevel: LoggerLevels = .Warning
#endif
//MARK: - Glyphs
//Icons to easily differentiate log level
let errorGlyph          = "❗"       // Glyph for level .Error
let warningGlyph        = "🚧"       // Glyph for level .Warning
let successGlyph        = "⛳"       // Glyph for level .Success
let informationGlyph    = "📣"       // Glyph for level .Info
//MARK: - Singleton
class var sharedInstance: Logger {
struct Singleton {
static let instance = Logger()
}
return Singleton.instance
}
//MARK: - Public Functions
//Log message on console based on the LoggerLevels
func logMessage(message: String ,
_ logLevel: LoggerLevels = .Info,
_ file: String = #file,
_ functionName: String = #function,
_ line: UInt = #line) {
if self.debugLevel.rawValue > LoggerLevels.None.rawValue
&& logLevel.rawValue <= self.debugLevel.rawValue {
//Trim the file path as #file gives complete file path
let fileName = URL(fileURLWithPath: file).deletingPathExtension().lastPathComponent
print("\(getIconForLogLevel(logLevel: logLevel)) \(fileName) 👉🏽 [ \(functionName):\(line) ] \(message)")
}
}
//MARK: - Private Functions
//Return approripate glyphs
private func getIconForLogLevel(logLevel: LoggerLevels) -> String {
switch logLevel
{
case .Error:
return "\(errorGlyph)"
case .Warning:
return "\(warningGlyph)"
case .Success:
return "\(successGlyph)"
case .Info:
return "\(informationGlyph)"
default:
return " "
}
}
}

To use the #if DEBUG enable it from the project build settings.

First we have an enum with the available log levels:

/**
Available Log level for Logger
- None:    Print no message
- Error:   Error messages
- Warning: Warning messages
- Success: Success messages
- Info:    Info messages
- All:     All messages
*/
enum LoggerLevels: Int {
case None = 0
case Error
case Warning
case Success
case Info
case All
}

With them, we can set up the debugLevel of the Logger to the level we desire each time:

Logger.sharedInstance.debugLevel = .Warning

this way, the Logger will only print the messages with a level equal to Warning or inferior (being in this case only Warning and Error). We can have a clearer console output when we want to trace a problem or a verbose one when not.

For even clearer messages, the Logger, by default (you can change them easily) prefixes the output with unicode glyphs for each log level:

let errorGlyph          = "❗"       // Glyph for level .Error
let warningGlyph        = "🚧"       // Glyph for level .Warning
let successGlyph        = "⛳"       // Glyph for level .Success
let informationGlyph    = "📣"       // Glyph for level .Info

It will print the filename which logged the message and the line number inside the file. To accomplish this easily we implicity pass this data using Swift’s built-in identifiers as the method signature shows:

func logMessage(message: String ,
_ logLevel: LoggerLevels = .Info,
_ file: String = #file,
_ functionName: String = #function,
_ line: UInt = #line)
  • The method logMessage will print the message into the console, similar to a print command but with the enhanced features.

Examples:

Logger.sharedInstance.debugLevel = .Warning
Logger.sharedInstance.logMessage(message: "Error Message", .Error)
Logger.sharedInstance.logMessage(message: "Warning Message", .Warning)
Logger.sharedInstance.logMessage(message: "Info Message", .Info)
Logger.sharedInstance.logMessage(message: "Success Message", .Success)
❗ ViewController 👉🏽 [ viewDidLoad():18 ] Error Message
🚧 ViewController 👉🏽 [ viewDidLoad():20 ] Warning Message

Hope this will be helpful for those who don’t want to integrate any other heavy third party Loggers.

Soon, I will write the blog for the file level logger.

Show your support

Do clap as much as you want. Clapping shows how much you appreciated Santosh Botre’s story.

SHOW YOUR SUPPORT