Last active
July 2, 2018 20:29
-
-
Save ferologics/4ee40ee362cfb76a670d1795ca17fea8 to your computer and use it in GitHub Desktop.
Simple logger; to be modularised in to a framework
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
fileprivate let logName = "debug.log" | |
fileprivate var debugLog = "" { | |
didSet { | |
var _debugLog = debugLog | |
guard let rangeOfOldCharacetrs = _debugLog.range(of: oldValue) else { return } | |
_debugLog.removeSubrange(rangeOfOldCharacetrs) | |
let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first | |
guard let url = directory?.appendingPathComponent(logName) else { return } | |
let path = url.path | |
do { | |
try _debugLog.appendToURL(fileURL: url) | |
} catch { | |
do { | |
try debugLog.write(toFile: path, atomically: true, encoding: String.Encoding.utf8) | |
} catch { | |
Logger.log(("Failed to create file with error: \(error)", .fatal)) | |
} | |
} | |
} | |
} | |
class Logger { | |
typealias Log = (message: String, event: LogEvent) | |
static var dateFormat = "yyyy-MM-dd hh:mm:ssSSS" | |
static var dateFormatter: DateFormatter { | |
let formatter = DateFormatter() | |
formatter.dateFormat = dateFormat | |
formatter.locale = Locale.current | |
formatter.timeZone = TimeZone.current | |
return formatter | |
} | |
enum LogEvent: String { | |
case success = "✅" // success | |
case info = "ℹ️" // info | |
case debug = "💬" // debug | |
case verbose = "🔬" // verbose | |
case error = "🚨" // error | |
case warning = "⚠️" // warning | |
case fatal = "🔥" // fatal | |
} | |
enum LogLevel { | |
case hidden | |
case vital | |
case `default` | |
case debug | |
case verbose | |
var allowedLogEvents: Set<LogEvent> { | |
get { | |
let vitalLogEvents: [LogEvent] = [.success, .fatal, .error] | |
switch self { | |
case .hidden: return Set([]) | |
case .vital: return Set(vitalLogEvents) | |
case .default: return Set(vitalLogEvents + [.info, .warning]) | |
case .debug: return Set(vitalLogEvents + [.info, .warning, .debug]) | |
case .verbose: return Set(vitalLogEvents + [.info, .warning, .debug, .verbose]) | |
} | |
} | |
} | |
} | |
static var logLevel: LogLevel = { | |
#if DEBUG | |
return .default | |
#else | |
return .hidden | |
#endif | |
}() | |
class func log | |
( | |
_ log: @autoclosure () -> Log, | |
fileName: String = #file, | |
line: Int = #line, | |
column: Int = #column, | |
funcName: String = #function | |
) | |
{ | |
let (message, event) = log() | |
let logMessage = "\(Date().toString()) \(event.rawValue) \(sourceFileName(filePath: fileName)) \(line):\(column) \(funcName) \(message)" | |
debugLog += logMessage + "\n" | |
// print logs only for the set log level | |
guard logLevel.allowedLogEvents.contains(event) else { return } | |
print(logMessage) | |
} | |
// MARK: - Helper | |
private class func sourceFileName(filePath: String) -> String { | |
let components = filePath.components(separatedBy: "/") | |
return components.isEmpty ? "" : components.last!.without(".swift") | |
} | |
} | |
extension Date { | |
func toString() -> String { | |
return Logger.dateFormatter.string(from: self as Date) | |
} | |
} | |
extension String { | |
func without(_ s: String) -> String { | |
guard let removalRange = self.range(of: s) else { return self } | |
var a = self | |
a.removeSubrange(removalRange) | |
return a | |
} | |
func appendLineToURL(fileURL: URL) throws { | |
try (self + "\n").appendToURL(fileURL: fileURL) | |
} | |
func appendToURL(fileURL: URL) throws { | |
do { | |
let data = try self.data(using: String.Encoding.utf8).unwrapOrThrow(CommonError.unwrapError) | |
try data.append(fileURL: fileURL) | |
} catch { | |
throw error | |
} | |
} | |
} | |
extension Data { | |
func append(fileURL: URL) throws { | |
if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) { | |
defer { | |
fileHandle.closeFile() | |
} | |
fileHandle.seekToEndOfFile() | |
fileHandle.write(self) | |
} | |
else { | |
try write(to: fileURL, options: .atomic) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment