Skip to content

Instantly share code, notes, and snippets.

@irace
Last active September 20, 2023 08:04

Revisions

  1. irace revised this gist Sep 6, 2018. 1 changed file with 15 additions and 0 deletions.
    15 changes: 15 additions & 0 deletions ConsoleLogDestination.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    import Foundation

    final class ConsoleLogDestination: LogDestination {
    func log(statement: String) {
    #if DEBUG
    print(statement)
    #endif
    }

    func error(error: Error) {
    #if DEBUG
    print(error)
    #endif
    }
    }
  2. irace revised this gist Sep 6, 2018. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions Logger.swift
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,7 @@ protocol LogDestination {

    func error(error: Error)
    }

    /**
    An abstraction on top of all different types of logging!

  3. irace revised this gist Sep 6, 2018. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions Logger.swift
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    import Foundation

    protocol LogDestination {
    func log(statement: String)

  4. irace created this gist Sep 6, 2018.
    116 changes: 116 additions & 0 deletions Logger.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,116 @@
    import Foundation
    protocol LogDestination {
    func log(statement: String)

    func error(error: Error)
    }
    /**
    An abstraction on top of all different types of logging!

    For now, this allows you to log a string, along with an optional `Error` instance (for `error` and `severe` levels
    only).

    In the future, we may want to add support for event and impression tracking, or we may prefer to keep those
    separate. Not sure yet!

    Some inspiration taken from [SwiftyBeaver](https://swiftybeaver.com), as well as
    [this blog post](https://medium.com/@sauvik_dolui/developing-a-tiny-logger-in-swift-7221751628e6).
    */
    final class Logger {
    private enum Level: CustomStringConvertible {
    case debug
    case info
    case verbose
    case warn
    case error
    case severe

    var description: String {
    switch self {
    case .debug: return "💬 DEBUG"
    case .info: return "ℹ️ INFO"
    case .verbose: return "🔬 VERBOSE"
    case .warn: return "⚠️ WARN"
    case .error: return "‼️ ERROR"
    case .severe: return "🔥 SEVERE"
    }
    }
    }

    // MARK: - State

    private static var dateFormatter = DateFormatter().then {
    $0.dateFormat = "hh:mm:ss"
    $0.locale = Locale.current
    $0.timeZone = TimeZone.current
    }
    // MARK: - Inputs

    private let destinations: [LogDestination]

    // MARK: - Initialization

    init(destinations: [LogDestination]) {
    self.destinations = destinations
    }

    // MARK: - Public
    func debug(_ message: String, filePath: String = #file, line: Int = #line, functionName: String = #function) {
    log(event: .debug, message: message, filePath: filePath, line: line, functionName: functionName)
    }

    func info(_ message: String, filePath: String = #file, line: Int = #line, functionName: String = #function) {
    log(event: .info, message: message, filePath: filePath, line: line, functionName: functionName)
    }

    func verbose(_ message: String, filePath: String = #file, line: Int = #line, functionName: String = #function) {
    log(event: .verbose, message: message, filePath: filePath, line: line, functionName: functionName)
    }

    func warn(_ message: String, filePath: String = #file, line: Int = #line, functionName: String = #function) {
    log(event: .warn, message: message, filePath: filePath, line: line, functionName: functionName)
    }
    func error(_ message: String, error: Error? = nil, filePath: String = #file, line: Int = #line, functionName: String = #function) {
    log(event: .error, message: message, error: error, filePath: filePath, line: line, functionName: functionName)
    }

    func severe(_ message: String, error: Error? = nil, filePath: String = #file, line: Int = #line, functionName: String = #function) {
    log(event: .severe, message: message, error: error, filePath: filePath, line: line, functionName: functionName)
    }

    // MARK: - Private

    private func log(event: Level, message: String, error: Error? = nil, filePath: String, line: Int, functionName: String) {
    let statement = Logger.statement(event: event, message: message, filePath: filePath, line: line, functionName: functionName)

    for destination in destinations {
    destination.log(statement: statement)

    if let error = error {
    destination.error(error: error)
    }
    }
    }

    private static func statement(event: Level, message: String, filePath: String, line: Int, functionName: String) -> String {
    return [
    Logger.dateFormatter.string(from: Date()),
    event.description,
    Logger.functionCall(filePath: filePath, functionName: functionName, line: line),
    "-",
    message
    ].joined(separator: " ")
    }

    private static func functionCall(filePath: String, functionName: String, line: Int) -> String {
    return "\(fileName(path: filePath)).\(functionName):\(line)"
    }

    private static func fileName(path: String) -> String {
    return path
    .components(separatedBy: "/")
    .last?
    .components(separatedBy: ".")
    .first ?? ""
    }
    }